diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-02-28 12:21:57 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-02-28 21:01:19 +0000 |
| commit | df8141c3214a5fb8d447297be64bdf5619b7d8a7 (patch) | |
| tree | f401303d36724c1055e25e0aaef9e0a27107c8a1 | |
| parent | lots of fixes (diff) | |
| download | alive-df8141c3214a5fb8d447297be64bdf5619b7d8a7.tar.gz alive-df8141c3214a5fb8d447297be64bdf5619b7d8a7.zip | |
doc and tag spec
| -rw-r--r-- | core/cell.moon | 42 | ||||
| -rw-r--r-- | core/parsing.moon | 8 | ||||
| -rw-r--r-- | core/registry.moon | 3 | ||||
| -rw-r--r-- | core/tag.moon | 36 | ||||
| -rw-r--r-- | spec/core/cell_spec.moon (renamed from spec/cell_spec.moon) | 0 | ||||
| -rw-r--r-- | spec/core/parsing_spec.moon (renamed from spec/parsing_spec.moon) | 0 | ||||
| -rw-r--r-- | spec/core/registry_spec.moon (renamed from spec/registry_spec.moon) | 0 | ||||
| -rw-r--r-- | spec/core/scope_spec.moon (renamed from spec/scope_spec.moon) | 0 | ||||
| -rw-r--r-- | spec/core/tag_spec.moon | 100 | ||||
| -rw-r--r-- | spec/core/value_spec.moon (renamed from spec/value_spec.moon) | 11 |
10 files changed, 161 insertions, 39 deletions
diff --git a/core/cell.moon b/core/cell.moon index 0cb8e9f..4b28a04 100644 --- a/core/cell.moon +++ b/core/cell.moon @@ -3,24 +3,9 @@ import Value from require 'core.value' import op_invoke, fn_invoke from require 'core.invoke' import Tag from require 'core.tag' --- ALV Cell type +-- An S-Expression with a head expression and any number of tail expressions, +-- an optional tag, and optionally the internal whitespace as parsed. class Cell --- common - -- 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] - @white[0] = '' - - assert #@white == #@children, "mismatched whitespace length" - - head: => @children[1] - tail: => [c for c in *@children[2,]] - - destroy: => - -- AST interface eval: (scope) => head = (@head!\eval scope)\const! @@ -42,12 +27,15 @@ class Cell Action\eval_cell scope, @tag, head, @tail! + -- quoting a Cell recursively quotes children, but preserves identity this + -- means that a quoted Cell may only be 'used' once. use :clone() otherwise. quote: (scope) => children = [child\quote scope for child in *@children] Cell @tag, children, @white + -- creates a clone of this Cell with its own identity by prepending a `parent` + -- tag and cloning all child expressoins recursively. clone: (parent) => - @tag\ensure! tag = @tag\clone parent children = [child\clone parent for child in *@children] Cell tag, children, @white @@ -67,6 +55,20 @@ class Cell '(' .. @tag\stringify! .. buf .. ')' +-- internal + -- 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] + @white[0] = '' + + assert #@white == #@children, "mismatched whitespace length" + + head: => @children[1] + tail: => [c for c in *@children[2,]] + -- static __tostring: => @stringify 2 @@ -85,9 +87,9 @@ class Cell tag, children, white = parse_args ... @ tag, children, white --- A parenthesis-less Cell (root of an ALV document) +-- A parenthesis-less Cell (root of an ALV document). -- --- evaluates with an implicit 'do' in the head +-- has an implicit head of 'do'. class RootCell extends Cell head: => Value.sym 'do' tail: => @children diff --git a/core/parsing.moon b/core/parsing.moon index 0123469..ac4f878 100644 --- a/core/parsing.moon +++ b/core/parsing.moon @@ -44,13 +44,7 @@ cell = P { :expr, :explist, :cell } -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 +program = root * -1 { :comment diff --git a/core/registry.moon b/core/registry.moon index e8272fa..2ac5825 100644 --- a/core/registry.moon +++ b/core/registry.moon @@ -73,9 +73,6 @@ class SimpleRegistry extends Registry last: (index) => replace: (index, expr) => - finalize: => - assert @ == @@active_registry, "not the active registry!" - @@active_registry, @prev = @prev, nil { :Registry diff --git a/core/tag.moon b/core/tag.moon index 122c67e..f38d36a 100644 --- a/core/tag.moon +++ b/core/tag.moon @@ -10,43 +10,59 @@ class DummyReg dummy = DummyReg! class Tag - new: (@value) => - - clone: (parent) => ClonedTag @, parent - + -- obtain the value that was previously registered (using keep or replace) for + -- this tag last: => if index = @index! Registry.active!\last index + -- assert that `expr` is the value that was previously registered for this + -- tag, and keep it for the current eval cycle. + -- fails for blank tags. keep: (expr) => index = assert @index! assert expr == Registry.active!\last index Registry.active!\replace index, expr + -- register `expr` for this tag for the current eval cycle. + -- registers blank tags. replace: (expr) => if index = @index! Registry.active!\replace index, expr else Registry.active!\init @, expr - ensure: => + -- create a copy of this tag scoped to a `parent` tag. + -- registers blank tags. + clone: (parent) => + -- ensure this tag is registered for the current eval cycle, + -- even if it is blank and has no associated value if index = @index! Registry.active!\replace index, dummy, true else Registry.active!\init @, dummy + assert parent, "need parent to clone!" + ClonedTag @, parent + +-- internal + new: (@value) => + index: => @value + -- callback from `Registry` when the eval cycle is ending and a tag value has + -- been generated set: (value) => - assert not @value, "setting #{@} again" + assert not @value, "#{@} is not blank" @value = value +-- static + @blank: -> Tag! @parse: (num) => @ tonumber num stringify: => if @value then "[#{@value}]" else '' - - __tostring: => if @value then "#{@value}" else '[blank]' + __tostring: => if @value then "#{@value}" else '?' class ClonedTag extends Tag new: (@original, @parent) => @@ -57,7 +73,9 @@ class ClonedTag extends Tag if orig and parent "#{parent}.#{orig}" - set: (value) => @original\set value + set: (value) => + assert @parent.value, "cloned tag #{@} set before parent" + @original\set value stringify: => error "cant stringify ClonedTag" diff --git a/spec/cell_spec.moon b/spec/core/cell_spec.moon index fcf9861..fcf9861 100644 --- a/spec/cell_spec.moon +++ b/spec/core/cell_spec.moon diff --git a/spec/parsing_spec.moon b/spec/core/parsing_spec.moon index ddf760f..ddf760f 100644 --- a/spec/parsing_spec.moon +++ b/spec/core/parsing_spec.moon diff --git a/spec/registry_spec.moon b/spec/core/registry_spec.moon index 6fe2e3a..6fe2e3a 100644 --- a/spec/registry_spec.moon +++ b/spec/core/registry_spec.moon diff --git a/spec/scope_spec.moon b/spec/core/scope_spec.moon index 471bbce..471bbce 100644 --- a/spec/scope_spec.moon +++ b/spec/core/scope_spec.moon diff --git a/spec/core/tag_spec.moon b/spec/core/tag_spec.moon new file mode 100644 index 0000000..7855fd6 --- /dev/null +++ b/spec/core/tag_spec.moon @@ -0,0 +1,100 @@ +import Tag from require 'core.tag' +import Registry from require 'core.registry' +import Logger from require 'logger' +Logger.init 'silent' + +with_reg = (fn) -> + registry = Registry! + fn = registry\wrap_eval fn + fn, registry + +do_reg = (fn) -> + fn, reg = with_reg fn + fn! + reg + +describe 'Tag', -> + describe 'should be constructable', -> + it 'by parsing', -> + tag = Tag\parse '2' + assert tag + assert.is.equal 2, tag.value + assert.is.equal '[2]', tag\stringify! + assert.is.equal '2', tostring tag + + it 'as blank Tags', -> + tag = Tag\blank! + assert tag + assert.is.nil tag.value + assert.is.equal '', tag\stringify! + assert.is.equal '?', tostring tag + + describe 'should be clonable', -> + do_asserts = (tag, expect) -> + assert tag + assert.is.nil tag.value + assert.is.equal expect, tostring tag + assert.has.error tag\stringify + + it 'from parsed tags', with_reg -> + parent = Tag\parse '1' + original = Tag\parse '2' + tag = original\clone parent + do_asserts tag, '1.2' + + it 'but not from blank tags', with_reg -> + parent = Tag\parse '1' + original = Tag\blank! + tag = original\clone parent + do_asserts tag, '1.?' + + it 'with blank parent', with_reg -> + parent = Tag\blank! + original = Tag\parse '2' + tag = original\clone parent + do_asserts tag, '?.2' + + it 'completely blank', with_reg -> + parent = Tag\blank! + original = Tag\blank! + tag = original\clone parent + do_asserts tag, '?.?' + + describe 'should be set-able', -> + it 'only if blank', with_reg -> + tag = Tag\parse '42' + assert.has.error -> tag\set 43 + + clone = tag\clone Tag\parse '3' + assert.has.error -> clone\set 42 + + clone = tag\clone Tag\blank! + assert.has.error -> clone\set 42 + + it 'and stores the value', with_reg -> + blank = Tag\blank! + blank\set 12 + + assert.is.equal blank.value, 12 + + it 'sets the original if cloned', with_reg -> + original = Tag\blank! + parent = Tag\parse '7' + + o_set = spy.on original, 'set' + p_set = spy.on parent, 'set' + + clone = original\clone parent + clone\set 11 + + assert.spy(o_set).was_called_with (match.is_ref original), 11 + assert.spy(p_set).was_not_called! + + assert.is.equal original.value, 11 + + it 'requires the parent to be registered if cloned', with_reg -> + original = Tag\blank! + parent = Tag\blank! + + clone = original\clone parent + assert.has.error -> clone\set 11 diff --git a/spec/value_spec.moon b/spec/core/value_spec.moon index bc68c5b..cda7123 100644 --- a/spec/value_spec.moon +++ b/spec/core/value_spec.moon @@ -66,6 +66,17 @@ describe 'Value', -> assert.has_error -> (Value.str 'hi')\unwrap 'num' assert.has_error -> (Value.sym 'hi')\unwrap 'str' + test 'with __call shorthand', -> + assert.is.equal 3.14, (Value.num 3.14)! + assert.is.equal 'hi', (Value.str 'hi')! + assert.is.equal 'hi', (Value.sym 'hi')! + assert.is.equal 3.14, (Value.num 3.14) 'num' + assert.is.equal 'hi', (Value.str 'hi') 'str' + assert.is.equal 'hi', (Value.sym 'hi') 'sym' + assert.has_error -> (Value.num 3.14) 'sym' + assert.has_error -> (Value.str 'hi') 'num' + assert.has_error -> (Value.sym 'hi') 'str' + describe 'checks equality', -> test 'using the type', -> val = Value 'num', 3 |
