aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-03-20 20:07:37 +0000
committers-ol <s-ol@users.noreply.github.com>2020-03-20 20:08:25 +0000
commit04eb8afc8367e51c15c507740b2c55fce2569b0d (patch)
tree01c5a53fbcd72d9a05009792126af5c54c8486ae /core
parentdocs/index: mention license + repo (diff)
downloadalive-04eb8afc8367e51c15c507740b2c55fce2569b0d.tar.gz
alive-04eb8afc8367e51c15c507740b2c55fce2569b0d.zip
language Error tracking
Close #3
Diffstat (limited to 'core')
-rw-r--r--core/base/init.moon4
-rw-r--r--core/base/match.moon7
-rw-r--r--core/error.moon85
-rw-r--r--core/init.moon4
-rw-r--r--core/invoke.moon7
-rw-r--r--core/value.moon3
-rw-r--r--core/version.moon4
7 files changed, 103 insertions, 11 deletions
diff --git a/core/base/init.moon b/core/base/init.moon
index 64b34f4..bb35140 100644
--- a/core/base/init.moon
+++ b/core/base/init.moon
@@ -12,6 +12,7 @@
-- @see match
-- @see Value
-- @see Result
+-- @see Error
import IO from require 'core.base.io'
import Op from require 'core.base.op'
@@ -21,6 +22,7 @@ import Input from require 'core.base.input'
import match from require 'core.base.match'
import Value from require 'core.value'
import Result from require 'core.result'
+import Error from require 'core.error'
{
:IO
@@ -31,5 +33,5 @@ import Result from require 'core.result'
:match
-- redundant exports, to keep anything an extension might need in one import
- :Value, :Result
+ :Value, :Result, :Error
}
diff --git a/core/base/match.moon b/core/base/match.moon
index a20bcdc..cb82ac4 100644
--- a/core/base/match.moon
+++ b/core/base/match.moon
@@ -2,6 +2,7 @@
-- Utilities for matching `Result` types.
--
-- @module match
+import Error from require 'core.error'
unpack or= table.unpack
class Pattern
@@ -39,11 +40,11 @@ class Pattern
matched = while @matches results[1]
table.remove results, 1
- assert @opt or #matched > 0, "expected at least one argument for spread"
+ assert @opt or #matched > 0, Error 'argument', "expected at least one argument for spread"
matched
else
matches = @matches results[1]
- assert @opt or matches, "couldn't match argument #{results[1]} as #{@}"
+ assert @opt or matches, Error 'argument', "argument #{results[1].value} incompatible with expected type #{@}"
if matches then table.remove results, 1
__tostring: =>
@@ -84,7 +85,7 @@ match = (pattern, inputs) ->
pattern = rest
Pattern pat
values = [p\match inputs for p in *patterns]
- assert #inputs == 0, "#{#inputs} extra arguments given!"
+ assert #inputs == 0, Error 'argument', "#{#inputs} extra arguments given!"
values
{
diff --git a/core/error.moon b/core/error.moon
new file mode 100644
index 0000000..a06c359
--- /dev/null
+++ b/core/error.moon
@@ -0,0 +1,85 @@
+----
+-- Language error and traceback.
+--
+-- @classmod Error
+class Error
+--- members
+-- @section members
+
+ --- append a traceback frame.
+ --
+ -- `where` should denote where the Error occured and fit grammatically to
+ -- complete the sentence `"{error} occured while {where}"`
+ --
+ -- @tparam string where
+ add_frame: (where) => @trace ..= "\n while #{where}"
+
+ __tostring: => "#{@kind} error: #{@message}#{@detail}#{@trace}"
+
+--- static functions
+-- @section static
+
+ --- create a new Error.
+ --
+ -- `kind` should be one of:
+ --
+ -- - `'reference'`: error concerning symbol resolution
+ -- - `'argument'`: error concerning Op argument matching
+ -- - `'implementation'`: error in the Lua/MoonScript implementation of alive.
+ -- Should not occur in normal operation, and constitutes a bug.
+ --
+ -- @classmethod
+ -- @tparam string kind
+ -- @tparam string message
+ -- @tparam ?string detail
+ new: (@kind, @message, @detail) =>
+ @trace = ""
+
+ handler = (err) ->
+ if err.__class == Error
+ err
+ else
+ Error 'implementation', err, debug.traceback 'Lua error below:', 2
+ --- Wrap function errors in a traceback frame.
+ --
+ -- Execute `fn(...)`, and turn any error thrown as a result into an
+ -- `Error` instance, before re-throwing it.
+ --
+ -- When `Error` instances are caught, `frame` is added to the traceback.
+ -- All other error values are turned into `'implementation'` Errors.
+ --
+ -- @tparam string frame
+ -- @tparam function fn
+ @wrap: (frame, fn, ...) ->
+ results = { xpcall fn, handler, ... }
+ ok = table.remove results, 1
+ if ok
+ unpack results
+ else
+ error with results[1]
+ \add_frame frame
+
+ --- Capture and wrap function errors in traceback frame.
+ --
+ -- Execute `fn(...)`, and turn any error thrown as a result into an
+ -- `Error` instance, before re-throwing it.
+ --
+ -- When `Error` instances are caught, `frame` is added to the traceback.
+ -- All other error values are turned into `'implementation'` Errors.
+ --
+ -- @tparam string frame
+ -- @tparam function fn
+ -- @treturn boolean `ok` true if exeuction suceeded without errors
+ -- @treturn Error|any `error_or_results` the `Error` instance or results
+ @try: (frame, fn, ...) ->
+ results = { xpcall fn, handler, ... }
+ ok = table.remove results, 1
+ if ok
+ ok, unpack results
+ else
+ ok, with results[1]
+ \add_frame frame
+
+{
+ :Error
+}
diff --git a/core/init.moon b/core/init.moon
index a5e892d..00e3cd4 100644
--- a/core/init.moon
+++ b/core/init.moon
@@ -17,6 +17,7 @@ L or= setmetatable {}, __index: => ->
import Value from require 'core.value'
import Result from require 'core.result'
import Scope from require 'core.scope'
+import Error from require 'core.error'
import Registry, SimpleRegistry from require 'core.registry'
import Tag from require 'core.tag'
@@ -35,6 +36,7 @@ globals = Scope.from_table require 'core.builtin'
-- @tfield Cell Cell
-- @tfield RootCell RootCell
-- @tfield Scope Scope
+-- @tfield Error Error
-- @tfield Registry Registry
-- @tfield Tag Tag
-- @tfield Scope globals global definitons
@@ -42,7 +44,7 @@ globals = Scope.from_table require 'core.builtin'
{
:Value, :Result
:Cell, :RootCell
- :Scope
+ :Scope, :Error
:Registry, :SimpleRegistry, :Tag
diff --git a/core/invoke.moon b/core/invoke.moon
index 736f284..97d3949 100644
--- a/core/invoke.moon
+++ b/core/invoke.moon
@@ -6,6 +6,7 @@ import Value from require 'core.value'
import Result from require 'core.result'
import Action from require 'core.base'
import Scope from require 'core.scope'
+import Error from require 'core.error'
--- `Action` implementation that invokes an `Op`.
--
@@ -40,7 +41,7 @@ class op_invoke extends Action
-- @treturn Result
eval: (scope, tail) =>
children = [L\push expr\eval, scope for expr in *tail]
- @op\setup [result for result in *children], scope
+ Error.wrap "invoking #{@op}#{@tag}", @op\setup, [result for result in *children], scope
any_dirty = false
for input in @op\all_inputs!
@@ -91,8 +92,8 @@ class fn_invoke extends Action
with L\push tail[i]\eval, outer_scope
fn_scope\set name, \make_ref!
- body = body\clone @tag
- result = body\eval fn_scope
+ clone = body\clone @tag
+ result = Error.wrap "invoking function #{body.tag} at #{@tag}", clone\eval, fn_scope
table.insert children, result
Result :children, value: result.value
diff --git a/core/value.moon b/core/value.moon
index bda6127..7f5a93d 100644
--- a/core/value.moon
+++ b/core/value.moon
@@ -3,6 +3,7 @@
--
-- @classmod Value
import Result from require 'core.result'
+import Error from require 'core.error'
import scope, base, registry from require 'core.cycle'
ancestor = (klass) ->
@@ -107,7 +108,7 @@ class Value
when 'num', 'str'
Result value: @
when 'sym'
- assert (scope\get @value), "undefined reference to symbol '#{@value}'"
+ assert (scope\get @value), Error 'reference', "undefined symbol '#{@value}'"
else
error "cannot evaluate #{@}"
diff --git a/core/version.moon b/core/version.moon
index e5a965c..af97600 100644
--- a/core/version.moon
+++ b/core/version.moon
@@ -12,8 +12,8 @@
-- @tfield string web the repo web URL
{
tag: "v0.0"
- rev_short: "23f893a"
- rev_long: "23f893a1303b35e11d7103d892c40b7e8d209a06"
+ rev_short: "662def4"
+ rev_long: "662def4ef082412147ae8126e80065d245f4b426"
repo: "https://github.com/s-ol/alivecoding.git"
web: "https://github.com/s-ol/alivecoding/tree/v0.0"
}