LANG/BGB Spec:
Initial: 2002-09-25 To: 2003-01-06

SYS/BGB Spec:
Initial: 2003-07-17

SYS/BGB

LANG/BGB
    Syntax
        LBS Syntax
        LB Syntax
        LB2 Syntax
        Notations
    Semantics
    Patterns
    Environments
    Objects
    Macros
    Threads/Messages
    Misc
    Constraints
    Possible Future
        Modules
Features
    Base Language Extensions
        Dictionaries
    Persistence
    Net
    Graphics
        2D Mode
        3D Mode
        Physics

LANG/BGB

This spec will outline differences between scheme as defined by R5RS and LANG/BGB.

Syntax

This section will talk about the syntaxes that may be used with LANG/BGB. A syntax in LANG/BGB is selected via the extension of the source file.
later I may allow the syntax to be changed in the repl via repl commands. the idea is that repl commands would have the form 'cmd:' or (cmd: ...), and are not passed to the interpreter.

LBS Syntax

The LBS syntax will be a variation of s-expressions, these will be similar to the scheme s-expressions except:
#z is defined as a general nil value. this is used to indicate a logical response as being neither true or false, or a value as N/A. this is distinguished from the empty list, which is intended to serve as such...

[...] will define soft lists, soft lists implicitly expand to (list ...).
#[...] will define soft vectors, similarly these expand to (vector ...).

