                               Ivy (version 2)
                             Preliminary Manual


INTRODUCTION

        Ivy is an embeddable byte-code compiled/interpreted language which
is useful as both an extension and a command language.  Its syntax is
designed to be easy to learn and to be fairly good looking.  Ivy currently
supports four data types: integers, strings, functions and objects.  Objects
are late-binding storage devices which take the role of arrays, structures
and simple look-up tables.  Floating point or arbitrary length floating
point numbers will be available in a future implementation. Ivy comes
packaged as an interactive language like BASIC and LISP.  You can either
execute language statements immediately from the keyboard or run a program
stored in a file.  Ivy is also easy to embed into another program.  Calls
are provided to execute Ivy code and to add C function extensions to Ivy's
interpreter.


COMMAND FORMAT

        ivy [-u] [-t] [-s] [-c] [filenames...]

                If no filenames are given, ivy takes input from the keyboard

                -t  is a debugging aid which displays the parse tree as
                    commands are entered

                -u  is a debugging aid which unassembles the byte-code as
                    it's made

                -s  is a debugging aid which inhibits executing generated
                    code

                -c  instructs printing stack top after each executed command


PROGRAM STRUCTURE

        Whenever a command or expression is encounted outside of a block, it
is executed immediately.  A command is a function or statement name followed
by expressions.

                command-name expr expr expr ...

                print "Hello world"

        The expressions get evaluated and their results are passed to the
command as arguments.  Multiple expressions or multiple expressions followed
by a command may be placed on a line:

                expr expr expr ...
                expr expr expr ... command-name expr expr expr ...

                a="Hello" b="World" print a b

        Multiple commands may also be placed on a line, but they must be
separated by semicolons (the ';' can be dropped if the command happens to
begin with a keyword):

                command ; command ; ...

                print "Hello" ; print "World"

        A command is really a function call and may be placed in an
expression as one:

                command-name[expr expr expr ...]

                print["Hello" "World"]

        Some statements also require a block of commands to follow them
('if' for example).  Such statements can still be formulated as function
calls, but they may not be used inside of an expression unless they are
enclosed within parenthesis.

        print (if[1==1] "One equals one" else "One equals two")

        Commas may be used to separate the expressions, but they are not
needed.  Ambiguities between operators which take multiple roles are
resolved by measuring how close the operators are to their operands.  For
example:

                a + b   - c             # Two expressions, a+b and -c
                a + b - c               # One expression, a+b-c

        In other words, the code is parsed how it looks (TABs are treated as
if there were tab stops every eight columns.  A parser directive will be
added later to allow this to be changed).

        Expressions may also cross lines if it is necessary to do so for
them to complete:

                a + b                   # Two expressions, a+b and -c
                - c

                a + b -                 # One expression, a+b-c
                c

        When a statement requires a block of commands to follow it, two
options are available.  The block may be composed of a single command on the
same line as the statement:

                if 1==1 print "One equals one"

        Or the block may be composed of multiple commands beginning on the
line following the statement:

                if 1==1
                  print "One equals one"
                  print "It certainly doesn't equal 2"

         Blocks end when there is no more input (in interactive mode, hit ^D
to end the current block) or, in keeping with the philosophy of having the
code parsed the way it looks, when the "indentation level" (the number of
columns at the beginning of the line) returns to that of the line containing
the command requiring the block.  For example:

                if x==1
                  print "X equals 1, not two"
                  print "or three or anything else"
                if x==2
                  print "X equals 2"

        Else associates with the if with the same indentation level, not, as
is usual, with the latest if.  Thus the following code works as it is
printed:

                if x!=1
                   if x==2
                      print "X equals two"
                else
                   print "X equals one"

