type program { functions: (handle function) sandboxes: (handle sandbox) } type sandbox { setup: (handle line) data: (handle line) cursor-word: (handle word) next: (handle sandbox) prev: (handle sandbox) } type function { name: (handle array byte) args: (handle word) # in reverse order body: (handle line) # some sort of indication of spatial location next: (handle function) } type line { name: (handle array byte) data: (handle word) result: (handle result) # might be cached next: (handle line) prev: (handle line) } type word { # at most one of these will be non-null scalar-data: (handle gap-buffer) text-data: (handle array byte) box-data: (handle line) # recurse # other metadata attached to this word display-subsidiary-stack?: boolean next: (handle word) prev: (handle word) } type value { scalar-data: int text-data: (handle array byte) box-data: (handle line) } type table { data: (handle array bind) next: (handle table) } type bind { key: (handle array byte) value: (handle value) # I'd inline this but we sometimes want to return a specific value from a table } type result { data: value-stack error: (handle array byte) # single error message for now } fn initialize-program _program: (addr program) { var program/esi: (addr program) <- copy _program var functions/eax: (addr handle function) <- get program, functions create-primitive-functions functions var sandbox-ah/eax: (addr handle sandbox) <- get program, sandboxes allocate sandbox-ah var sandbox/eax: (addr sandbox) <- lookup *sandbox-ah initialize-sandbox sandbox } fn initialize-sandbox _sandbox: (addr sandbox) { var sandbox/esi: (addr sandbox) <- copy _sandbox var line-ah/eax: (addr handle line) <- get sandbox, data allocate line-ah var line/eax: (addr line) <- lookup *line-ah var cursor-word-ah/esi: (addr handle word) <- get sandbox, cursor-word allocate cursor-word-ah initialize-line line, cursor-word-ah } # initialize line with a single empty word # if 'out' is non-null, save the word there as well fn initialize-line _line: (addr line), out: (addr handle word) { var line/esi: (addr line) <- copy _line var word-ah/eax: (addr handle word) <- get line, data allocate word-ah { compare out, 0 break-if-= var dest/edi: (addr handle word) <- copy out copy-object word-ah, dest } var word/eax: (addr word) <- lookup *word-ah initialize-word word } fn create-primitive-functions _self: (addr handle function) { # x 2* = x 2 * var self/esi: (addr handle function) <- copy _self allocate self var _f/eax: (addr function) <- lookup *self var f/esi: (addr function) <- copy _f var name-ah/eax: (addr handle array byte) <- get f, name populate-text-with name-ah, "2*" var args-ah/eax: (addr handle word) <- get f, args allocate args-ah var args/eax: (addr word) <- lookup *args-ah initialize-word-with args, "x" var body-ah/eax: (addr handle line) <- get f, body allocate body-ah var body/eax: (addr line) <- lookup *body-ah initialize-line body, 0 var curr-word-ah/ecx: (addr handle word) <- get body, data allocate curr-word-ah var curr-word/eax: (addr word) <- lookup *curr-word-ah initialize-word-with curr-word, "x" curr-word-ah <- get curr-word, next allocate curr-word-ah curr-word <- lookup *curr-word-ah initialize-word-with curr-word, "2" curr-word-ah <- get curr-word, next allocate curr-word-ah curr-word <- lookup *curr-word-ah initialize-word-with curr-word, "*" # x 1+ = x 1 + var next/esi: (addr handle function) <- get f, next allocate next var _f/eax: (addr function) <- lookup *next var f/esi: (addr function) <- copy _f var name-ah/eax: (addr handle array byte) <- get f, name populate-text-with name-ah, "1+" var args-ah/eax: (addr handle word) <- get f, args allocate args-ah var args/eax: (addr word) <- lookup *args-ah initialize-word-with args, "x" var body-ah/eax: (addr handle line) <- get f, body allocate body-ah var body/eax: (addr line) <- lookup *body-ah initialize-line body, 0 var curr-word-ah/ecx: (addr handle word) <- get body, data allocate curr-word-ah var curr-word/eax: (addr word) <- lookup *curr-word-ah initialize-word-with curr-word, "x" curr-word-ah <- get curr-word, next allocate curr-word-ah curr-word <- lookup *curr-word-ah initialize-word-with curr-word, "1" curr-word-ah <- get curr-word, next allocate curr-word-ah curr-word <- lookup *curr-word-ah initialize-word-with curr-word, "+" # x 2+ = x 1+ 1+ var next/esi: (addr handle function) <- get f, next allocate next var _f/eax: (addr function) <- lookup *next var f/ecx: (addr function) <- copy _f var name-ah/eax: (addr handle array byte) <- get f, name populate-text-with name-ah, "2+" var args-ah/eax: (addr handle word) <- get f, args allocate args-ah var args/eax: (addr word) <- lookup *args-ah initialize-word-with args, "x" var body-ah/eax: (addr handle line) <- get f, body allocate body-ah var body/eax: (addr line) <- lookup *body-ah initialize-line body, 0 var curr-word-ah/ecx: (addr handle word) <- get body, data allocate curr-word-ah var curr-word/eax: (addr word) <- lookup *curr-word-ah initialize-word-with curr-word, "x" curr-word-ah <- get curr-word, next allocate curr-word-ah curr-word <- lookup *curr-word-ah initialize-word-with curr-word, "1+" curr-word-ah <- get curr-word, next allocate curr-word-ah curr-word <- lookup *curr-word-ah initialize-word-with curr-word, "1+" # TODO: populate prev pointers } fn populate-text-with _out: (addr handle array byte), _in: (addr array byte) { var in/esi: (addr array byte) <- copy _in var n/ecx: int <- length in var out/edx: (addr handle array byte) <- copy _out populate out, n var _out-addr/eax: (addr array byte) <- lookup *out var out-addr/edx: (addr array byte) <- copy _out-addr var i/eax: int <- copy 0 { compare i, n break-if->= var src/esi: (addr byte) <- index in, i var val/ecx: byte <- copy-byte *src var dest/edi: (addr byte) <- index out-addr, i copy-byte-to *dest, val i <- increment loop } }