`[...] is a semi-hygenic version of backquote, it expands (adqq ...). within this form symbols of the form key$ are automatically gensym'd (and are gueranteed unique within this instance).

Both #! ... !# and #| ... |# are notations for block comments. Block comments are allowed to be nested. Block comments are required to terminate with the same form as the began, thus #! ... !# or #| ... |#, but not #! ... |# or #| ... !#. Both kinds may be nested within each other but the previous rule still holds, thus: #| #! |# !# is invalid.
Block comments are not allowed to begin within line comments if the end is not on the same line.

; is the notation for line comments (as per r5rs).

#;... is a notation for commenting out a single form (irrespective of type/linebreaks).
ex: (+ 1 #;(+ 2 3) 4) => 5, as the center (+ 2 3) is commented out.

Otherwise it is syntactically similar to scheme syntax as defined in R5RS.

LB Syntax (un-deprecated)

This syntax is intended to be a useful comprimise between s-expressions and a more conventional syntax. For the most part the lang/bgb syntax will map directly to s-expressions. I have chosen not to introduce any new semantics through the syntax, thus keeping the reader simple.
In this syntax every normal line is interpreted as a list:

f x y => (f x y)

Lower lines with a higher indentation are considered as sub-lists to the last line with a lower indentation:

begin
        f x y
                f2 z
=> (begin (f x y (f2 z)))

I will define that tab will normally pad the indentation up to a multiple of 8 chars.
'\' may be used as a line continuation character, in which case the text found on the next immediate line is considered as part of the current line.

f x y \
z
=> (f x y z)


in this case indentation is considered as unimportant, however no blank lines or comments are allowed on the next line.

f x y \

        z


Will be considered invalid.
'^' will be used to mark an object on a line to be an expression, rather than a list.

^ x => x
This is intended to allow arguments to be placed on lower lines with relative ease.

Multiple objects may be placed after '^' in which case they will all be submitted to the function:

^ x y z => x y z

Expressions may be wrapped in parenthesis, which will indicate a manual list.
This may be useful when it is not desired to code on a lower line, or to avoid increasing nesting. All parenthesis are required to be matched, and the normal indentation rules still apply.

f (f
    f x)
=> (f (f (f x)))


Comments will be indicated using the c style // and /* */ notations.
/* and */ will be allowed to be nested.

idea: make a seperation between (...) and [...]. square brackets can be used for "soft lists", parens are processed directly however [...] => (list ...). also possible: soft vectors, #[...] becomes (vector ...).
{...}, block notation. a block is considered similar to an annonymous lambda. {...} => (lambda () ...)

lists entered directly or vectors with the #(...) notation would be considered immutable...

A 'dot notation' is also supported. This is detected while parsing symbols, such that:
a => a, a.b => (a 'b), a.b.c => ((a 'b) 'c), ...
This can be used when referring to objects or namespaces, ie: self.name, root-env.system, ...

Infix notation is also supported, names beginning with "!$%&*+-/:<+>?^" will be allowed to be infix. If such a name is the second element in a list it will default to being put in functional position. '.' also has a special use here, period prefixing a normal symbol will allow it to be used infix, and '.' prefixing an infix name will indicate that it is a normal symbol.

+ 1 2 => (+ 1 2)
1 + 2 => (+ 1 2)
f 1 2 => (f 1 2)
1 .f 2 => (f 1 2)
f .+ x => (f + x)

LB2 Syntax

The LB2 syntax is similar to the LB syntax, with the exception that it is not indentation sensitive, however it will remain line-sentisitve.
LB2 will use "block notation" to acieve nesting.
There will be 2 block forms:
{...}, which will expand to (begin ...)
#{...}, which will become just ...

A block must follow an ordinary line, and will merge with the last line.

'^' in LB has become '^' and '#^'.
'^' will just expand to its arguments:
^ x => x.

However, '#^' will merge its contents with the last line:
foo x
#^ y
=> (foo x y).

Misc Notations

LANG/BGB will include keywords, these will be ordinary symbols with the exception that the last character is ':'. key:, a:, a-list:, ... are keywords.
:key is an alternate notation for keywords.

The 2 forms of keywords vary in a minor semantic respect:
Keywords of the form key: will match symbols of the same base, ex: foo: matches 'foo;
This does not hold for keywords of the form :key, they will only match themselves.

Symbols ending in '$' are viewed as "hygenic symbols", these have the property of being automatically renamed in some forms.

Semantics

There will be a difference in the workings of binding between Scheme and LANG/BGB:
bindings may be patterns. When a pattern is bound with a value the value will be decomposed to bind the values in the pattern:
(let (((x y) '(1 2))) (+ x y)) => 3

Similar can also occure with lambda and plambda, but is not allowed with defvar or define.

LANG/BGB will include dynamic variables.
Dynamic variables will be bound using defvar and letvar.

(defvar var [value])
Will define var as a dynamic var, and, if present, value will be bound to var.
A dynamic var is required to be defined before it is referenced.

(letvar ((var value)*) body*)
This is similar to let, however it will bind values within the dynamic environment rather than the lexical environment.

(define var value)
This is similar to the scheme define, it will bind if not present or replace if present.

(defmulti pattern value)
This will be similar to define but will decompose value in order to bind to the variables in pattern.

(defmultivar pattern value)
This will be similar to defmulti but will bind in the dynamic environment.

(rlet name ((var value)*)
        body*)
This will be a renamed form of named let. the reason for this rename is that named let can be confusing when first seen.

(function name (pattern)
        body*)
This will be the preferred means by which to define a function.
An implementation may allow multiple functions to share the same name and differ in argument shape or structure. At present I will not define the order in which definitions will be searched, so it will be considered invalid for function definitions to overlap.

(plambda (pattern)
        body*)
This will be similar to lambda, but will preserve pattern for later matching. I will not define if a plambda can be directly applied to arguments.

(pattern closure)
This will extract the pattern from a closure defined by plambda (not implemented).

(match pattern arguments)
Will return a weight indicating how closely arguments matches pattern, or #f in the case that pattern and arguments do not match.
Pattern matches will be based on whether both have the same general shape, and that literals are equal.

(eval form)
In normal cases I will define eval to work within the environment of a caller, thus it may be used for defining new code within the caller.

(eval form env)
Evaluate form with the lexical environment given in env, and the present dynamic environment.

Environments are first class objects. I will define 'current-environment' as being able to take a snapshot of the bindings in existance from where it is called.
(I may later allow for controlled "contexts", changes within these contexts will be consistent between calls)

(set! var value)
Set! will assign a value to a variable or expression. Conceptually though set! will not distinguish between variables and expressions, a variable reference is considered as equivalent to a symbol identifying the variable, which is equivalent to an expression evaluating to a given location.
Expressions will have 2 return values: a reference to the returned object, and a reference to the slot in which that value came from. These 2 values will be referred to as 'ax' and 'rax' respectively.
Rax does not necissarily refer to a location though, and can not normally be passed up through statements; it is only visible from direct returns. I will define that apply is to clear this value to #z, and it may be cleared in other places as well.
Other systems had defined the concept of a setter, however that concept is not viewed as fundamental in this case. A setter will be viewed as a function which returns it's value in rax, and a getter returns it's value in ax.
(bind-getter-setter getter setter) will create a function which when called will invoke both functions on the given arguments, placing the getter in ax and the setter in rax. This will be one way in which to explicitly return a value in rax.

Locatives will be similar to typed, range checked pointers. Conceptually a locative will contain: a lower extent, an upper extent, and a current reference. Normally: lower<=reference<upper. The type will indicate the type of data within the region referred to by this locative, and will be the same as that for vectors.
Locatives will also serve as handles for objects such as slots, and to allow an alternate form of string manipulation (these are what will be returned in rax).

possible:
vec idx value;
obj slot value;
and, env var value; could possibly be removed.

locative? obj
Returns #t if obj is a locative, #f otherwise.

locative->integer locative
integer->locative integer
These will convert between integers and locatives. I will leave the nature of these an implementation issue.

set* locative value
Will assign value to the spot referred to by the current reference in locative.

contents locative
Will extract the value from the spot referred to by the locative's reference.

locative-new lower upper type
Creates a new locative with the lower and upper bounds defined by lower and upper, and the type type. The reference in a locative is initially set to the lower bounds.

locative-copy locative
Create a copy of the locative which may be modified independantly of the previous copy.

loc++ locative
loc-- locative
Step the direction of the locative, referring to next and previous elements respectively.

Patterns

A pattern is either a literal, a symbol, or a list (which in turn may contain more patterns).
2 literals are to match if their values are equal (with the exception of _:, which only requires the other to be a keyword).
A keyword of the form key: will also match a symbol with the same base.
An ordinary symbol will match any other type.
A list will match another list with the same length if all the members match between the lists.

Environments

Environments will be first class objects in LANG/BGB. The environments will be viewed as a stack of layers, with the outer layers being closer to the "top level" and the inner ones being increasingly closer to the current lexical bindings.
During evaluation new layers are added on top and removed as execution winds through the functions.
At any given point 'current-environment' can be called to make a snapshot of the bindings in place at that time, the position and shape of the environment is considered as static at that point (excluding changes later made to the environment, which are not to effect things created using this env). Other bindings may be added on top or at the current level, however only assignment will be visible within this env (excluding assignment to bindings not in place within this env).

At present I will define that environments will also preserve syntactic bindings.

(env 'sym)
Refers to a binding within the env.

(env 'sym value)
Assigns a value to the binding within the env.

Objects

I will use a prototype object system.
Objects will accept messages. An object has slots/handlers. A given slot may hold a certain value.
Handlers will be defined using plambda and passed to objects. When an object recieves a handler it will add it to it's list of handlers.
A message passed to an object will first be checked against the list of handlers, trying the closest match. Otherwise it will check if the message contains a plambda.
A message without a matching handler will be silently dropped.

Handlers and slots will have an associated "position", with the newest being searched first and the older ones later. this allows handlers to hide each other based on order (making the order of definition important).

It is important not to have slots and handlers with matching bases (ex: the slot foo and a handler for the message (foo:)) as there may be conflicts. Implicitly all slots can be viewed as handlers for a message of the form (slot: . x).

The general syntax for message passing will be:
(object message*)

Objects will accept a few predefined messages:

(obj clone:)
This will clone the object and cause it to return a copy of itself.

(obj get: slot)
Explicitly get a slot value.
Slot may also be a pattern in which case the associated handler can be fetched.

(obj set: slot value)
Explicitly set a slot value.

(obj slot-name)
Will cause it to return the value associated with a given slot.

(obj (plambda ...))
Will allow adding a handler to an object. If multiple handlers are added with the same pattern (via equal?) then all but the last are dropped (as it is not possible to match with them). By adding a handler the same pattern one can replace the existing handler. The new handler will have the same slot position as the previous.

(obj pattern)
Will allow one to fetch the handler associated with a given handler.

(obj slot-name value)
Will bind or assign value to the indicated slot.

Worth noting is that it may not be possible to tell the difference between a slot and a message handler. This is not entirely bad as it allows transparent invokation of functions as slots, an example of which could be:
(define triangle (root-obj clone:))
(triangle 'a 0)
(triangle 'b 0)
(triangle (plambda (c:) (sqrt (exp (self 'a) 2) (exp (self 'b) 2)))

For the convienience of defining objects there is the newobject macro:

(newobject parent . patterns)
Parent is cloned, then each of the patterns is applied to the new object.
Each has the form:
(name value) //the definition of object slots
((pattern...) body) //the definition of object handlers

This expands as:
let ((obj (parent clone:)))
(patterns)

Where:
(name value) => (obj 'name value)
((pattern...) body) => (plambda (pattern...) body)

Macros

Macros will be implemented in LANG/BGB. The idea is that a macro will take a piece of code and perform some operation on it, and will return a new piece of code to be compiled in place of the macro call. It is also possible for macros to return other macro definitions, in which case they are evaluated just the same as the original macro call.

(define-syntax name func)
Defines a macro which is bound to name. Func is a closure accepting a single argument, the form it was invoked as.

example:
(define-syntax add
        (lambda ((_ a b)) `(+ ,a ,b)))
