\begindata{text,539940888} \textdsversion{12} \template{default} \define{global

\begindata{text,539940888}
\textdsversion{12}
\template{default}
\define{global
}
\define{footnote
attr:[Flags OverBar Int Set]
attr:[FontSize PreviousFontSize Point -2]}
\define{concat
attr:[Script PreviousScriptMovement Point 6]
attr:[FontSize PreviousFontSize Point 2]}
\flushright{16 July 1993 - Ness 2.0}
\
\majorheading{Ness Author's Reference Manual}
\center{by Wilfred J. Hansen}
\indent{\flushright{\smaller{_________________________________
Andrew Consortium
Carnegie Mellon University
__________________________________
}}
Ness is a programming language for the Andrew ToolKit. With it,
documents
may contain active elements controlled by Ness scripts. The language
features an innovative substring algebra for string processing. \
This manual is intended for authors who want to write Ness programs or
incorporate Ness scripts in documents or applications. For a description
of all documents describing Ness, see the \bold{Ness User's Manual}.
Contents
1.
Writing Ness
2.
Writing stand-alone programs
3.
Extending objects in embedded scripts
}\
\begindata{bp,539975080}
Version 2
n 0
\enddata{bp,539975080}
\view{bpv,539975080,62,0,0}
Copyright IBM Corporation 1988, 1989 - All Rights Reserved
Copyright Carnegie Mellon University 1993 - All Rights Reserved
\smaller{
$Disclaimer:
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided
that the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of IBM not be used in advertising or
publicity pertaining to distribution of the software without specific,
written prior permission.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD
TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ANY COPYRIGHT
HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
$
}\
\begindata{bp,539975512}
Version 2
n 0
\enddata{bp,539975512}
\view{bpv,539975512,63,0,0}
Ness \italic{programs} reside in their own files and process other files.
Ness \italic{scripts} reside as insets within a document or application
and extend and control the behavior of other insets. This manual
describes
how to write Ness programs or incorporate Ness scripts in documents or
applications. For details of writing the language itself, see Ness
Language Reference Manual. For a full list of the Ness documentation,
see
the \bold{Ness User's Manual}.
Some of the early parts below describe Ness cultural conventions which
are
unenforcable. Warning, things you will need to know are embedded in the
cultural stuff to give you incentive to wade through the culture.
\section{1. Writing Ness}
Several topics are of interest in writing Ness code, whether in
standalone
programs or scripts embedded in documents or applications.
\subsection{1.1 What a Ness script looks like}
Although the Ness compiler pays very little attention to program
formatting
and typography, you should keep in mind that the purpose of writing a
program is to explain it to another human because humans have much lower
tolerance for confusing programs than computers. In the Ness security
scheme, users are encouraged to read Ness programs and to ignore any they
do not understand. Not all users will avail themselves of this
opportunity, but enough will that it well behooves you as author to take
some care to produce a readable document.
Ness programs may contain typography, all of which is ignored except that
within string constants.
Typical uses of typography:
highlight function names and the names of global variables
use indentation styles instead of tabs
use headings and titles in comments
put reserved words in italics
(\italic{function, if, return,} ...)
A comment can be one long line with the comment mark (--) only at its
beginning. \
Where useful, include diagrams, rasters, and tables in comments to
explain
the program.
Comments are important for every global entity, both variable and
function.
The comments should indicate the purpose of the entity sufficiently well
that a reader of can understand any given function having read only the
comments describing the functions and global variables it uses. That is,
without reading the contents of any other function. For a function the
initial comment should describe the arguments, the return value, and any
exceptional circumstances that affect the behavior. For instance if it
is
a string processing function what does it do differently at the ends of
the
string or in case it doesn't find what it is looking for.
Indentation should follow the examples or the indentation shown in the
grammar in the \bold{Ness Language Reference Manual}. In particular, if
a
form beginning with a reserved word "\bold{xyz}" has an "\bold{end xyz}",
the first line of the form should begin with the reserved word, the last
line should begin with the matching "\bold{end xyz}" indented the same
amount, and all lines between should be indented further by at least one
tab stop. The reserved words \bold{else} and \bold{elif} are indented
the
same distance as their \bold{if}. (If indentation gets too deep, either
restructure the algorithm or put the inner portion in a function.)
In general global variables should be longer words and capitalized.
\
Put a space after a comma and around the assignment and append operators
(:= and \concat{~}\bold{:=} ). Very often there should be a space
around
plus (+) and minus(-). After a function name, the left parenthesis
should
follow without an intervening space.
In writing functions that process strings, it is best to write them so
they
process their argument, rather than assuming they will process an entire
base string. In other words, searches should be limited by the end of
the
argument rather than by the end of the base.
\subsection{1.2 Ness version number}
The Ness system may evolve from time to time. This raises the
possibility
that a program may expect one language and the system may implement some
other. As far as possible changes will be made in an upward compatible
manner so old programs will continue to run with newer compilers. To
prevent trying to run newer programs with older compilers, each program
has
associated with it a \italic{Ness version number}.
In a Ness object, the Ness version number is automatically recorded when
the object is saved. In a Ness program created with an editor the
version
number is recorded with a line of the form
--$ness 2
(or what ever version number is appropriate). If the compiler is at a
lower version number than the program it will refuse to compile it.
\subsection{1.2 Errors}
The Ness processor indicates errors as precisely as possible: the exact
piece of the program with the error is indicated. For standalone
programs
errors are printed by line. For instance, the program:
\leftindent{\italic{function} \bold{f_one}()
subseq foo := another()
\italic{else}
\italic{end fiction}
\italic{function}
\bold{another}()
\italic{return} "a"
\italic{end function}}
will give these errors:
\example{\smaller{Compile error(s) in /tmp/foo
line 3 - syntax error
source text is:
line 6 -
>>> else <<< \
. . . restart with token
source text is:
>>> function <<<
another ()}}
In each entry the first line gives the line number and error message,
while
the second line is the erroneous source text with the error indicated
within >> and <<. For syntax errors, the error will sometimes precede
the
marked text. Note that syntax errors cause the processor to skip ahead
to
the next function declaration; intervening errors are not reported.
For embedded Ness programs executing interactively, the error position is
shown by moving the selection to the erroneous token or tokens and
displaying the error in the message line. To get to the next error,
choose
the NextError option from the Ness menu card or type the sequence
control-X-control-N.
Occasionally the item highlighted will be next to the error, rather than
the error itself. For a syntax error, the highlight often indicates the
token after the erroneous one because the error token would have been
legal
in some other program. A missing \bold{end} token will usually not be
detected until the next \bold{end}; this is best detected by proper
indentation. \
Errors during execution may sometimes fail to find the location of the
error. In this case the error indication may be the empty string at the
beginning of a function or the beginning of the entire script.
If an error occurs in a function compiled from the ness library (see
section 6 of the \bold{Ness Function Reference Manual}), Ness does its
best
to show that error as well. For standalone execution, the error is
indicated in the error list. For embedded execution another window,
named
NessLibrary, is brought up and the error is highlighted there. The
NessLibrary window behaves a lot like most ez windows, but does have some
differences; it is best when through with it to use ESC-D to discard it.
If the erroneous library function was not your own, you should contact
its
author and mention that the problem occurred.
The most imposing Ness error message is
\leftindent{! ! !
!!!!!!!!!!}
Disasterous Ness error in this function.
Quit soon.
This is displayed whenever the interpreter detects a bus error or
segmentation fault during execution. In general it is okay to continue
with the same editor because, after all, the offending memory acces could
not have done anything because there was no such address. Consider,
however, that the offending address is pseudo-randow so on other
executions
of the same statement it might refer to and damage some part of the
memory
that was crucial. It is for this reason that the message is so strongly
stated.
\subsection{1.3 Functions available}
These are sources for functions to call from Ness programs.
\leftindent{1) Functions defined elsewhere in the same script
2) Ness builtin functions
3) Ness library functions
4) Proctable functions
}
The first of these is described in the \bold{Ness Language Reference
Manual}, the last in the \bold{Ness Hacker's Manual}, and the rest in the
\bold{Ness Function Reference Manual}. \
There are \italic{three} different places a Ness script may appear in the
editor:
\leftindent{as an embedded script in a document or application
as a Ness program in a file of its own
in the NessLibrary window}
It is unlikely that one script would appear in all three places, but
quite
conceivable that it could be edited as a file and in a NessLibrary winodw
simultaneously. Beware: these are two separate copies of the text;
changes
to one will not affect the other. \
\section{2.
Writing stand-alone programs}
To write a program in Ness, create a file with the extension ".n" and
write
the script in it. Execute the script with nessrun, as shown in the
\bold{Ness User's Manual}.
Nessrun presents to the program the remainder of the command line after
the
program name, so the program can have any set of switches and arguments
it
wants. This text is passed to the program as the single argument to the
function 'main', which is where execution begins. \
When executed with nessrun, a program may be non-interactive, or it can
open a window and interact with the user.
\subsection{2.1 Example non-interactive program}
The next two pages give a sample program which reads a file, "processes"
it
line-by-line, and writes the revised file. In this case the processing
is
simply to make a copy of the contents of the line and create an identical
line in the output file. As the program notes, the entire processing
step
could be written as \
return copy(text)
but then it would not illustrate how to find the lines of the file.
Discussion continues after the program text.
\begindata{bp,539981896}
Version 2
n 0
\enddata{bp,539981896}
\view{bpv,539981896,64,0,0}
\example{\smaller{-- process.n
\
-Read a file, process each line, and write the result to
filename.doc
---
Usage:
nessrun
process.n
filename
$ness 1
\italic{marker} destext := "doc"
-- extension for destination file
\italic{marker} letters := "qwertyuiopasdfghjklzxcvbnm"
\leftindent{~ "QWERTYUIOPASDFGHJKLZXCVBNM"
~ "_"}
-- Process(text)
--
process the text and \
--
return the revised version
--
The text may be read-only, so we use ~:= to build new text.
--
In this example, the new text is just \
--
a concatenation of the lines of the old
-\italic{function} \bold{Process}(text)\leftindent{
\italic{marker} new := newbase()
-- the output text
\italic{marker} nl
-- a newline in the original text
\italic{marker} line
-- one line of the original text \
--
(without a newline at either end)
nl := search(text, "\\n")
-- find first newline
line := extent(text, start(nl))
-- find first line
\italic{while} nl /= "" \italic{do}
-- "process" a line:
new ~:= line ~ "\\n"
line := finish(nl)
\
-- start of next line
nl := search(extent(line, text), "\\n")
line := extent(line, start(nl))
-- next newline
-- the entire next line
\italic{end} \italic{while}
-- At this point, 'line' refers to everything \
--
from the finish of the last newline to the finish of 'text'
\italic{if} line /= "" \italic{then}
-- there is more in 'text' after its last newline
new ~:= line
-- "process" the tail \
new ~:= "\\n"
-- gratuitously add a final newline
\italic{end} \italic{if}
\italic{return} new}
\italic{end} \italic{function}
\begindata{bp,539985208}
Version 2
n 0
\enddata{bp,539985208}
\view{bpv,539985208,65,0,0}
\italic{function} \bold{main}(args)
\leftindent{\italic{marker} filename, outname, t
filename := token(args, letters ~ "./0123456789")
outname := search(filename, ".")
t := search(finish(outname), ".")
\italic{while} t /= "" \italic{do} -- find the last "."
\leftindent{outname := t
t := search(finish(outname), ".")}
\italic{end} \italic{while}
--
append "." ~ destext if there is no "." in the filename,
--
or there is a slash after the last ".",
--
or filename already ends in "."~destext
\italic{if}
outname = "" \
\italic{or} search(finish(outname), "/") /= ""
\italic{or} extent(next(outname), filename) = destext
\italic{then}
\leftindent{outname := filename ~ "." ~ destext}
\italic{else} \
\leftindent{outname := extent(filename, outname) ~ destext}
\italic{end} \italic{if}
printline("Process: " ~ filename ~ " -> " ~ outname)
t := readfile(filename)
-- t is read-only if the file is
t := Process(t)
-- save: the old ouput: \
system("mv " ~ outname ~ " " \
~ outname ~ ".BAK 2> /dev/null")
writefile(outname, t)}
\italic{end} \italic{function}}}
The main function first extracts the input filename from the arguments.
Note that as written it only recognizes names consisting of letters,
digits, underline, dot, and slash.
Next it uses a \bold{while} loop to
find the last dot, checks the extension, and generates the name for the
output file. After then printing a message it reads the old file,
processes it, moves the old output file, and writes the new output file.
The function \bold{Process} advances through the text one line at a time,
setting the variable 'line' to have the contents of each successive line,
without a newline at either end. The "processed" text is accumulated in
'new' by appending to its end. The loop is carefully written to process
only the 'text' value passed in, even if it is a substring of some longer
string.
It is instructive to see why the loop leaves 'line' referring to
everything
after the last newline. The essential cause is that when search() fails
to
find what it is looking for it returns finish() of its first argument.
In
this case because the first argument ends at the end of the text, that
location is returned for failure. And then 'line' is set to everything
from finish() of the last newline to finish() of 'text'.
\subsection{2.2 Nessrun amenities}
Nessrun implements two switches which, if used, are inserted in the
command
line just after 'nessrun' and before the filename. \
\description{-x forces a dump of the code generated for the program.
(In
most circumstances this is of little value to you as a Ness programmer.)
The code generated is that of a stack machine: operands are fetched to
the
stack with Load instructions, operators apply to the top elements of the
stack, and results are put back in variables with store instructions.
For
more information about the exact contents of the dump, you can try
reading
the source code of module atk/ness/objects/dump.c in the Ness source
code.
-f causes the nessrun program to fork, thus freeing the command window
for
further command initiation. This switch is particularly of use when the
application opens an interactive window.}
When writing a standalone program, you may wish to utilize the textview_
proctable functions. To allow this, nessrun provides a value for
'defaulttext'; the value is an empty text, so to use it you first copy
the
text with replace(base(currentselection(defaulttext)),
the-text-to-be-processed).
The nessview inset provides some tools of use when editing Ness code.
Primarily this means you can compile the program without leaving the
editor. To utilize the nessview inset to edit Ness programs, you can add
the following to your ~/.atkinit file:
\leftindent{addfiletype .n ness "template=default"}
If you edit a new file with the extension .n, it will be editted with the
nessview inset and saved with "\\begindata\{ness" so next time it will be
read as Ness. Previously existing xyz.n files that have styles have
already been written with "\\begindata\{text", so editing them will not
use
the nessview inset. Note also that the second time you edit a .n file
with
the ness inset, you will find the warning message wrapped around it. You
can click on the Author Mode button near the end of the file. \
You can remove the warning from all your Nesses by adding to your
preferences the line
*.NessUseDialogBoxInsteadOfWarning: on
Thereafter a dialog box will appear whenever you see a Ness script.
The \bold{Ness User's Manual} explains that a Ness script may begin with
\
#!$ANDREWDIR/bin/nessrun
If the file it is in is made executable with something like
chmod +x filename.n
then a user can execute the Ness program just by typing its name to the
shell. What the User's Manual does not mention, however, is that the #!
line must be the absolutely first thing in the file. If the file is
originally created with styles or embedded objects, ez will expect the
file
to begin with "\\begindata" and will otherwise show it as plain ASCII.
It
is easiest to simply create such programs without styles or embedded
objects. However, if you are editing the Ness code with the ness inset,
it
will get read properly.
\subsection{2.3
Interactive Nessrun applications}
Although ATK applications can be written as documents with embedded Ness
scripts, this has two disadvantages: the embedded Ness occupies screen
space and the user must empower the embedded Ness each time the
application
is started. These problems can be avoided by writing the application as
a
standalone Ness program which opens a window and interacts with the user.
See the function launchApplication in nessfunc.d; note that this
function
does not return until the user exits from the application. In order to
intercept events to an object named in the marker, the program may
"extend"
those objects.
When an application
is started from nessrun, it is appropriate that it
should fork in order to release the command window.
with the -f switch to nessrun.
This is accomplished
A program design may require action when an object first beomes visible
on
the screen. To do so, the extend block for any named object can contain
on
event specification for event "BecameVisible"; the code within will be
called whenever the object first is displayed on the screen.
\section{3. Extending objects in embedded scripts}
Ness scripts embedded as insets in documents can extend the behavior of
insets appearing elsewhere in the document. You can insert a Ness inset
just as any other inset: type ESC-TAB and respond to the prompt with
"ness". An embedded text will appear which differs in appearance from an
ordinary text inset in that there is an additional "Ness" menu card.
The most direct way to take advantage of a Ness inset in a document is to
insert within the inset a script which processes the document's text.
After Empowering the Ness, each time you select "Do main()" from the
Ness
menu card, the function main() in the script will be called (with no
arguments). For example, suppose you insert the following script in a
Ness
inset within this document and then choose Do main() from the menu. The
function counts the number of instances of "Ness" and shows the number in
the message line. (As of 10:04:12 EDT 10 Oct 1989, the value displayed
is
104.)
\smaller{\example{\italic{
function} \bold{main}()
-- count the occurrences of the string "Ness"
\italic{integer} count
\italic{marker} word
count := 0
word := start(base(currentselection(defaulttext)))
\italic{while} \italic{True} \italic{do}
word := search(finish(word), "Ness")
\italic{if} word = "" \italic{then}
TellUser(textimage(count))
\italic{exit} \italic{function}
\italic{end} \italic{if}
count := count + 1
\italic{end} \italic{while}
\italic{end} \italic{function}}
}
The function currentselection() returns a marker for the text currently
selected in the default text. Base() then computes a marker for the
entire
text containing that selection. Finally, start() computes an empty
marker
at the beginning of its argument. In this way, the search for "Ness"
begins at the front of the document, no matter what portion of the
document
is currently selected. Each execution of search() within the loop finds
a
subsequent instance of "Ness" because it begins the search with the
next()
character after the current instance.
Warning: When I first wrote the above routine I omited the call to
finish(). As a result the function went into a loop because it
continuously found the same instance of "Ness". As explained in the
NessUser's Manual, you can use control-G to exit an embedded Ness script
that is caught in a loop .
When a run-time error occurs or even when control-G is pressed, the Ness
script is disabled until recompiled. And the script will only recompile
after you have changed its text. You may have to go into Author mode,
add
and remove a single character, and then request the recompilation.
\subsection{3.1 Embedding and naming}
When designing a document or application the first step is to design the
appearance and behavior. Decide what buttons, fields, and other insets
you
desire and what will happen for user actions to each. For instance, you
may want a click on a picture of a flower to scroll the document to a
section on horticulture. The next two steps are to layout the images and
build the Ness script.
By convention, when you enhance a document with a Ness script you should
include in the design of the document a section which describes to the
reader the ways in which the document is enhanced. That way the reader
can
decide whether or not to empower the script. \
There are some constraints on the placement of the description of the
Ness
enhancements and the Ness script itself. The description should appear
close to the Ness so the reader can find it easily while deciding whether
to Empower the script.
The script itself should appear close to the
beginning of the document or close to the first inset controlled by the
Ness. Otherwise the user may not see the script and may thus not have a
chance to empower it and enjoy its benefits.
When placing insets in the document or application they need to be given
names so the Ness script can refer to them. The full description of
creating and naming insets is covered by the documents in
$ANDREWDIR/doc/adew/; what follows is just one possible approach.
A name may be given to an inset by embedding it in a \italic{cel} inset,
which is in turn embedded in the parent. The cel inset remembers a name
given to it and registers that name with its parent. The name is passed
up
the parentage until it reaches an arbiter, which then remembers the name
in
conjunction with its cel. Ness asks the arbiter surrounding it for cels
by
names.
The user interface to all this is covered in the documents in
/usr/andre/doc/adew/. Here's one approach: use the \italic{arbcon} to
create insets, paste them in your work, and finally use the arbcon again
to
give names to the insets.
If you have in your .atkinit the line "addkey ness-dostmt \\e\\e view"
you
can bring up an arbcon window by typing ESC-ESC and respond to the
"Ness:"
prompt with "arbcon_create()". Create an inset with the arbcon by
clicking
one of the names in the list at the top middle. The act of clicking puts
a
new instance of that sort of object into the cut buffer; from thence you
can paste it into your document or application. Whenever you click on an
inset its name and attributes will be displayed in the lower portion of
the
arbcon window. Initially the name will be some non-descript
identification
like "value", "value-1", "value-2", ... .
Ness scripts refer to inset names in two ways. The inset() function
takes
as its argument a marker value and tries to find an inset with that name,
returning an object value for the inset. The extend construct names an
inset which will be the target for all the event specifiers within the
extend. If we give the flower the name "rosebud", the script might say
\example{\smaller{\italic{extend} "\bold{rosebud}"
\leftindent{\italic{on} \italic{mouse} "any"
\leftindent{\italic{if} mouseaction = mouseleftup \italic{then}
\leftindent{\italic{marker} b := base(currentselection(defaulttext))
b := search(b, "\\n3.1 Horticulture")
\italic{if} b /= "" \italic{then}\leftindent{
setcurrentselection(defaulttext, b)
textview_line_to_top(defaulttext)}
\italic{end} \italic{if}}
\italic{end} \italic{if}}
\italic{end} \italic{mouse}}
\italic{end} \italic{extend}}}
In this case when the mouse goes up in the flower the text will be
searched
for the header of the Horticulture section and that line will be moved
tothe top of the window.
Within ATK, the names of various insets are managed by an arbiter object.
When a Ness is Empowered, it tells the arbiter it wants to know about
named insets. As insets become visible the Ness is informed of them and
extends them as described in its script.
An arbiter is an inset that can contain any other sort of inset. Thus
you
can insert an arbiter containin, say, a table. Thereafter named insets
within the table only send their names to the locally enclosing arbiter
and
not to the outermost one. To extend these inner insets, a Ness must be
inserted as one of the insets within the table. In this way, there may
be
multiple copies of the table in a document each with its own script and
each with subordinate insets having thee same names.xxx Discuss
hierarchical name spaces by embedding arbiters.
\bold{3.2 User Interface to Ness}
The menu options for Ness are documented in the \bold{Ness User's
Manual}.
It is useful to point out that if you as author want to see what a
script
will look like to a user you can select the "Add Warning" option. To
resume editting you will then have to scroll to the end of the script and
click on the box labelled "Author mode - Let me edit the script".
The following keystrokes are also defined by a Ness inset:
\description{\bold{ctl-X ctl-N}
- Display the next error or the next
warning message. After the last the message line shows "No more errors".
Typing the keys again will restart with the first error.
\bold{ctl-U ctl-X ctl-N}
message.
-
\bold{ESC ctl-N shift-C } -
Display the previous error or warning
Compile the script.
\bold{ctl-X ctl-E} - Compile the script and execute beginning with
function main() or the currently selected startup function (see the next
entry).
\bold{ctl-U ctl-X ctl-E} - Prompts for a function name and sets that
name
to be the currently selected startup function. Then goes ahead and does
everything like ctl-X ctl-E (just above).
\bold{ESC ctl-D shift-D}
-
Turn on Ness debugging.
This is useful only
for debugging the Ness processor and inset.
debugging
programs written in Ness.
\bold{Esc ~}
right now\}}
-
It is of no aid for
Switch between author and user modes.
\{This is broken
\section{Appendix. Known bugs}
If the keys in the argument to a dokeys call a keysequence which is
intercepted by \bold{on keys}, Ness crashes.
parseint(), parsereal(), and firstobject() do not obey the search
conventions for limiting the search.
Ness scripts modified in the NessLibrary window do not affect copies of
the
script in other windows.
\enddata{text,539940888}