aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-03-21 19:06:18 +0000
committers-ol <s-ol@users.noreply.github.com>2020-03-21 19:06:18 +0000
commite83df1af2cdad8c2d61ba790a96875cd260eceaf (patch)
tree5766654329675bd5259be772bc2537c7fdd8ab1c /core
parentdocs/guide: document supported interpreter versions (diff)
downloadalive-e83df1af2cdad8c2d61ba790a96875cd260eceaf.tar.gz
alive-e83df1af2cdad8c2d61ba790a96875cd260eceaf.zip
new meta/doc system
Diffstat (limited to 'core')
-rw-r--r--core/base/action.moon33
-rw-r--r--core/builtin.moon487
-rw-r--r--core/cell.moon2
-rw-r--r--core/init.moon5
-rw-r--r--core/invoke.moon28
-rw-r--r--core/result.moon2
-rw-r--r--core/value.moon43
7 files changed, 358 insertions, 242 deletions
diff --git a/core/base/action.moon b/core/base/action.moon
index cfca919..7ada4ba 100644
--- a/core/base/action.moon
+++ b/core/base/action.moon
@@ -15,9 +15,11 @@ class Action
--- create a new instance.
--
+ -- @tparam Cell cell the Cell to evaluate
-- @tparam Value head the (`AST:eval`d) `head` of the Cell to evaluate
- -- @tparam Tag tag the Tag of the expression to evaluate
- new: (@head, @tag) =>
+ new: (@cell, @head) =>
+ @tag = @cell.tag
+ @tag\replace @
--- perform the actual evaluation.
--
@@ -43,12 +45,13 @@ class Action
-- @tparam ?Action prev the previous Action instance
setup: (prev) =>
- --- the head of the `Cell` this Action was created for.
- --
+ --- the `Cell` this Action was created for.
+ -- @tfield Cell cell
+
+ --- the evaluated head of `cell`.
-- @tfield AST head
- --- the identity of the `Cell` this Action was created for.
- --
+ --- the identity of `cell`.
-- @tfield Tag tag
--- static functions
@@ -61,31 +64,29 @@ class Action
-- it pass it to `setup`. Register the `Action` with `tag`, evaluate it
-- and return the `Result`.
--
+ -- @tparam Cell cell the `Cell` being evaluated
-- @tparam Scope scope the active scope
- -- @tparam Tag tag the tag of the `Cell` being evaluated
-- @tparam Value head the (`AST:eval`d) head of the `Cell` being evaluated
- -- @tparam {AST,...} tail the raw AST parameters to the `Cell` being evaluated
-- @treturn Result the result of evaluation
- @eval_cell: (scope, tag, head, tail) =>
- last = tag\last!
+ @eval_cell: (cell, scope, head) =>
+ last = cell.tag\last!
compatible = last and (last.__class == @) and last.head == head
L\trace if compatible
- "reusing #{last} for #{tag} <#{@__name} #{head}>"
+ "reusing #{last} for #{cell.tag} <#{@__name} #{head}>"
else if last
- "replacing #{last} with new #{tag} <#{@__name} #{head}>"
+ "replacing #{last} with new #{cell.tag} <#{@__name} #{head}>"
else
- "initializing #{tag} <#{@__name} #{head}>"
+ "initializing #{cell.tag} <#{@__name} #{head}>"
- action = @ head, tag
+ action = @ cell, head
if compatible
action\setup last
else
last\destroy! if last
action\setup nil
- tag\replace action
- action\eval scope, tail
+ action\eval scope, cell\tail!
__tostring: => "<#{@@__name} #{@head}>"
__inherited: (cls) => cls.__base.__tostring = @__tostring
diff --git a/core/builtin.moon b/core/builtin.moon
index 49de80f..bd3183f 100644
--- a/core/builtin.moon
+++ b/core/builtin.moon
@@ -6,216 +6,282 @@
--
-- @module builtin
import Action, Op, FnDef, Input, match from require 'core.base'
-import Value from require 'core.value'
+import Value, LiteralValue from require 'core.value'
import Result from require 'core.result'
import Cell from require 'core.cell'
import Scope from require 'core.scope'
import Tag from require 'core.tag'
import op_invoke from require 'core.invoke'
-class doc extends Action
- @doc: "(doc sym) - print documentation in console
-
-prints the docstring for sym in the console"
-
- eval: (scope, tail) =>
- assert #tail == 1, "'doc' takes exactly one parameter"
-
- result = L\push tail[1]\eval, scope
- with Result children: { def }
- value = result\const!
- L\print "(doc #{tail[1]}):\n#{value.doc}\n"
-
-class def extends Action
- @doc: "(def sym1 val-expr1
- [sym2 val-expr2]...) - declare symbols in parent scope
-
-defines the symbols sym1, sym2, ... to resolve to the values of val-expr1, val-expr2, ...
-updates all val-exprs."
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail > 1, "'def' requires at least 2 arguments"
- assert #tail % 2 == 0, "'def' requires an even number of arguments"
-
- children = L\push ->
- return for i=1,#tail,2
- name, val_expr = tail[i], tail[i+1]
- name = (name\quote scope)\unwrap 'sym'
-
- with val_expr\eval scope
- scope\set name, \make_ref!
-
- Result :children
-
-class use extends Action
- @doc: "(use scope1 [scope2]...) - merge scopes into parent scope
-
-adds all symbols from scope1, scope2, ... to the parent scope.
-all scopes have to be eval-time constants."
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- for child in *tail
- result = L\push child\eval, scope
- value = result\const!
- scope\use value\unwrap 'scope', "'use' only works on scopes"
-
- Result!
-
-class require_ extends Action
- @doc: "(require name-str) - require a module
-
-returns the module's scope
-name-str has to be an eval-time constant."
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail == 1, "'require' takes exactly one parameter"
-
- result = L\push tail[1]\eval, scope
- name = result\const!
-
- L\trace @, "loading module #{name}"
- scope = Value.wrap require "lib.#{name\unwrap 'str'}"
- Result :value
-
-class import_ extends Action
- @doc: "(import sym1 [sym2]...) - require and define modules
-
-requires modules sym1, sym2, ... and defines them as sym1, sym2, ... in the current scope"
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail > 0, "'import' requires at least one arguments"
-
- for child in *tail
- name = (child\quote scope)\unwrap 'sym'
- value = Value.wrap require "lib.#{name}"
- scope\set name, Result :value -- (require "lib.#{name})\unwrap 'scope'
- Result!
-
-class import_star extends Action
- @doc: "(import* sym1 [sym2]...) - require and use modules
-
-requires modules sym1, sym2, ... and merges them into the current scope"
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail > 0, "'import' requires at least one arguments"
-
-
- for child in *tail
- name = (child\quote scope)\unwrap 'sym'
- value = Value.wrap require "lib.#{name}"
- scope\use value\unwrap 'scope' -- (require "lib.#{name}")\unwrap 'scope'
-
- Result!
-
-class fn extends Action
- @doc: "(fn (p1 [p2]...) body-expr) - declare a (lambda) function
-
-the symbols p1, p2, ... will resolve to the arguments passed to the function."
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail == 2, "'fn' takes exactly two arguments"
- { params, body } = tail
-
- assert params.__class == Cell, "'fn's first 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"
- param\quote scope
-
- body = body\quote scope
- Result value: Value.wrap FnDef param_symbols, body, scope
-
-class defn extends Action
- @doc: "(defn name-sym (p1 [p2]...) body-expr) - define a function
-
-declares a lambda (see (doc fn)) and defines it in the current scope"
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail == 3, "'defn' takes exactly three arguments"
- { name, params, body } = tail
-
- 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"
- param\quote scope
-
- body = body\quote scope
- fn = FnDef param_symbols, body, scope
-
- scope\set name, Result value: Value.wrap fn
- Result!
-
-class do_expr extends Action
- @doc: "(do expr1 [expr2]...) - update multiple expressions
-
-evaluates and continously updates expr1, expr2, ...
-the last expression's value is returned."
-
- eval: (scope, tail) =>
- scope = Scope scope
- Result 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
-
-bool has to be an eval-time constant. If it is truthy, this expression is equivalent
-to then-expr, otherwise it is equivalent to else-xpr if given, or nil otherwise."
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail >= 2, "'if' needs at least two parameters"
- assert #tail <= 3, "'if' needs at most three parameters"
-
- { xif, xthen, xelse } = tail
-
- xif = L\push xif\eval, scope
- xif = xif\const!\unwrap!
-
- if xif
- xthen\eval scope
- elseif xelse
- xelse\eval scope
-
-class trace_ extends Action
- @doc: "(trace! expr) - print an eval-time constant to the console"
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail == 1, "'trace!' takes exactly one parameter"
-
- with result = L\push tail[1]\eval, scope
- L\print "trace! #{tail[1]\stringify!}: #{result.value}"
-
-class trace extends Action
- @doc: "(trace expr) - print values to the console
-
-prints expr's value whenever it changes."
-
- class traceOp extends Op
- setup: (inputs) =>
- { prefix, value } = match 'str any', inputs
- super
- prefix: Input.cold prefix
- value: Input.value value
-
- tick: =>
- L\print "trace #{@inputs.prefix!}: #{@inputs.value.stream}"
-
- eval: (scope, tail) =>
- L\trace "evaling #{@}"
- assert #tail == 1, "'trace!' takes exactly one parameter"
-
- op = Value 'opdef', traceOp
- tag = @tag\clone Tag.parse '-1'
- prefix = Value.str tostring tail[1]
- op_invoke\eval_cell scope, tag, op, { prefix, tail[1] }
+doc = Value.meta
+ meta:
+ name: 'doc'
+ summary: "Print documentation in console."
+ examples: { '(doc sym)' }
+ description: "Print the documentation for `sym` to the console"
+
+ value: class extends Action
+ format_meta = =>
+ str = @summary
+ if @examples
+ for example in *@examples
+ str ..= '\n' .. example
+ if @description
+ str ..= '\n' .. @description\match '^\n*(.+)\n*$'
+ str
+
+ eval: (scope, tail) =>
+ assert #tail == 1, "'doc' takes exactly one parameter"
+
+ result = L\push tail[1]\eval, scope
+ with Result children: { def }
+ meta = result.value.meta
+ L\print "(doc #{tail[1]}):\n#{format_meta meta}\n"
+
+def = Value.meta
+ meta:
+ name: 'def'
+ summary: "Declare symbols in current scope."
+ examples: { '(def sym1 val-expr1 [sym2 val-expr2…])' }
+ description: "
+Define the symbols `sym1`, `sym2`, … to resolve to the values of `val-expr1`,
+`val-expr2`, …."
+
+ value: class extends Action
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ assert #tail > 1, "'def' requires at least 2 arguments"
+ assert #tail % 2 == 0, "'def' requires an even number of arguments"
+
+ children = L\push ->
+ return for i=1,#tail,2
+ name, val_expr = tail[i], tail[i+1]
+ name = (name\quote scope)\unwrap 'sym'
+
+ with val_expr\eval scope
+ scope\set name, \make_ref!
+
+ Result :children
+
+use = Value.meta
+ meta:
+ name: 'use'
+ summary: "Merge scopes into current scope."
+ examples: { '(use scope1 [scope2…])' }
+ description: "
+Copy all symbol definitions from `scope1`, `scope2`, … to the current scope.
+All arguments have to be evaltime constant."
+
+ value: class extends Action
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ for child in *tail
+ result = L\push child\eval, scope
+ value = result\const!
+ scope\use value\unwrap 'scope', "'use' only works on scopes"
+
+ Result!
+
+require_ = Value.meta
+ meta:
+ name: 'require'
+ summary: "Load a module."
+ examples: { '(require name)' }
+ description: "Load a module and return its scope."
+
+ value: class extends Action
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ assert #tail == 1, "'require' takes exactly one parameter"
+
+ result = L\push tail[1]\eval, scope
+ name = result\const!
+
+ L\trace @, "loading module #{name}"
+ scope = Value.wrap require "lib.#{name\unwrap 'str'}"
+ Result :value
+
+import_ = Value.meta
+ meta:
+ name: 'import'
+ summary: "Require and define modules."
+ examples: { '(import sym1 [sym2…])' }
+ description: "
+Requires modules `sym1`, `sym2`, … and define them as `sym1`, `sym2`, … in the
+current scope."
+
+ value: class extends Action
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ assert #tail > 0, "'import' requires at least one arguments"
+
+ for child in *tail
+ name = (child\quote scope)\unwrap 'sym'
+ value = Value.wrap require "lib.#{name}"
+ scope\set name, Result :value -- (require "lib.#{name})\unwrap 'scope'
+ Result!
+
+import_star = Value.meta
+ meta:
+ name: 'import*'
+ summary: "Require and use modules."
+ examples: { '(import* sym1 [sym2…])' }
+ description: "
+Requires modules `sym1`, `sym2`, … and merges them into the current scope."
+
+ value: class extends Action
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ assert #tail > 0, "'import' requires at least one arguments"
+
+
+ for child in *tail
+ name = (child\quote scope)\unwrap 'sym'
+ value = Value.wrap require "lib.#{name}"
+ scope\use value\unwrap 'scope' -- (require "lib.#{name}")\unwrap 'scope'
+
+ Result!
+
+fn = Value.meta
+ meta:
+ name: 'fn'
+ summary: "Declare a function."
+ examples: { '(fn (p1 [p2…]) body-expr)' }
+ description: "
+The symbols `p1`, `p2`, ... will resolve to the arguments passed when the
+function is invoked."
+
+ value: class extends Action
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ assert #tail == 2, "'fn' takes exactly two arguments"
+ { params, body } = tail
+
+ assert params.__class == Cell, "'fn's first 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"
+ param\quote scope
+
+ body = body\quote scope
+ Result value: with Value.wrap FnDef param_symbols, body, scope
+ .meta = {
+ summary: "(user defined function)"
+ examples: { "(??? #{table.concat [p! for p in *param_symbols], ' '})" }
+ }
+
+defn = Value.meta
+ meta:
+ name: 'defn'
+ summary: "Define a function."
+ examples: { '(defn name-sym (p1 [p2…]) body-expr)' }
+ description: "
+Declare a function and define it as `name-sym` in the current scope.
+The symbols `p1`, `p2`, ... will resolve to the arguments passed when the
+function is invoked."
+
+ value: class extends Action
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ assert #tail == 3, "'defn' takes exactly three arguments"
+ { name, params, body } = tail
+
+ 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"
+ param\quote scope
+
+ body = body\quote scope
+
+ value = with Value.wrap FnDef param_symbols, body, scope
+ .meta =
+ :name
+ summary: "(user defined function)"
+ examples: { "(#{name} #{table.concat [p! for p in *param_symbols], ' '})" }
+
+ scope\set name, Result :value
+ Result!
+
+do_expr = Value.meta
+ meta:
+ name: 'do_expr'
+ summary: "Evaluate multiple expressions in a new scope."
+ examples: { '(do expr1 [expr2…])' }
+ description: "
+Evaluate `expr1`, `expr2`, … and return the value of the last expression."
+
+ value: class extends Action
+ eval: (scope, tail) =>
+ scope = Scope scope
+ Result children: [expr\eval scope for expr in *tail]
+
+if_ = Value.meta
+ meta:
+ name: 'if'
+ summary: "Make an evaltime const choice."
+ examples: { '(if bool then-expr [else-expr])' }
+ description: "
+`bool` has to be an evaltime constant. If it is truthy, this expression is equivalent
+to `then-expr`, otherwise it is equivalent to `else-xpr` if given, or nil otherwise."
+
+ value: class extends Action
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ assert #tail >= 2, "'if' needs at least two parameters"
+ assert #tail <= 3, "'if' needs at most three parameters"
+
+ { xif, xthen, xelse } = tail
+
+ xif = L\push xif\eval, scope
+ xif = xif\const!\unwrap!
+
+ if xif
+ xthen\eval scope
+ elseif xelse
+ xelse\eval scope
+
+trace_ = Value.meta
+ meta:
+ name: 'trace!'
+ summary: "Trace an expression's value at evaltime."
+ examples: { '(trace! expr)' }
+
+ value: class extends Action
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ assert #tail == 1, "'trace!' takes exactly one parameter"
+
+ with result = L\push tail[1]\eval, scope
+ L\print "trace! #{tail[1]\stringify!}: #{result.value}"
+
+trace = Value.meta
+ meta:
+ name: 'trace'
+ summary: "Trace an expression's values at runtime."
+ examples: { '(trace expr)' }
+
+ value: class extends Action
+ class traceOp extends Op
+ setup: (inputs) =>
+ { prefix, value } = match 'str any', inputs
+ super
+ prefix: Input.cold prefix
+ value: Input.value value
+
+ tick: =>
+ L\print "trace #{@inputs.prefix!}: #{@inputs.value.stream}"
+
+ eval: (scope, tail) =>
+ L\trace "evaling #{@}"
+ assert #tail == 1, "'trace!' takes exactly one parameter"
+
+ tag = @tag\clone Tag.parse '-1'
+ inner = Cell tag, {
+ LiteralValue 'opdef', traceOp, 'trace'
+ Value.str tostring tail[1]
+ tail[1]
+ }
+ inner\eval scope
{
:doc
@@ -226,8 +292,17 @@ prints expr's value whenever it changes."
import: import_
'import*': import_star
- true: Value.bool true
- false: Value.bool false
+ true: Value.meta
+ meta:
+ name: 'true'
+ summary: "The boolean constant `true`."
+ value: Value.bool true
+
+ false: Value.meta
+ meta:
+ name: 'false'
+ summary: "The boolean constant `false`."
+ value: Value.bool false
:fn, :defn
'do': do_expr
diff --git a/core/cell.moon b/core/cell.moon
index 2109ade..b7f4a1d 100644
--- a/core/cell.moon
+++ b/core/cell.moon
@@ -83,7 +83,7 @@ class Cell
else
error "cannot evaluate expr with head #{head}"
- Action\eval_cell scope, @tag, head, @tail!
+ Action\eval_cell @, scope, head
--- quote this Cell, preserving its identity.
--
diff --git a/core/init.moon b/core/init.moon
index 00e3cd4..1aa0d2d 100644
--- a/core/init.moon
+++ b/core/init.moon
@@ -49,7 +49,10 @@ globals = Scope.from_table require 'core.builtin'
:Registry, :SimpleRegistry, :Tag
:globals
- parse: program\match
+
+ parse: (str) ->
+ assert (program\match str), Error 'syntax', "failed to parse"
+
eval: (str, inject) ->
scope = Scope nil, globals
scope\use inject if inject
diff --git a/core/invoke.moon b/core/invoke.moon
index 97d3949..654e436 100644
--- a/core/invoke.moon
+++ b/core/invoke.moon
@@ -8,6 +8,20 @@ import Action from require 'core.base'
import Scope from require 'core.scope'
import Error from require 'core.error'
+get_name = (value, raw) ->
+ meta = if value.meta then value.meta.name
+ locl = if raw and raw.type == 'sym' then raw!
+
+ if locl
+ if meta and meta != locl
+ "'#{meta}' (local '#{locl}')"
+ else
+ "'#{locl}'"
+ else if meta
+ "'#{meta}'"
+ else
+ "(unnamed)"
+
--- `Action` implementation that invokes an `Op`.
--
-- @type op_invoke
@@ -41,7 +55,9 @@ class op_invoke extends Action
-- @treturn Result
eval: (scope, tail) =>
children = [L\push expr\eval, scope for expr in *tail]
- Error.wrap "invoking #{@op}#{@tag}", @op\setup, [result for result in *children], scope
+
+ frame = "invoking op #{get_name @head, @cell\head!} at [#{@tag}]"
+ Error.wrap frame, @op\setup, [result for result in *children], scope
any_dirty = false
for input in @op\all_inputs!
@@ -81,9 +97,13 @@ class fn_invoke extends Action
-- @tparam {AST,...} tail the arguments to this expression
-- @treturn Result the result of this evaluation
eval: (outer_scope, tail) =>
- { :params, :body, :scope } = @head\unwrap 'fndef', "cant fn-invoke #{@head}"
+ name = get_name @head, @cell\head!
+ frame = "invoking function #{name} at [#{@tag}]"
- assert #params == #tail, "argument count mismatch in #{@head}"
+ { :params, :body, :scope } = @head\unwrap 'fndef', "cant fn-invoke #{@head}"
+ if #params != #tail
+ error with Error 'argument', "expected #{#params} arguments, found #{#tail}"
+ \add_frame frame
fn_scope = Scope scope, outer_scope
@@ -93,7 +113,7 @@ class fn_invoke extends Action
fn_scope\set name, \make_ref!
clone = body\clone @tag
- result = Error.wrap "invoking function #{body.tag} at #{@tag}", clone\eval, fn_scope
+ result = Error.wrap frame, clone\eval, fn_scope
table.insert children, result
Result :children, value: result.value
diff --git a/core/result.moon b/core/result.moon
index 357a868..52203da 100644
--- a/core/result.moon
+++ b/core/result.moon
@@ -61,9 +61,7 @@ class Result
for stream in @op\all_inputs!
if stream\dirty!
self_dirty = true
- break
- -- L\trace "#{@op} is #{if self_dirty then 'dirty' else 'clean'}"
return unless self_dirty
@op\tick!
diff --git a/core/value.moon b/core/value.moon
index 7f5a93d..da7f6d0 100644
--- a/core/value.moon
+++ b/core/value.moon
@@ -72,23 +72,22 @@ class Value
-- - `fndef` - `value` is a `FnDef` instance
-- - `scope` - `value` is a `Scope` instance
--
- -- @tfield string type the type name
+ -- @tfield string type
--- the wrapped Lua value.
+ -- @tfield any value
+
+ --- documentation metadata.
--
- -- the following builtin typenames are used:
+ -- an optional table containing metadata for error messages and
+ -- documentation. The following keys are recognized:
--
- -- - `str` - strings, `value` is a Lua string
- -- - `sym` - symbols, `value` is a Lua string
- -- - `num` - numbers, `value` is a Lua number
- -- - `bool` - booleans, `value` is a Lua boolean
- -- - `bang` - trigger signals, `value` is a Lua boolean
- -- - `opdef` - `value` is an `Op` subclass
- -- - `builtin` - `value` is an `Action` subclass
- -- - `fndef` - `value` is a `FnDef` instance
- -- - `scope` - `value` is a `Scope` instance
+ -- - `name`: optional name
+ -- - `summary`: single-line description (markdown)
+ -- - `examples`: optional list of single-line code examples
+ -- - `description`: optional full-text description (markdown)
--
- -- @tfield any value the wrapped value
+ -- @tfield ?table meta
--- AST interface
--
@@ -139,6 +138,7 @@ class Value
-- @tparam any value the Lua value to be accessed through `unwrap`
-- @tparam string raw the raw string that resulted in this value. Used by `parsing`.
new: (@type, @value, @raw) =>
+ @meta = {}
unescape = (str) -> str\gsub '\\([\'"\\])', '%1'
--- create a capture-function (for parsing with Lpeg).
@@ -157,6 +157,7 @@ class Value
--
-- @tparam any val the value to wrap
-- @tparam[opt] string name the name of this value (for error logging)
+ -- @treturn Value
@wrap: (val, name='(unknown)') ->
typ = switch type val
when 'number' then 'num'
@@ -188,21 +189,39 @@ class Value
--- create a constant number.
-- @tparam number num the number
+ -- @treturn Value
@num: (num) -> Value 'num', num, tostring num
--- create a constant string.
-- @tparam string str the string
+ -- @treturn Value
@str: (str) -> Value 'str', str, "'#{str}'"
--- create a constant symbol.
-- @tparam string sym the symbol
+ -- @treturn Value
@sym: (sym) -> Value 'sym', sym, sym
--- create a constant boolean.
-- @tparam boolean bool the boolean
+ -- @treturn Value
@bool: (bool) -> Value 'bool', bool, tostring bool
+ --- wrap and document a value.
+ --
+ -- wraps `args.value` using `wrap`, then assigns `meta`.
+ --
+ -- @tparam table args table with keys `value` and `meta`
+ -- @treturn Value
+ @meta: (args) ->
+ with Value.wrap args.value
+ .meta = args.meta if args.meta
+
+class LiteralValue extends Value
+ eval: => Result value: @
+
{
:Value
+ :LiteralValue
:load_
}