CONSTANTS

        Integers may be entered in a variety of bases:

                x=128           # Decimal
                x=0x80          # Hexadecimal
                x=0200          # Octal
                x=0b10000000    # Binary

        Also the ASCII value of a character may be taken as an integer:

                x='A            # The value 65
                x='C'           # The value 67 (the second ' is optional)
                x=''            # The ASCII value for '
                x='''           # The ASCII value for '

        The following "escape sequences" may also be used in place of a
character:

                x='\n           # New-line
                x='\r           # Return
                x='\b           # Backspace
                x='\t           # Tab
                x='\a           # Alert (bell)
                x='\e           # ESC
                x='\f           # Form-feed
                x='\^a          # Ctrl-A (works for ^@ to ^_ and ^?)
                x='\010         # Octal for 8
                x='\xFF         # Hexadecimal for 255
                x='\d196        # Decimal
                x='\z           # Any other character is returned as itself

        String constants are enclosed in double-quotes:


                x="Hello there"

        Escape sequences may also be used inside of strings.
        Large strings may be written on multiple lines using + operation
(which executed at compile-time over constant strings):

                x="Hello " +
                  "there"

EXPRESSIONS

        An expression is a single or dual operand operator, a constant, a
variable, a lambda function, commands enclosed within parenthesis, a
function call, or an object.  Examples of each of these cases follow:

                ~expr                   Single operand

                expr+expr               Dual operand

                25                      Constant

                (command ; ...)         Commands or expressions inside of
                                        parenthesis (evaluates to the last
                                        expression or command)

                expr[expr ...]          Function call

                {1, 2, 3, 4}            An array object

                {`next=item `value=1}   A structure object

                (::x y ; x*y)[3, 5]     Calling a lambda function

OPERATORS

        Ivy uses a superset of operators from C but with the precedence
fixed. Constant expressions are computed at compile-time.
Here are the operators grouped from highest precedence to lowest:

        `                               # Named argument

        .                               # Member selection

        [ ]                             # Function call

        - ~ ! ++ --                     # Single operand

        << >>                           # Shift group

        * / & %                         # Multiply group

        + - | ^                         # Add group

        == > < >= <= !=                 # Comparison group

        &&                              # Logical and

        ||                              # Logical or

        = <<= >>= *= /= %= += -= |= ^= .=       # Pre-assignments
        : <<: >>: *: /: %: +: -: |: ^: .:       # Post-assignments

        \                               # Sequential evaluation

        ,                               # Sequential evaluation or argument
                                        # separation


        A detailed description of each operator follows:

        ` Named argument

                This operator can be used to explicitly state the argument
or member name in a command, function call or object.  For example:

                open `name="joe.c",  `mode="r"
                square[`x=5, `y=6]
                {`1=5 `0=7}                     # Array object
                {`x=10 `y=10}                   # Structure object

        . Member selection

                This operator is used to select a named member from an
object.  For example:

                o={`x=5, `y=10}         # Create an object
                print o.x               # Print member x
                print o["x"]            # Equivalent to above

        [ ] Function call

                This operator calls the function resulting from the
expression on the left with the argument inside of the brackets.  This
operator can also be used for object member selection and for string
character selection and substring operations.  Examples of each of these
follow:

                x.y[5]                  # Call function y in object x

                z[0]=1, z[1]=2          # Set numbered members of an object

                z["foo"]=3, z["bar"]=4  # Set named member of an object

                print "Hello"[0]        # Prints 72

                print "Hello"[1,3]      # Prints "el" (selects substring
                                        # beginning with first index and
                                        # end before second).

                a="Hello"
                a[0]='G
                a[5]=" there"
                print a                 # Prints "Gello there"
                                        # Overwrites characters in the
                                        # destination string and space-fills
                                        # if necessary.

        - Negate

        ~ Bit-wise one's complement

        ! Logical not

        ++ Pre or post increment depending on whether it precedes or follows
           a variable (executed by adding integer 1 to object)

        -- Pre or post decrement

        << Bit-wise shift left

        >> Bit-wise shift right

        * Multiply

        / Divide

        & Bit-wise AND

        % Modulus (Remainder)

        + Add or concatenate

                In addition to adding integers, this operand concatenates
        strings if strings are passed to it.  For example:

                print "Hello"+" There"          # Prints "Hello There"

                Add also adds a single item onto the end of an array.  For
        example:

                a={1 2 3}
                a+=4                    # a now is { 1 2 3 4 }

        - Subtract

        | Bit-wise OR

                If objects are given as arguments to OR, OR unions the
        objects together into a single object.  If the objects have
        numerically referenced members, OR will append the array on the
        right to the array on the left.  For example:

                a={1 2 3}
                b={4 5 6}
                a|=b                    # a now is {1 2 3 4 5 6}

        ^ Bit-wise Exclusive OR

        == Returns 1 (true) if arguments are equal or 0 (false) if arguments
           are not equal.  Can be used for strings and numbers.

        >  Greater than
        >= Greater than or equal to
        <  Less than
        <= Less than or equal to
        != Not equal to

        && Logical and

                The right argument is only evaluated if the left argument is
        true (non-zero).

        || Logical or

                The right argument is evaluated only if the left argument is
        false (zero).

        \ Sequential evaluation

                The left and then the right argument are evaluated and the
        result of the right argument is returned.

        , Sequential evaluation or argument separator

                When this is used inside of [ ] or { } it is an argument
        separator.  In those cases, \ should be used for sequential
        evaluation.

        = Pre assignment

                The right side is evaluated and the result is stored in the
        variable specified on the left side.  The right side's result is
        also returned.

        : Post assignment

                The right side is evaluated and the result is stored in the
        variable specified on the left side.  The left side's original value
        is returned.

        X= Pre-assignment group

                These translate directly into: "left = left X right"

        X: Post-assignment group

                These translate directly into: "left : left X right"

        Notes on assignment groups:

                .=      translates into "left = left . right" and is
                        useful for traversing linked lists.  For example:

                        for list=0\ x=0, x!=10, ++x     # Build list
                          list={`next=list, `value=x}

                        for a=list, a, a.=next          # Print list
                          print a.value

                x+:1    Is the same as x++
                x+=1    Is the same as ++x

                a:b:c:5
                        ':' is useful for shifting the value of variables
                        around.  In this example, a gets b, b gets c, and
                        c gets 5.

                a:b:a
                        ':' is also useful for swapping the values of
                        variables.  In this example, a gets swapped with
                        b.


STATEMENTS

Function declaration:

        :name expr expr expr ... ; body

        :name expr expr expr ...
          body

                These declare functions.  Here are some examples:

                        :square x ; x*x

                        :square[x] x*x

                        :square x
                          x*x

                        square=(::x ; x*x)

                The last form uses "Lambda" (nameless) functions.  You can
                also use lambda functions without assigning them:

                        x=(::x ; x*x)[6]        # x gets assigned 36

                You can also enclose the function arguments in square
                backets:

                        x=(::[x] x*x)[6]                # ; not needed


If statement

        if expr block
        else if expr block
        else block

                Note that 'else' does not work unless it is in a block.

Loop statement

         loop block
               The block gets repeatedly executed until a 'break' or
               'until' statement within the block terminates the loop.

While statement

         while expr block
               The block is repeatedly executed if the expression is true.

For statement

         for expr1, expr2, expr3 block
               This is a shorthand for the follow while statement:

                        expr1 while expr2
                           block
                           expr3

               Thus,
                  expr1 is usually used as an index variable initializer
                  expr2 is the loop test
                  expr3 is the index variable incrementer

Loop labels

         @scan  for ...
         @scan  while ...
         @scan  loop
               Loop blocks may be labeld such a way. Labels can be
               used in break/continue operators.


Return statement

        return
        return expr
                This exits the function it is executed in with the given
                return value or with the value of the last expression
                preceeding the return.

Break statement

         break
         break N
               This aborts the innermost or Nth innermost loop

         break lab
               This aborts loop labeled by lab

Continue statement

         continue
         continue N
               This jumps to the beginning of the innermost or Nth loop.

         continue lab
               This jumps to the beginning of the loop labeled by lab

Until statement

         until expr

               This exits the loop it's in if the expression is true.

Local statement

         local a, b, c,... block

               This declares variables which are local to the block

With statement

         with x block

               The members of the object x look like local variables inside
               of the block.

Include statement

         include "string"

               Executes the file specified by the string.


FUNCTIONS

        When the block inside of a function gets control a special
variable becomes visible:

                argv    Contains an object containing numbered members
                        which are each set the arguments passed to the
                        function.

        So for example, if the function:

                :x
                  for a=0, a!=len[argv], ++a
                    print argv[a]

        gets called as follows:

                x[1 2 3]

        The following gets printed:

        1
        2
        3

        Default values may be specified for missing arguments in function
calls.  For example if this function:

                :func x=5, y=6
                  x*y

        Is called as follows:

                print func[1]           # '6' is printed
                print func[]            # '30' is printed
                print func[`y=7]        # '35' is printed


        Functions may be assigned to variables and passed to functions.  For
example you can define a function 'apply' which applies a function to an
argument:

                :apply x y
                  return x[y]

                :square x
                  return x*x

                print apply[square,5]   # Prints 25


        Functions can return other functions.  To do this 'return' must be
used since it forces its argument to be an expression (otherwise the
returned function name would look like a function call).  For example:

                :square x
                  return x*x

                :foo
                  return square

                print foo[][4]          # Prints 16

VARIABLES

        Variables set outside of functions are global variables.  They will
be visible in any block unless 'local' is used to make local variables.

        If a variable is set inside of a function and there is no global
variable of the same name, that variable will be local to the block it was
assigned in.


OBJECTS

        Objects can be created either member by member:

                o.a=5
                o.b=6

        or all at once:

                o={`a=5, `b=6}

        Objects are assigned by reference.  This means that if you have an
object in one variable:

                x={1 2 3}

        And you assign it to another:

                y=x

        And then change one of the members of x:

                x[0]=5

        Then the change will appear both in x and in y


COMMENTS

        Everything from any # not in a string or string constant to the
end of the line is a comment.


FUNCTION LIBRARY

        len[a]

                Returns the length of string 'a' or number of element in
                array 'a'

        print[...]

                Prints the arguments

        a=get[]

                Get a line of input as a string

        x=atoi["2"]

                Converts a string to a number

        s=itoa[20]

                Convert a number to a string