(add 2 3)

(pattern-case key . forms)
Where each form is:
(pattern body)

Matches key against each pattern in forms, and once a match is found, returns the result of executing body.
If no match is found the result is undefined.

(defmacro name (args)
        body*)
This is a shorthand for macro definition, it exists mostly for typing convinience.

``(pattern...)
This is an alternative for quasiquote. ``(pattern...) expands as (doubleqq (pattern...)), and differs from the main quasiquote in that it forms variable renaming. At present this is done through hygenic variables, but later it may automatically rename bound variables (at which time a syntax may be in place to cause capture). Hygenic variables are identified by symbols with the form 'name;', and the renaming will work by replacing such symbols with appropriate gensyms. Later occurances of the same symbol within the pattern will use the same gensym, however the symbols will not be valid outside that pattern.
problem: this is presently not sufficient to implement hygenic macros...

possible new rule:
within the quotation symbols are altered to indicate they refer to a specific environment, which is passed along with the expanded code. new bindings are effectively renamed or bound within the passed environment.
syntax first sums up the bindings used within the quotation and generates an env with these bound (having been renamed to gensyms). hygenic symbols could be considered literals which escape the conversion (as normal symbols).
also: symbols could be replaced with objects which represent a binding between the actual object and the symbol name. the objects could differentiate variable and syntactic bindings, and could be handled during compilation.
they would be replaced by constant forms as appropriate, or be expanded in the case of syntax.
new binds are just renamed to gensyms.

