aboutsummaryrefslogtreecommitdiffstats
path: root/core/const.moon
diff options
context:
space:
mode:
Diffstat (limited to 'core/const.moon')
-rw-r--r--core/const.moon106
1 files changed, 106 insertions, 0 deletions
diff --git a/core/const.moon b/core/const.moon
new file mode 100644
index 0000000..564ab53
--- /dev/null
+++ b/core/const.moon
@@ -0,0 +1,106 @@
+import Op, Action 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 Const
+ types = {
+ sym: true
+ str: true
+ num: 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
+
+-- 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
+ @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 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
+
+:Const, :load_