diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-02-16 11:47:24 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-02-16 11:47:24 +0000 |
| commit | 2953f1e56b408fc26eb54fa65935505dd128ce82 (patch) | |
| tree | 8c7c513ccf03df06c4e9e2e70ba68031d2d0b7a5 /core | |
| parent | add ==, mod (diff) | |
| download | alive-2953f1e56b408fc26eb54fa65935505dd128ce82.tar.gz alive-2953f1e56b408fc26eb54fa65935505dd128ce82.zip | |
major refactoring: Const, Stream + ResultNode
Diffstat (limited to 'core')
| -rw-r--r-- | core/base.moon | 69 | ||||
| -rw-r--r-- | core/builtin.moon | 64 | ||||
| -rw-r--r-- | core/cell.moon | 28 | ||||
| -rw-r--r-- | core/const.moon | 136 | ||||
| -rw-r--r-- | core/init.moon | 8 | ||||
| -rw-r--r-- | core/invoke.moon | 50 | ||||
| -rw-r--r-- | core/parsing.moon | 15 | ||||
| -rw-r--r-- | core/registry.moon | 5 | ||||
| -rw-r--r-- | core/scope.moon | 8 | ||||
| -rw-r--r-- | core/value.moon | 157 |
10 files changed, 289 insertions, 251 deletions
diff --git a/core/base.moon b/core/base.moon index dcf600a..1b1be5d 100644 --- a/core/base.moon +++ b/core/base.moon @@ -1,15 +1,13 @@ -class Op --- common - new: => - -- (...) => @setup ... +-- base definitions for extensions - get: => @value - getc: => - L\warn "stream #{@} cast to constant" - @value +-- a persistent expression Operator +-- +-- accepts Const or Stream inputs and produces a Stream output +class Op + update: (dt) => --- Value interface - update: => + -- set @out to a Value (Const or Stream) + setup: (...) => destroy: => @@ -17,11 +15,16 @@ class Op __tostring: => "<op: #{@@__name}>" __inherited: (cls) => cls.__base.__tostring = @__tostring - spawn: (Opdef, ...) -> - Opdef ... +-- a builtin / special form / cell-evaluation strategy +-- +-- responsible for quoting/evaluating subexpressions, +-- instantiating and patching Ops, +-- updating the current Scope, +-- etc. class Action --- common + -- head: the (:eval'd) head of the Cell to evaluate (a Const) + -- tag: the Tag of the expression to evaluate new: (head, @tag) => @patch head @@ -35,9 +38,9 @@ class Action -- free resources destroy: => - -- update this instance for :eavl() with new head - -- if :patch() returns false, this instance is :destroy'ed and recreated instead - -- must *not* return false when called after :new() + -- update this instance for :eval() with new head + -- if :patch() returns false, this instance is :destroy'ed and recreated + -- instead must *not* return false when called after :new() -- only considered if Action types match patch: (head) => if head == @head @@ -46,35 +49,51 @@ class Action @head = head -- static - @get_or_create: (ActionType, head, tag) -> + -- find & patch the action for the expression with Tag 'tag' if it exists, + -- and is compatible with the new Cell contents, otherwise instantiate it. + -- register the action with the tag, evaluate it and return the ResultNode + @eval_cell: (scope, tag, head, tail) => last = tag\last! compatible = last and - (last.__class == ActionType) and + (last.__class == @) and (last\patch head) and last L\trace if compatible - "reusing #{last} for #{tag} <#{ActionType.__name} #{head}>" + "reusing #{last} for #{tag} <#{@__name} #{head}>" else if last - "replacing #{last} with new #{tag} <#{ActionType.__name} #{head}>" + "replacing #{last} with new #{tag} <#{@__name} #{head}>" else - "initializing #{tag} <#{ActionType.__name} #{head}>" + "initializing #{tag} <#{@__name} #{head}>" - if compatible + action = if compatible tag\keep compatible compatible else last\destroy! if last - with next = ActionType head, tag + with next = @ head, tag tag\replace next + action\eval scope, tail + __tostring: => "<#{@@__name} #{@head}>" __inherited: (cls) => cls.__base.__tostring = @__tostring +-- a ALV function definition +-- +-- when called, expands its body with params bound to the fn arguments +-- (see core.invoke.fn-invoke) class FnDef + -- params: sequence of (:quote'd) symbols, each naming a function parameter + -- body: (:quote'd) expression the function evaluates to + -- scoe: the lexical scope the function was defined in (closure) new: (@params, @body, @scope) => __tostring: => - table.concat [p\stringify! for p in *@params], ' ' + "(fn (#{table.concat [p\stringify! for p in *@params], ' '}) ...)" -:Op, :Action, :FnDef +{ + :Op + :Action + :FnDef +} diff --git a/core/builtin.moon b/core/builtin.moon index 97f4457..71beac3 100644 --- a/core/builtin.moon +++ b/core/builtin.moon @@ -1,8 +1,8 @@ +-- builtin special forms import Action, FnDef from require 'core.base' -import Const from require 'core.const' +import ResultNode, Value, Const from require 'core.value' import Cell from require 'core.cell' import Scope from require 'core.scope' -import UpdateChildren from require 'core.invoke' class doc extends Action @doc: "(doc sym) - print documentation in console @@ -13,8 +13,9 @@ prints the docstring for sym in the console" assert #tail == 1, "'doc' takes exactly one parameter" def = L\push tail[1]\eval, scope - L\print "(doc #{tail[1]\stringify!}):\n#{def\getc!.doc}\n" - nil + with ResultNode children: { def } + def = def.value\const!\unwrap! + L\print "(doc #{tail[1]\stringify!}):\n#{def.doc}\n" class def extends Action @doc: "(def sym1 val-expr1 @@ -28,16 +29,15 @@ updates all val-exprs." assert #tail > 1, "'def' requires at least 2 arguments" assert #tail % 2 == 0, "'def' requires an even number of arguments" - values = L\push -> + children = L\push -> return for i=1,#tail,2 name, val_expr = tail[i], tail[i+1] - name = (name\quote scope)\getc 'sym' + name = (name\quote scope)\unwrap 'sym' - val = val_expr\eval scope - scope\set name, Const.wrap_ref val - val + with val_expr\eval scope + scope\set name, .value - UpdateChildren values + ResultNode :children class use extends Action @doc: "(use scope1 [scope2]...) - merge scopes into parent scope @@ -48,12 +48,11 @@ all scopes have to be eval-time constants." eval: (scope, tail) => L\trace "evaling #{@}" for child in *tail - value = L\push child\eval, scope - L\trace @, "merging #{value} into #{scope}" - assert value.type == 'scope', "'use' only works on scopes" - scope\use value\getc 'scope' + result = L\push child\eval, scope + value = result\value_only!\const! + scope\use value\unwrap 'scope', "'use' only works on scopes" - nil + ResultNode! class require_ extends Action @doc: "(require name-str) - require a module @@ -65,10 +64,11 @@ name-str has to be an eval-time constant." L\trace "evaling #{@}" assert #tail == 1, "'require' takes exactly one parameter" - name = L\push tail[1]\eval, scope + result = L\push tail[1]\eval, scope + name = result\value_only!\const! L\trace @, "loading module #{name}" - Const.wrap require "lib.#{name\getc 'str'}" + ResultNode value: Value.wrap require "lib.#{name\unwrap 'str'}" class import_ extends Action @doc: "(import sym1 [sym2]...) - require and define modules @@ -79,12 +79,11 @@ requires modules sym1, sym2, ... and defines them as sym1, sym2, ... in the curr L\trace "evaling #{@}" assert #tail > 0, "'import' requires at least one arguments" - for child in *tail - name = (child\quote scope)\getc 'sym' - scope\set name, Const.wrap require "lib.#{name}" + name = (child\quote scope)\unwrap 'sym' + scope\set name, Value.wrap require "lib.#{name}" - nil + ResultNode! class import_star extends Action @doc: "(import* sym1 [sym2]...) - require and use modules @@ -97,10 +96,10 @@ requires modules sym1, sym2, ... and merges them into the current scope" for child in *tail - name = (child\quote scope)\getc 'sym' - scope\use (Const.wrap require "lib.#{name}")\getc 'scope' + name = (child\quote scope)\unwrap 'sym' + scope\use (Value.wrap require "lib.#{name}")\unwrap 'scope' - nil + ResultNode! class fn extends Action @doc: "(fn (p1 [p2]...) body-expr) - declare a (lambda) function @@ -118,7 +117,7 @@ the symbols p1, p2, ... will resolve to the arguments passed to the function." param\quote scope body = body\quote scope - Const.wrap FnDef param_symbols, body, scope + ResultNode value: Value.wrap FnDef param_symbols, body, scope class defn extends Action @doc: "(defn name-sym (p1 [p2]...) body-expr) - define a function @@ -130,7 +129,7 @@ declares a lambda (see (doc fn)) and defines it in the current scope" assert #tail == 3, "'defn' takes exactly three arguments" { name, params, body } = tail - name = (name\quote scope)\getc 'sym' + name = (name\quote scope)\unwrap 'sym' assert params.__class == Cell, "'defn's second argument has to be an expression" param_symbols = for param in *params.children assert param.type == 'sym', "function parameter declaration has to be a symbol" @@ -139,9 +138,8 @@ declares a lambda (see (doc fn)) and defines it in the current scope" body = body\quote scope fn = FnDef param_symbols, body, scope - scope\set name, Const.wrap fn - - nil + scope\set name, Value.wrap fn + ResultNode! class do_expr extends Action @doc: "(do expr1 [expr2]...) - update multiple expressions @@ -150,7 +148,7 @@ evaluates and continously updates expr1, expr2, ... the last expression's value is returned." eval: (scope, tail) => - UpdateChildren [(expr\eval scope) or Const.empty! for expr in *tail] + ResultNode children: [expr\eval scope for expr in *tail] class if_ extends Action @doc: "(if bool then-expr [else-xpr]) - make an eval-time const choice @@ -166,7 +164,7 @@ to then-expr, otherwise it is equivalent to else-xpr if given, or nil otherwise. { xif, xthen, xelse } = tail xif = L\push xif\eval, scope - xif = xif\getc! + xif = xif\value_only!\const!\unwrap! if xif xthen\eval scope @@ -180,8 +178,8 @@ class trace extends Action L\trace "evaling #{@}" assert #tail == 1, "'trace' takes exactly one parameter" - with val = L\push tail[1]\eval, scope - L\print "trace:", val + with result = L\push tail[1]\eval, scope + L\print "trace #{tail[1]\stringify!}: #{result.value}" { :doc, :trace diff --git a/core/cell.moon b/core/cell.moon index 4aa847b..642e1a6 100644 --- a/core/cell.moon +++ b/core/cell.moon @@ -1,15 +1,19 @@ -import Const from require 'core.const' +-- ALV Cell type +import Const from require 'core.value' import op_invoke, fn_invoke from require 'core.invoke' import Tag from require 'core.tag' +-- ALV Cell type class Cell -- common - new: (@tag, @children, @white) => + -- tag: the parsed Tag + -- children: sequence of child AST Nodes + -- white: optional sequence of whitespace segments ([0 .. #@children]) + new: (@tag=Tag.blank!, @children, @white) => if not @white @white = ['' for i=1,#@children+1] - if not @tag - @tag = Tag.blank! + assert #@white == #@children, "mismatched whitespace length" head: => @children[1] tail: => [c for c in *@children[2,]] @@ -18,7 +22,8 @@ class Cell -- AST interface eval: (scope) => - head = @head!\eval scope + head_result = @head!\eval scope + head = head_result.value\const! Action = switch head.type when 'opdef' -- scope\get 'op-invoke' @@ -27,7 +32,7 @@ class Cell -- scope\get 'fn-invoke' fn_invoke when 'builtin' - head\getc! + head\unwrap! else print head for k,v in pairs head @@ -35,8 +40,7 @@ class Cell print head.__class.__name error "cannot evaluate expr with head #{head}" - action = Action\get_or_create head, @tag - action\eval scope, @tail! + Action\eval_cell scope, @tag, head, @tail! quote: (scope) => children = [child\quote scope for child in *@children] @@ -81,6 +85,9 @@ class Cell tag, children, white = parse_args ... @ tag, children, white +-- A parenthesis-less Cell (root of an ALV document) +-- +-- evaluates with an implicit 'do' in the head class RootCell extends Cell head: => Const.sym 'do' tail: => @children @@ -98,4 +105,7 @@ class RootCell extends Cell @parse: (...) => @__parent.parse @, (Tag\parse '0'), ... -:Cell, :RootCell +{ + :Cell + :RootCell +} diff --git a/core/const.moon b/core/const.moon deleted file mode 100644 index 99e4178..0000000 --- a/core/const.moon +++ /dev/null @@ -1,136 +0,0 @@ -import Op, Action, FnDef from require 'core.base' - -local Scope -load_ = -> - import Scope from require 'core.scope' - -ancestor = (klass) -> - assert klass, "cant find the ancestor of nil" - while klass.__parent - klass = klass.__parent - klass - -class Ref - new: (@original) => - - get: (...) => @original\get ... - getc: (...) => @original\get ... - - destroy: => - update: => - -class Const - types = { - sym: true - str: true - num: true - bool: true - scope: true - op: true - opdef: true - fndef: true - builtin: true - } - - new: (@type, @value, @raw) => - assert types[@type], "invalid Const type: #{@type}" - --- Value interface - get: (type) => - assert not type or type == @type, "#{@} is not a #{type}" - @value - - getc: (type) => - assert not type or type == @type, "#{@} is not a #{type}" - @value - - update: (dt) => - switch @type - when 'op' - @value\update dt - --- AST interface - eval: (scope) => - switch @type - when 'num', 'str' - @ - when 'sym' - assert (scope\get @value), "undefined reference to symbol '#{@value}'" - else - error "cannot evaluate #{@}" - - quote: => @ - - stringify: => @raw - - clone: (prefix) => @ - -- in case of doubt: - -- clone: (prefix) => Const @type, @value, @raw - --- static - __tostring: => - value = if @type == 'opdef' or @type == 'builtin' then @value.__name else @value - "<#{@type}: #{value}>" - - __eq: (other) => - other.type == @type and other.value == @value - - unescape = (str) -> str\gsub '\\([\'"\\])', '%1' - - @parse: (type, sep) => - switch type - when 'num' then (match) -> @ 'num', (tonumber match), match - when 'sym' then (match) -> @ 'sym', match, match - when 'str' then (match) -> @ 'str', (unescape match), sep .. match .. sep - - @num: (num) -> Const 'num', num, tostring num - @str: (str) -> Const 'str', str, "'#{str}'" - @sym: (sym) -> Const 'sym', sym, sym - @bool: (bool) -> Const 'bool', bool, tostring bool - @empty: -> Const 'str', '', "''" - - @wrap: (val, name='(unknown)') -> - typ = switch type val - when 'number' then 'num' - when 'string' then 'str' - when 'table' - if base = rawget val, '__base' - -- a class - switch ancestor val - when Op then 'opdef' - when Action then 'builtin' - else - error "#{name}: cannot wrap class '#{val.__name}'" - elseif val.__class - -- an instance - switch ancestor val.__class - when Op then 'op' - when Scope then 'scope' - when FnDef then 'fndef' - when Const - return val - else - error "#{name}: cannot wrap '#{val.__class.__name}' instance" - else - -- plain table - return Const 'scope', Scope.from_table val - else - error "#{name}: cannot wrap Lua type '#{type val}'" - - Const typ, val - - @wrap_ref: (val) -> - if base = rawget val, '__base' - -- a class - error "#{name}: cannot wrap_ref class '#{val.__name}'" - elseif val.__class - -- an instance - switch ancestor val.__class - when Op then Ref val - when Const then val - else - error "#{name}: cannot wrap_ref '#{val.__class.__name}' instance" - else - error "#{name}: cannot wrap_ref Lua type '#{type val}'" - -:Const, :load_ diff --git a/core/init.moon b/core/init.moon index 1d9e191..b885747 100644 --- a/core/init.moon +++ b/core/init.moon @@ -2,7 +2,7 @@ L or= setmetatable {}, __index: => -> import Op, Action, FnDef from require 'core.base' -import Const, load_ from require 'core.const' +import Stream, Const, load_ from require 'core.value' import Scope from require 'core.scope' load_! @@ -15,7 +15,8 @@ import cell, program from require 'core.parsing' globals = Scope.from_table require 'core.builtin' { - :Const, :Cell, :RootCell + :Stream, :Const + :Cell, :RootCell :Op, :Action, :FnDef :Scope @@ -28,5 +29,6 @@ globals = Scope.from_table require 'core.builtin' scope\use inject if inject ast = assert (cell\match str), "failed to parse: #{str}" - Const.wrap ast\eval scope + result = ast\eval scope + result\value_only! } diff --git a/core/invoke.moon b/core/invoke.moon index 5ec4a82..5a6c420 100644 --- a/core/invoke.moon +++ b/core/invoke.moon @@ -1,39 +1,23 @@ -import Const from require 'core.const' +import ResultNode, Value from require 'core.value' import Action from require 'core.base' import Scope from require 'core.scope' -class UpdateChildren - new: (@children) => - - update: (dt) => - for child in *@children - -- L\trace "updating #{child}" - L\push child\update, dt - - get: => @children[#@children]\get! - getc: => @children[#@children]\getc! - - __tostring: => '<forwarder>' - class op_invoke extends Action patch: (head) => return true if head == @head @op\destroy! if @op - @head = head - assert @head.type == 'opdef', "cant op-invoke #{@head}" - @op = @head\getc!! - + def = head\const!\unwrap 'opdef', "cant op-invoke #{@head}" + @head, @op = head, def! + true eval: (scope, tail) => - L\trace "evaling #{@}" - args = L\push -> [L\push expr\eval, scope for expr in *tail] + children = L\push -> [L\push expr\eval, scope for expr in *tail] + value = @op\setup unpack [child.value for child in *children] - -- Const 'op', with @op - with @op - \setup unpack args + ResultNode :children, :value, op: @op class fn_invoke extends Action -- @TODO: @@ -48,27 +32,23 @@ class fn_invoke extends Action true eval: (outer_scope, tail) => - assert @head.type == 'fndef', "cant fn-invoke #{@head}" - { :params, :body, :scope } = @head\getc! + { :params, :body, :scope } = @head\const!\unwrap 'fndef', "cant fn-invoke #{@head}" assert #params == #tail, "argument count mismatch in #{@head}" fn_scope = Scope @, scope - for i=1,#params - name = params[i]\getc! - argm = tail[i] - fn_scope\set name, L\push argm\eval, outer_scope + children = for i=1,#params + name = params[i]\unwrap 'sym' + with L\push tail[i]\eval, outer_scope + fn_scope\set name, .value body = body\clone @tag + result = body\eval fn_scope - body\eval fn_scope - -class do_expr extends Action - eval: (scope, tail) => - UpdateChildren [(expr\eval scope) or Const.empty! for expr in *tail] + table.insert children, result + ResultNode :children, value: result.value { :op_invoke, :fn_invoke - :UpdateChildren } diff --git a/core/parsing.moon b/core/parsing.moon index 58dbf62..96d8125 100644 --- a/core/parsing.moon +++ b/core/parsing.moon @@ -1,4 +1,4 @@ -import Const from require 'core.const' +import Const from require 'core.value' import Cell, RootCell from require 'core.cell' import Tag from require 'core.tag' import R, S, P, V, C, Ct from require 'lpeg' @@ -14,13 +14,14 @@ space = (wc^1 * (comment * wc^1)^0) / 1 -- required whitespace mspace = (comment + wc)^0 / 1 -- optional whitespace -- atoms -sym = ((R 'az', 'AZ') + (S '-_+*/.!?')) ^ 1 / Const\parse 'sym' +digit = R '09' +first = (R 'az', 'AZ') + S '-_+*/.!?=' +sym = first * (first + digit)^0 / Const\parse 'sym' strd = '"' * (C ((P '\\"') + (P '\\\\') + (1 - P '"'))^0) * '"' / Const\parse 'str', '\"' strq = "'" * (C ((P "\\'") + (P '\\\\') + (1 - P "'"))^0) * "'" / Const\parse 'str', '\'' str = strd + strq -digit = R '09' int = digit^1 float = (digit^1 * '.' * digit^0) + (digit^0 * '.' * digit^1) num = (float + int) / Const\parse 'num' @@ -43,7 +44,13 @@ cell = P { :expr, :explist, :cell } -program = root * -1 +parse_error = (root, rest) -> + if #rest > 0 + error "failed to parse, rest is:\n#{rest}" + + root + +program = root * (C (P 1)^0) * -1 / parse_error { :comment diff --git a/core/registry.moon b/core/registry.moon index 3fc6d55..4dd5bbb 100644 --- a/core/registry.moon +++ b/core/registry.moon @@ -41,8 +41,9 @@ class Registry -- (e.g. first [A] is solved, then [5.A] is solved) continue if tag\index! - L\trace "assigning new tag #{value} to #{tag} #{expr}" - tag\set @next_tag! + next_tag = @next_tag! + L\trace "assigned new tag #{next_tag} to #{tag} #{expr}" + tag\set next_tag @map[tag\index!] = expr assert @ == @@active_registry, "not the active registry!" diff --git a/core/scope.moon b/core/scope.moon index ed4d67d..aaa38f2 100644 --- a/core/scope.moon +++ b/core/scope.moon @@ -1,10 +1,10 @@ -import Const from require 'core.const' +import Value from require 'core.value' class Scope new: (@node, @parent) => @values = {} - set_raw: (key, val) => @values[key] = Const.wrap val, key + set_raw: (key, val) => @values[key] = Value.wrap val, key set: (key, val) => L\trace "setting #{key} = #{val} in #{@}" @values[key] = val @@ -22,7 +22,7 @@ class Scope scope = @get start assert scope and scope.type == 'scope', "cant find '#{prefix}#{start}' for '#{prefix}#{key}'" - scope\getc!\get rest, "#{prefix}#{start}/" + scope\unwrap!\get rest, "#{prefix}#{start}/" use: (other) => L\trace "using defs from #{other} in #{@}" @@ -31,7 +31,7 @@ class Scope from_table: (tbl) -> with Scope! - .values = { k, Const.wrap v, k for k,v in pairs tbl } + .values = { k, Value.wrap v, k for k,v in pairs tbl } __tostring: => buf = "<Scope" diff --git a/core/value.moon b/core/value.moon new file mode 100644 index 0000000..f3f9796 --- /dev/null +++ b/core/value.moon @@ -0,0 +1,157 @@ +-- ALV Value types +import Op, Action, FnDef from require 'core.base' + +local Scope +load_ = -> + import Scope from require 'core.scope' + +ancestor = (klass) -> + assert klass, "cant find the ancestor of nil" + while klass.__parent + klass = klass.__parent + klass + +-- Result of evaluating an expression +-- carries (all optional): +-- - a Value +-- - an Op (to update) +-- - children (results of subexpressions that were evaluated) +-- +-- ResultNodes form a tree that controls execution order and message passing +-- between Ops. +class ResultNode + -- params: table with optional keys op, value, children + new: (params={}) => + @op = params.op + @value = params.value + @children = params.children or {} + + -- unwrap value and assert that neither @op nor @children were set + value_only: (msg) => + assert not @op and #@children == 0, msg or "pure expression expected" + @value + + update: (dt) => + for child in *@children + child\update dt + @op\update dt if @op + + __tostring: => + buf = "<result=#{@value}" + buf ..= " #{@op}" if @op + buf ..= " (#{#@children} children)" if #@children > 0 + buf ..= ">" + buf + +local Const, Stream + +-- ALV Type wrapper +class Value + -- @type - type name. + -- builtin types: * literals: sym, num, bool + -- * scope, opdef, fndef, builtin + -- @value - Lua value - access through :unwrap() + new: (@type, @value) => + + -- asserts value-constness + -- returns self (for chaining) + const: => error 'not a constant' + + -- unwrap to the Lua type + -- asserts @type == type, msg if given + unwrap: (type, msg) => + assert type == @type, msg or "#{@} is not a #{type}" if type + @value + +-- static + __tostring: => + value = if 'table' == (type @value) and rawget @value, '__base' then @value.__name else @value + "<#{@@__name} #{@type}: #{value}>" + __eq: (other) => other.type == @type and other.value == @value + __inherited: (cls) => + cls.__base.__tostring = @__tostring + cls.__base.__eq = @__eq + + -- wrap a Lua type + @wrap: (val, name='(unknown)') -> + typ = switch type val + when 'number' then 'num' + when 'string' then 'str' + when 'table' + if base = rawget val, '__base' + -- a class + switch ancestor val + when Op then 'opdef' + when Action then 'builtin' + else + error "#{name}: cannot wrap class '#{val.__name}'" + elseif val.__class + -- an instance + switch ancestor val.__class + when Scope then 'scope' + when FnDef then 'fndef' + when Value + return val + else + error "#{name}: cannot wrap '#{val.__class.__name}' instance" + else + -- plain table + return Const 'scope', Scope.from_table val + else + error "#{name}: cannot wrap Lua type '#{type val}'" + + Const typ, val + +class Stream extends Value + new: (@type, @value=nil) => + + set: (@value) => + -- set dirty flag (?) + +class Const extends Value + new: (type, value, @raw) => + super type, value + +-- Value interface + const: => @ + +-- AST interface + eval: (scope) => + value = switch @type + when 'num', 'str' + @ + when 'sym' + assert (scope\get @value), "undefined reference to symbol '#{@value}'" + else + error "cannot evaluate #{@}" + + ResultNode :value + + quote: => @ + + stringify: => @raw + + clone: (prefix) => @ + -- in case of doubt: + -- clone: (prefix) => Const @type, @value, @raw + +-- static + unescape = (str) -> str\gsub '\\([\'"\\])', '%1' + + @parse: (type, sep) => + switch type + when 'num' then (match) -> @ 'num', (tonumber match), match + when 'sym' then (match) -> @ 'sym', match, match + when 'str' then (match) -> @ 'str', (unescape match), sep .. match .. sep + + @num: (num) -> Const 'num', num, tostring num + @str: (str) -> Const 'str', str, "'#{str}'" + @sym: (sym) -> Const 'sym', sym, sym + @bool: (bool) -> Const 'bool', bool, tostring bool + +{ + :ResultNode + :Value + :Stream, :Const + :load_ +} |