(mini . opcodes*)
This allows statements to be written within the LANG/BGB "minicode", this can be viewed as a kind of high level assembler and is not intended to be used in general programs (as the nature of the minicode may change).
This makes use of ,, (doublemark) in order to allow inlining of statements.
During compilation the indicated minicode fragments will be substituted in place of the mini construct, and inlined expressions will be compiled and substituted in place.

Threads/Messages

(begin-thread
        body*)
Begin a thread which executes body then terminates. The return value is the "pid" of the thread, which may be used to refer to the thread.

(begin-looped-thread
        body*)
Begins a thread which executes body in a continuous loop. This returns a pid.

(thread thunk)
Begin a thread which evaluates thunk then terminates. Similarly this also returns a pid.

(recieve-case (pattern handler)*)
Recieves a message and dispatches it to the first handler in which the message matches pattern.

(recieve)
Recieves a message and returns the value.

(pid args*)
Sends a message to pid. the message is prepended with the sender's pid so that a response may be sent.

Misc

=, synonym for equal?
==, synonym for eq?
!=, not equal?
!==, not eq?
:=, set!
more to be added.

Constraints

A simplistic constraints system exists.
Constraints are variables with special contents that, instead of returning themselves when the var is referenced, will return the value associated with them.
When the value of a constraint is assigned it will invalidate any that depend on it (ie: so they can be recomputed on next reference).
Constraints may also be placed in objects.

