aboutsummaryrefslogtreecommitdiffstats
path: root/core/value.moon
diff options
context:
space:
mode:
Diffstat (limited to 'core/value.moon')
-rw-r--r--core/value.moon157
1 files changed, 157 insertions, 0 deletions
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_
+}