CodeTrees in JSON - Spicery/Nutmeg GitHub Wiki

The following is a quick sketch of a few initial types of the codetree. The code-tree refers to a whole collection of nodes, each node being a codelet. The JSON schema, which gives a more formal definition, and can be found in codetree.schema at the top-level of the repo.

Every codelet of a codetree is a JSON object with a property "kind" that tells us what type of node it is . We have picked the more distinctive word 'kind' as opposed to 'type' in the hope that it will cause less ambiguity when writing documents. However it is really a synonym for being a subtype.

All

  • Every codelet has a (required) property "kind".

Literal Constants

  • Constants uniquely have the (required) property "value", which is always string-valued, even for integers or booleans.
  • No other codelet may have that property.
  • Constants may have auxilliary properties that tell us how to decode the "value" property e.g. "radix" or "format"
  • Examples
    • { "kind": "string", "value" : "hello, world!" }
    • { "kind": "int", "radix": 10, "value": "727823" }
    • { "kind": "date", "format": "YYYY-MM-DD", "value": "2020-06-04" }
  • Python constructors (from codetree)
    • StringCodelet( "hello, world!" ), StringCodelet( value="hello, world!" )
    • IntCodelet(727823), IntCodelet(radix='10', value='727823')

Identifiers (IDs)

  • Identifiers can be introduced (var, val, const), used for their value (get) or may be assigned to (set). This is described by the "reftype" property.
  • Resolving will remove "var", "const" and "val" reftypes in favour of "new" and two boolean properties: "nonassignable" and "const". The "val" reftype adds "nonassignable": true and "const" adds "const": true.
  • Examples
    • { "kind" : "id", "name" : "x", "reftype" : "val" } which becomes after resolution { "kind" : "id", "name" : "x", "reftype" : "new", "nonassignable": true, "const": false }
  • Python constructors (from codetree)
    • IdCodelet( name='x', reftype='const' )

Sequences (seq)

  • Sequences correspond to sequential statements or patterns.
  • They appear pervasively in the codetree!
  • Their kind property is seq.
  • The sequence of expressions is put in an array valued property body.
  • Examples
    • { "kind": "seq", "body": [ { "kind": "int", "value": "1" }, { "kind": "int", "value": "2" } }
    • { "kind": "seq", "body": [] } - the empty sequence
  • Python constructors (from codetree)
    • SeqCodelet( IntCodelet( 1 ), IntCodelet( 2 ) )
    • SeqCodelet( body=[ IntCodelet( 1 ), IntCodelet( 2 ) ] )
    • SeqCodelet() ### the empty sequence

Binding

  • Bindings perform a one-way pattern-matching.
  • Examples
    • { "kind" : "bind", "lhs" : PATTERN, "rhs" : EXPRESSION }

If

  • If-expressions are TEST, THEN, ELSE statements
  • Statements are represented as an array of expressions - as there's no distinction between a single statement and an expression at the syntactic level.
  • Example
    • { "kind":"if", "test": {"kind":"bool", "value":"true"}, "then": {"kind":"string", "value":"yes"}, "else": {"kind":"string", "value":"yes"} }
    • See Extended Example

Let

  • Let-expressions have an upper half that introduces bindings (typically) and then a lower half that has a series of statements.
  • Statements are represented by an array e.g. [ {"kind":"binding", "lhs": {"kind":"id", "name":"x", "reftype": "var"}, "rhs": {"kind":"null"} } ]
  • Examples
    • { "kind": "let", "top": STATEMENTS, "bottom": STATEMENTS }
    • See Extended Example

System Call (kind: syscall)

  • Used to represent calls to built-in functions
  • Examples
    • {"kind": "syscall", "name": "currentDirectory", "arguments": [] }
    • See Extended Example

Call (kind: call)

  • Used to represent calls to variables
  • Examples
    • {"kind": "call", "function": { "kind": "id", "name": "f", "reftype": "get"}, "arguments": [] }

Function Objects

  • Used to represent (user-defined) functions and methods.
  • They have the required property of "parameters", which should be a list of patterns (ids).
  • And the required property "body", which is the code that should be executed.
  • The compilation process will add two fields "nargs" (number of arguments) and "nlocals" (number of locals), which determine how many values are popped off the value stack and into the first slots of the call-frame and how big the call-frame is.
  • Examples

For and In

  • Used to represent loops
  • Examples
    • { "kind": "for", "query": { "kind": "in", "pattern": { "kind": "id", "name": "i", "reftype": "val" }, "streamable": { "kind": "id", "name": "L", "reftype": "get" } }

Wuntil = While/Until

  • Used to filter a query
  • Example
    • { "kind": "wuntil", "query": { "kind": "nonstop" }, "result": { "body": [], "kind": "seq" }, "sense": false, "test": { "kind": "bool", "value": "true" } }

Do

  • Used to provide an action for each solution of a query
  • Examples
    • { "kind": "do", "body": { "kind": "seq", "body": [] }, "query": { "kind": "nonstop" } }

Nonstop

  • Defines a query with an infinite number of solutions that binds no variables
  • Examples
    • { "kind": "nonstop" }