(constraint <expression>)
This will create a constraint for the given expression. The expression will be used to indicate what value the constraint will have once it is computed.

(assign! <constraint-var> <value>)
Will assign the value of a constraint.

examples:
(define x (constraint 3))
(define y (constraint 4))
(define z (constraint (sqrt (+ (* x x) (* y y)))))

so:
x => 3
y => 4
z => 5

(define w (vector x y z))
w => #(3 4 5)

(assign! x 6)
(assign! y 8)
z => 10

w => #(3 4 5), since w was a normal value and not a constraint.


Possible Future

Modules

Modules will exist as environments with a controlled set of bindings.
During creation of a module a new binding layer will be created representing the new top level, all lower bindings will be left intact and will exist as part of the lexical environment for defined closures.
When that form is returned from the layer will be stripped off and used as the top level of a new module.

module
    forms...
Will create a new annonymous module.

defmodule location name
    forms...
Will define a new module.

import module
Import bindings from module and bind them in the present lexical env (likely using bindings which exist at compile time).

also possible:
export vars...
or: export (modname var)...

Create an annonymous module containing vars (second notation supporting renaming).

import module vars...
or: import module (var modname)...
Import a controlled set of vars with possible renaming.

also:
with-import module (vars... | (var modname)...)
    body...
Similar, but imports only temporarily.

