type sandbox { setup: (handle line) data: (handle line) # display data cursor-call-path: (handle call-path-element) expanded-words: (handle call-path) partial-name-for-cursor-word: (handle word) # only when renaming word partial-name-for-function: (handle word) # only when defining function # 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 { scalar-data: (handle gap-buffer) next: (handle word) prev: (handle word) } type value { type: int int-data: int # if type = 0 text-data: (handle array byte) # if type = 1 array-data: (handle array value) # if type = 2 file-data: (handle buffered-file) # if type = 3 } 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 } # A call-path is a data structure that can unambiguously refer to any specific # call arbitrarily deep inside the call hierarchy of a program. type call-path { data: (handle call-path-element) next: (handle call-path) } # A call-path element is a list of elements, each of which corresponds to some call. type call-path-element { word: (handle word) next: (handle call-path-element) } type result { data: value-stack error: (handle array byte) # single error message for now } 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 initialize-line line var word-ah/ecx: (addr handle word) <- get line, data var cursor-call-path-ah/eax: (addr handle call-path-element) <- get sandbox, cursor-call-path allocate cursor-call-path-ah var cursor-call-path/eax: (addr call-path-element) <- lookup *cursor-call-path-ah var dest/eax: (addr handle word) <- get cursor-call-path, word copy-object word-ah, dest } # initialize line with a single empty word fn initialize-line _line: (addr line) { var line/esi: (addr line) <- copy _line var word-ah/eax: (addr handle word) <- get line, data allocate word-ah 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 var curr-word-ah/ecx: (addr handle word) <- get body, data # *curr-word = "x" allocate curr-word-ah var tmp/eax: (addr word) <- lookup *curr-word-ah var curr-word/edx: (addr word) <- copy tmp initialize-word-with curr-word, "x" # *curr-word->next = "2" var next-word-ah/ebx: (addr handle word) <- get curr-word, next allocate next-word-ah tmp <- lookup *next-word-ah initialize-word-with tmp, "2" # *curr-word->next->prev = cu
discard """
output: '''-1abc'''
"""
var
a {.compileTime.} = 2
b = -1
c {.compileTime.} = 3
d = "abc"
static:
doAssert a == 2
doAssert c == 3
echo b, d