these forms of import and export could be created using macros:
export vars... =>
``(let ((mod (empty-env))) (mod 'var var)... mod)
export (modname var)... =>
``(let ((mod (empty-env))) (mod 'modname var)... mod)

import and with-import could expand to define's and let's respectively.

misc: would need to preserve variable/syntax identity, possible: at present not allow import/export of syntax.
idea: generalized import could exist, however the module would need to exist at compile time. runtime importing could exist but be limited to a finate set of variables.

Features

This section will talk about the features present within the system.

Base Language Extensions

Dictionaries

Dictionaries will associate keys with values. There is little restriction to what can be used as a key. Dictionaries will be "reference by value", thus it is not allowed to have more than one type of key in a given dictionary.

(dict-new)
This will allow creation of a new dictionary which is initially empty.

(<dict> <key> <value>)
Will allow binding of key within the dictionary.

(<dict> <key>)
Will retrieve the value associated with <key> from the dict.
#z is returned if key is not found, at present it is not possible to determine if the key is not found or the key is bound to #z.

Persistence

By use of the '--store', '--nostore', and '--image' command line options one will be able to enable, disable, or control the store image to be used.

The rest of this will talk in the context of the strore being enabled.

The main repl by default not be persistent. The main repl will by defualt represent the most recent state of the system, and will be clean on each boot.
This will not be the case for alternate repl's, which will be persistent and, thus, may reflect an older state of the system. New repl's, however, will reflect the state of the system at the time of creation.

All data is implicitly persistent, and without any need for programmer intervention; however, without extra effort in some cases the data may not be accessible and thus collected upon subsequent runs (an example of this would be bindings only present within the main repl).

'sys-root' will be a binding to an environment which is used for storing data between runs. This will be one of a number of ways in which data may be bound to the system and thus later accessible.

Net

The default SYS/BGB network interface will be a crude distributed system.

The general idea is that nodes will be looked up based on guids.

There is a search protocol so that a node can change addresses and another node (assuming it can aquire or has open links to other nodes) can locate the node in question.
The fairly simple algorithm of passing the search requests forward over all open links (dropping ones extending past their ttl or having passed by there already) is used. If a match is found it is passed backwards to the source (enough info is maintained to trace the response back to the sender, though if it takes too long this info will be wiped out and the response dropped when it hits a broken link).

Control Nodes will be used to locate/contact other nodes (though a number of control nodes can be set up, links to multiple can be held, ...). Nearly any allready connected node can be used as a control node, or a disconnected node could also be used (though messages would be confined to the enclosing mesh unless an external link is formed somewhere).

References to many remote objects will be largely transparent, others will be copied. Passed references may be applied and to a lesser extent used in other ways, copied objects may be used normally, but will not maintain identity with the source objects. Other objects may be 'mirrored'. A mirrored object will remain synchronized with the source, but will be cheaper than an object passed by reference.

There will also be persistent references/links. Persistent links mean that a node can shut down, then come back up, and have its links (to nodes also still up) still in place, and links from other nodes to this one will "revive" (currently this is not very efficient, I will need to add a way to limit how quickly it polls/tries to reconnect, ie: a timer).

Identity (in this context) will mean that the source object and the object recieved when it is passed in a message are necessarily the same, and that modifications to the recieved object will be reflected in the source.
Psuedo Identity will be maintained with mirrored objects. Mirrored objects will largely behave like those passed by reference, however it is possible for them to become temporarily out of sync, or for other situations to occure which are not possible with references. In some cases it is possible to distinguish the behavior of an object passed by reference and one that is mirrored.

Numbers, cons cells, vectors, strings, and symbols are copied.
Environments, builtin functions, threads, and closures are passed by reference.
Objects are mirrored by default.

A function/object recieving a message over the net will have the 'from' dynamic variable bound to the thread of the sender (by default), or possibly another target in which to direct responses.

At the time of this writing handlers (with the exception of threads or of unidirectional messages) will need to return or else the sender and any other local threads will remain blocked.

The dynamic var 'from' is not bound in the case of threads, instead from is included within the message and is thus defined within the handler (ie: recieve-case).

Application will normally send a message, with the exception of threads, messages are bidirectional (threads being unidirectional by default), and with the 'from' of the reciever being directed at the current thread.

(-> obj . msg), (send-u obj msg)
Will send a unidirectional message, with unidirectional messages the sender will not block waiting for a return value, for local passes this will implicitly create a new thread to handle the message.

(<*> obj from . msg), (send-from obj from msg)
will send a message (by default bidirectional) with the from of the reciever being defined by from.

(*> obj from . msg), (send-from-u obj from msg)
will send a unidirectional message with the from of the reciever referring to from.

the long form of these has the message as an argument, these may be used to pass dynamically generated messages (in order to avoid needing to use apply to send dynamically generated messages).

these can be defined in terms of each other via a macro:
(defmacro -> (obj . msg)
    '(send-u ,obj [,@msg]))

(defmacro *> (obj from . msg)
    '(send-from ,obj ,from [,@msg]))

...

or (discouraged):
(defmacro send-from (obj from msg)
    '(apply *> [,obj ,from ,@msg]))

...


I will define that the long form exist via functions, and the shorthand forms may or may not be macros.

Adresses also exist in the system, an address can be applied and has the form:
(addr key: . msg)
This connects (if not connected allready) to the node indicated via addr and then sends msg to the specified handler (named via key:).

(add-net-handler key: handler)
Defines a handler for a given key, the intent of handlers is to allow nodes to get references and such to things defined on said node.

Addresses may be composed or located:
(list->addr def)
will create such an addr, def is a list with the form (type ...),
type defines how the rest is structured:
    (ipv4tcp (a b c d) port)
        defines a tcp address;
    (ipv4udp (a b c d) port)
        defines udp addr.

Similarly, (addr->list addr) will decompose an address into said list form.

(find-host name) will locate the address for an indicated host.

MRP: Message Relay Protocol (deprecated)

MRP spec contains newer version.

MRP will give each connection a stack machine. This stack machine will process messages from other nodes. It will handle directing messages to remote objects and will dispatch incomming messages to the appropriate objects.

An incomming reference will have the full route info to get it back to the source.

Encoding

multibyte values will be in big-endian order.

when the stream is in command mode a byte will be read and interpreted:
cmd&7:
0: number
    (cmd>>3)&7
        0=unsigned
        1=signed
        2=float
        3=widenum, 128-1024 bit
        4=misc/const

    (cmd>>6)&3
        0=1 byte/u128
        1=2 byte/u128
        2=4 byte/u128
        3=8 byte/u128

    misc:
        1=false
        2=true
        3=null
        4=eol

1: command
    2 bytes, upper 4 bits and next byte (forming upper 8 of opcode)

    range:
        0x000-0x0FF: vid/base protocol
        0x100-0x1FF: mrp
        0x200-0xDFF: reserved
        0xE00-0xEFF: extension required
        0xF00-0xFFF: extension optional (all are MARK ... OP)

2: object
    object has upper 5 bits as a type. this is followed by data
        relating to the the object.
    1: data object
        followed by byte encoding and 32 bit length.
        encoding will have the lower 3 bits for data encoding:
            0: raw
            1: deflate
        encoding will have the next 3 bits as a type:
            0: data
            1: byte vector
            2: block
        the upper 2 bits of encoding are reserved.
    2: symbol
        contains a byte length and so many bytes of data.
    3: string
        contains a short length and so many shorts of data.
    4: negotiation
        contains a short length and so many bytes of data.
        "keyword" or "var=value"
    5: binary command
        contains a short opcode, a short length, and so many bytes of
        data.
        these are not to be directed at the interpreter, rather they
        are related to network features. these are also not to effect
        the future behavior of the net stack/opcodes.
        unknown binary commands are to be ignored, space is divided:
            0-4095: mrp
            4096-32767: implementation
            32768-65535: possible user/implementation

Opcodes

Name
Number
Description
MRPOP_NOP
0x000
Does nothing
MRPOP_MARK
0x005
Marks the current stack position
MRPOP_CONS
0x100
Conses arguments: a b -> (a . b)
MRPOP_RCONS
0x101
Reverse conses arguments: a b -> (b . a)
MRPOP_LIST
0x102
Creates a list: MARK ... -> (...)
MRPOP_LISTI
0x103
Creates a list with a non EOL tail: MARK a... b -> (a... . b)
MRPOP_VECTOR
0x104
Creates a vector: MARK ... -> #(...)
MRPOP_ADDR
0x108
addr port type -> ADDR
type: 1=ipv4udp, 2=ipv4tcp
MRPOP_RREF
0x109
Relative to the sender of the message: refnum type -> LREF
MRPOP_LREF
0x10A
ADDR refnum type -> LREF
MRPOP_DISPATCH
0x10B
msg from refnum
MRPOP_RDISPATCH
0x10C
msg from refnum cont-id
sends SETTER and RETURN to return values.
cont-id will be used to sync calls and returns
MRPOP_SETTER
0x10D
setter cont-id
MRPOP_RETURN
0x10E
value cont-id
send parts of a return value, setter is to come first
MRPOP_YREF
0x10F
refnum -> obj
relative to the reciever, to be used for references to objects on reciever.
MRPOP_COPY
0x110
refnum cont -> sends RETURN w/flat version

#define MRPVAL_FALSE    1
#define MRPVAL_TRUE    2
#define MRPVAL_NULL    3
#define MRPVAL_EOL    4

#define MRPVAL_IPV4UDP    1
#define MRPVAL_IPV4TCP    2

//RREF/LREF type, low 3 bits type:
#define MRPVAL_TYPE_OBJECT    1    //next 6 bits object type
#define MRPVAL_TYPE_CONS    2

//extended types
#define MRPVAL_TYPE_CLOSURE    ((1<<3)|1)
#define MRPVAL_TYPE_ENV        ((2<<3)|1) //environment
#define MRPVAL_TYPE_ENVOBJ    ((3<<3)|1) //object
#define MRPVAL_TYPE_CONTEXT    ((4<<3)|1) //interpreter context/thread
#define MRPVAL_TYPE_FUNCTION    ((5<<3)|1)

Graphics

The console can be summoned via tab, and tab can also make it go away.

F2 puts the gui into "3D mode" which is a different space than the 2D plane (later I may allow multiple 3D spaces, but for now there is one...).

2D Mode

Arrows can pan the gui.
Delete and end control zoom (this is partly related to my handedness).
Input focus follows the mouse, rmb can drag objects.
Lmb can be used to pan (ie: by "dragging" the plane).
Center can also be used for mouse controlled zoom.

(render show: ...) can be use to make objects visible. Some objects are created in the gui init script but are not shown by default.

Render is a general object used for interaction with the local gui. When a 'render:' handler is called 'render' still refers to the local gui, but 'from' may refer to a non-local one (similar goes for other handlers as well).

3D Mode

3D mode is a seperate space from 2D mode.

Controls differ as well:
    Up/down are forwards/backwards;
    Left/right control strafing;
    Delete/end control up/down movement;
    The mouse controls angles;
    Mouse+lmb can also control forwards/backwards movement.

Up/down angles are constrained to +-90, mostly as I wanted to avoid getting the camera "upside down" (for some things this could be useful, so I will consider it). Similarly for now I do not have roll, but may add that later (it is in my mind complicated and rarely useful...).

I will define that this will use right-hand coordinates with +Y as up, and a CCW face front. The base unit length will be the meter, mass kilogram, force newton, ...

(render3d show: ...) can show 3d objects (primitives, groups, entities).

(render3d camera: entity) set the entity to be used as a camera.

(primitive-3d key opts...) can create a 3d primitive.
Key can be: 'cube:', 'cylinder:', 'sphere:' or 'disk:' at present.

Cylinder, sphere, and disk are normally aligned along the XY plane.

Options are keywords which may be followed by values:
name: symbol
Allows the primitive to be named.
min: vector
Defines the minimum extents (cube).
max: vector
Defines the maximum extents (also cube).
radius: scalar
Defines the normal radius (cylinder, sphere, disk).
radius-top: scalar
Radius at top (cylinder, top is +Z).
radius-bottom: scalar
Radius at bottom (cylinder, bottom is -Z).
height: scalar
The height of a cylinder.
texture: map
Allows selection of a texture map.
translate: vector
Translates primitive by vector (local).
rotate: vector
Rotates by vector (local).
scale: vector
Scales by vector (also local).
identity:
Resets back to identity value.

Transforms are cummulative, meaning that (annoyingly enough) at present one has to reset identity to get non-local transforms (though I may add "global" forms of the transforms for this), and has to take the order into account when performing transformations.

These options can be passed to primitives after creation for the purpose of altering them.

(group-3d opts... objs...) creates a group of objects.

At present opts is limited to those for transformation and to 'name:' and 'texture:'.

With a group though one can reference named primitives:
(define c (group-3d (primitive-3d sphere: name: 'sphere radius: 10)))
c.sphere would refer to the inner sphere.

(texture opts...)
Allows the creation of texture objects.
At present only a few options are allowed for textures:
    name: name, allows the texture to be named;
    image: file, allows the texture image to be selected.

Texture mapping has scope, where each textured primitive adds to the texture scope. Untextured primitives within the rendering scope of a textured primitive/group will use the texture of that primitive/group.

Entities are objects, that, like the gui, are rendered via a 'render:' handler (may change to 'render-3d:' to allow objects with seperate 2D/3D appearance).
Both prinitives and groups may be passed 'render:' messages in order to cause them to be rendered.

Entities will have special slots:
    origin, vector, will indicate the location of the object (to effect rendered primitives);
    angles, vector, will indicate the rotation of the object (also to effect primitives);
    velocity, vector, indicates the current object velocity;
    mass scalar, will indicate the object mass;
    bounce scalar, will indicate how much energy is used in bouncing (relative).
    friction scalar, will indicate how much energy is absorbed by objects sliding along surface (relative);
    bbox-max vector, indicates the maximum extents of the entity;
    bbox-min vector, indicates the minimum extents of the entity;
    v-offset vector, relative offset if this entity is used as a camera;
    v-angles vector, viewing angles if this entity is used as a camera (yaw pitch roll, y-axis up).

Physics

Physics will be centered around entities.

(phys add: ent) will add the entity to the physics system.
(phys gravity:) will fetch the gravity vector.
(phys gravity: vector) will set the gravity vector.

For now there will be bounding box collision.
bbox-min and bbox-max will refer to the bounding extents of the entity. Finer collision detection (such as the individual primitives) may be added later.
Entities will have friction, this will indicate how much to slow other entities that contact it.