From df8141c3214a5fb8d447297be64bdf5619b7d8a7 Mon Sep 17 00:00:00 2001 From: s-ol Date: Fri, 28 Feb 2020 13:21:57 +0100 Subject: doc and tag spec --- core/cell.moon | 42 +++++++------ core/parsing.moon | 8 +-- core/registry.moon | 3 - core/tag.moon | 36 ++++++++--- spec/cell_spec.moon | 36 ----------- spec/core/cell_spec.moon | 36 +++++++++++ spec/core/parsing_spec.moon | 146 +++++++++++++++++++++++++++++++++++++++++++ spec/core/registry_spec.moon | 8 +++ spec/core/scope_spec.moon | 114 +++++++++++++++++++++++++++++++++ spec/core/tag_spec.moon | 100 +++++++++++++++++++++++++++++ spec/core/value_spec.moon | 123 ++++++++++++++++++++++++++++++++++++ spec/parsing_spec.moon | 146 ------------------------------------------- spec/registry_spec.moon | 8 --- spec/scope_spec.moon | 114 --------------------------------- spec/value_spec.moon | 112 --------------------------------- 15 files changed, 577 insertions(+), 455 deletions(-) delete mode 100644 spec/cell_spec.moon create mode 100644 spec/core/cell_spec.moon create mode 100644 spec/core/parsing_spec.moon create mode 100644 spec/core/registry_spec.moon create mode 100644 spec/core/scope_spec.moon create mode 100644 spec/core/tag_spec.moon create mode 100644 spec/core/value_spec.moon delete mode 100644 spec/parsing_spec.moon delete mode 100644 spec/registry_spec.moon delete mode 100644 spec/scope_spec.moon delete mode 100644 spec/value_spec.moon 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/cell_spec.moon deleted file mode 100644 index fcf9861..0000000 --- a/spec/cell_spec.moon +++ /dev/null @@ -1,36 +0,0 @@ -import Cell, RootCell, Value, Scope, globals from require 'core' -import Registry from require 'core.registry' -import Logger from require 'logger' -Logger.init 'silent' - -hello_world = Cell nil, { (Value.sym 'hello'), (Value.str 'world') } -two_plus_two = Cell nil, { (Value.sym '+'), (Value.num 2), (Value.num 2) } - -describe 'Cell', -> - it 'supports quoting', -> - with hello_world\quote! - assert.is.equal Cell, .__class - assert.is.equal (Value.sym 'hello'), \head! - assert.is.same { Value.str 'world' }, \tail! - - with two_plus_two\quote! - assert.is.equal Cell, .__class - assert.is.equal (Value.sym '+'), \head! - assert.is.same { (Value.num 2), (Value.num 2) }, \tail! - - -describe 'RootCell', -> - test 'head is always "do"', -> - cell = RootCell\parse {} - assert.is.equal (Value.sym 'do'), cell\head! - - cell = RootCell nil, { hello_world, two_plus_two } - assert.is.equal (Value.sym 'do'), cell\head! - - test 'tail is all children', -> - cell = RootCell\parse {} - assert.is.same {}, cell\tail! - - cell = RootCell nil, { hello_world, two_plus_two } - assert.is.same { hello_world, two_plus_two }, - cell\tail! diff --git a/spec/core/cell_spec.moon b/spec/core/cell_spec.moon new file mode 100644 index 0000000..fcf9861 --- /dev/null +++ b/spec/core/cell_spec.moon @@ -0,0 +1,36 @@ +import Cell, RootCell, Value, Scope, globals from require 'core' +import Registry from require 'core.registry' +import Logger from require 'logger' +Logger.init 'silent' + +hello_world = Cell nil, { (Value.sym 'hello'), (Value.str 'world') } +two_plus_two = Cell nil, { (Value.sym '+'), (Value.num 2), (Value.num 2) } + +describe 'Cell', -> + it 'supports quoting', -> + with hello_world\quote! + assert.is.equal Cell, .__class + assert.is.equal (Value.sym 'hello'), \head! + assert.is.same { Value.str 'world' }, \tail! + + with two_plus_two\quote! + assert.is.equal Cell, .__class + assert.is.equal (Value.sym '+'), \head! + assert.is.same { (Value.num 2), (Value.num 2) }, \tail! + + +describe 'RootCell', -> + test 'head is always "do"', -> + cell = RootCell\parse {} + assert.is.equal (Value.sym 'do'), cell\head! + + cell = RootCell nil, { hello_world, two_plus_two } + assert.is.equal (Value.sym 'do'), cell\head! + + test 'tail is all children', -> + cell = RootCell\parse {} + assert.is.same {}, cell\tail! + + cell = RootCell nil, { hello_world, two_plus_two } + assert.is.same { hello_world, two_plus_two }, + cell\tail! diff --git a/spec/core/parsing_spec.moon b/spec/core/parsing_spec.moon new file mode 100644 index 0000000..ddf760f --- /dev/null +++ b/spec/core/parsing_spec.moon @@ -0,0 +1,146 @@ +import space, atom, expr, explist, cell, program, comment from require 'core.parsing' +import Value from require 'core' +import Logger from require 'logger' +Logger.init 'silent' + +verify_parse = (parser, str) -> + with assert parser\match str + assert.is.equal str, \stringify! + +verify_parse_nope = (parser, str) -> + with assert parser\match str + without_nope = str\match '^(.*) nope$' + assert.is.equal without_nope, \stringify! + +describe 'atom parsing', -> + test 'symbols', -> + sym = verify_parse_nope atom, 'some-toast nope' + assert.is.equal 'sym', sym.type + assert.is.equal 'some-toast', sym\unwrap! + assert.is.equal 'some-toast', sym\stringify! + + describe 'numbers', -> + it 'parses ints', -> + num = verify_parse_nope atom, '1234 nope' + assert.is.equal 'num', num.type + assert.is.equal 1234, num\unwrap! + assert.is.equal '1234', num\stringify! + + it 'parses floats', -> + num = verify_parse_nope atom, '0.123 nope' + assert.is.equal 'num', num.type + assert.is.equal 0.123, num\unwrap! + + num = verify_parse_nope atom, '.123 nope' + assert.is.equal 'num', num.type + assert.is.equal 0.123, num\unwrap! + + num = verify_parse_nope atom, '0. nope' + assert.is.equal 'num', num.type + assert.is.equal 0, num\unwrap! + + describe 'strings', -> + it 'parses double-quote strings', -> + str = verify_parse_nope atom, '"help some stuff!" nope' + assert.is.equal 'str', str.type + assert.is.equal 'help some stuff!', str\unwrap! + + it 'parses single-quote strings', -> + str = verify_parse_nope atom, "'help some stuff!' nope" + assert.is.equal 'str', str.type + assert.is.equal "help some stuff!", str\unwrap! + + it 'handles escapes', -> + str = verify_parse_nope atom, '"string with \\"quote\\"s and \\\\" nope' + assert.is.equal 'str', str.type + assert.is.equal 'string with \"quote\"s and \\', str\unwrap! + + str = verify_parse_nope atom, "'string with \\'quote\\'s and \\\\' nope" + assert.is.equal 'str', str.type + assert.is.equal "string with \'quote\'s and \\", str\unwrap! + +describe 'Cell', -> + test 'basic parsing', -> + node = verify_parse cell, '( 3 ok-yes + "friend" )' + + assert.is.equal 3, #node.children + assert.is.equal (Value.num 3), node.children[1] + assert.is.equal (Value.sym 'ok-yes'), node.children[2] + assert.is.equal (Value.str 'friend'), node.children[3] + + test 'tag parsing', -> + node = verify_parse cell, '([42]tagged 2)' + + assert.is.equal 2, #node.children + assert.is.equal 42, node.tag.value + + test 'tag parsing with whitespace', -> + node = verify_parse cell, '([42] + tagged 2)' + + assert.is.equal 2, #node.children + assert.is.equal 42, node.tag.value + +describe 'RootCell parsing', -> + describe 'handles whitespace', -> + verify = (str) -> + node = verify_parse program, str + + assert.is.equal 2, #node.children + assert.is.equal (Value.num 3), node.children[1] + assert.is.equal (Value.sym 'ok-yes'), node.children[2] + + it 'at the front of the string', -> + verify ' 3\tok-yes' + + it 'at the end of the string', -> + verify ' 3\tok-yes\n' + + it 'everywhere', -> + verify ' 3\tok-yes\n' + +test 'whitespace', -> + assert.is.equal ' ', space\match ' ' + assert.is.equal '\n\t ', space\match '\n\t ' + +describe 'comments', -> + comment = comment / 1 + it 'are parsed', -> + str = '#(this is a comment)' + assert.is.equal str, comment\match str + + it 'extend to matching braces', -> + str = '#(this is a comment #(with nested comments))' + assert.is.equal str, comment\match str + + it 'can nest', -> + str = '#(this is a comment (with nested parenthesis))' + assert.is.equal str, comment\match str + +describe 'resynthesis', -> + test 'mixed parsing', -> + str = '( 3 ok-yes + "friend" )' + node = verify_parse program, str + assert.is.equal str, node\stringify! + + test 'complex', -> + str = ' + #(send a CC controlled LFO to /radius) + (osc "/radius" (lfo (cc 14))) + + (osc rot + (step + #(whenever a kick is received...) + (note "kick") + + #(..cycle through random rotation values) + (random-rot) + (random-rot) + (random-rot) + (random-rot) + ) + ) ' + matched = assert.is.truthy verify_parse program, str + assert.is.equal str, matched\stringify! diff --git a/spec/core/registry_spec.moon b/spec/core/registry_spec.moon new file mode 100644 index 0000000..6fe2e3a --- /dev/null +++ b/spec/core/registry_spec.moon @@ -0,0 +1,8 @@ +import Registry, Tag from require 'core.registry' +import Logger from require 'logger' +Logger.init 'silent' + +mk = -> + mock destroy: => + +describe 'registry', -> diff --git a/spec/core/scope_spec.moon b/spec/core/scope_spec.moon new file mode 100644 index 0000000..471bbce --- /dev/null +++ b/spec/core/scope_spec.moon @@ -0,0 +1,114 @@ +import Scope, Value, Op from require 'core' +import Logger from require 'logger' +Logger.init 'silent' + +class TestOp extends Op + new: (...) => super ... + +describe 'Scope', -> + describe 'constifies', -> + scope = Scope! + + test 'numbers', -> + scope\set_raw 'num', 3 + + got = (scope\get 'num')\const! + assert.is.equal 'num', got.type + assert.is.equal 3, got.value + + test 'strings', -> + scope\set_raw 'str', "im a happy string" + + got = (scope\get 'str')\const! + assert.is.equal 'str', got.type + assert.is.equal "im a happy string", got.value + + test 'Values', -> + pi = Value 'num', 3.14 + scope\set_raw 'pi', pi + + assert.is.equal pi, (scope\get 'pi')\const! + + test 'Opdefs', -> + scope\set_raw 'test', TestOp + + got = (scope\get 'test')\const! + assert.is.equal 'opdef', got.type + assert.is.equal TestOp, got.value + + test 'Scopes', -> + sub = Scope! + scope\set_raw 'sub', sub + + got = (scope\get 'sub')\const! + assert.is.equal 'scope', got.type + assert.is.equal sub, got.value + + test 'tables', -> + pi = Value 'num', 3.14 + scope\set_raw 'math', { :pi } + + got = (scope\get 'math')\const! + assert.is.equal 'scope', got.type + assert.is.equal Scope, got.value.__class + assert.is.equal pi, (got.value\get 'pi')\const! + assert.is.equal pi, (scope\get 'math/pi')\const! + + it 'wraps Values in from_table', -> + pi = Value 'num', 3.14 + scope = Scope.from_table { + num: 3 + str: "im a happy string" + :pi + math: :pi + test: TestOp + } + + got = (scope\get 'num')\const! + assert.is.equal 'num', got.type + assert.is.equal 3, got.value + + got = (scope\get 'str')\const! + assert.is.equal 'str', got.type + assert.is.equal "im a happy string", got.value + + assert.is.equal pi, (scope\get 'pi')\const! + + got = (scope\get 'test')\const! + assert.is.equal 'opdef', got.type + assert.is.equal TestOp, got.value + + got = (scope\get 'math')\const! + assert.is.equal 'scope', got.type + assert.is.equal pi, (scope\get 'math/pi')\const! + + it 'gets from nested scopes', -> + root = Scope! + a = Scope! + b = Scope! + + pi = Value 'num', 3.14 + b\set_raw 'test', pi + a\set_raw 'child', b + root\set_raw 'deep', a + + assert.is.equal pi, (root\get 'deep/child/test')\const! + + describe 'inheritance', -> + root = Scope! + root\set_raw 'hidden', 1234 + root\set_raw 'inherited', "inherited string" + + scope = Scope nil, root + + it 'allows access', -> + got = (scope\get 'inherited')\const! + assert.is.equal 'str', got.type + assert.is.equal "inherited string", got.value + + it 'can keep defs', -> + scope\set_raw 'hidden', "overwritten" + + got = (scope\get 'hidden')\const! + assert.is.equal 'str', got.type + assert.is.equal "overwritten", got.value 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/core/value_spec.moon b/spec/core/value_spec.moon new file mode 100644 index 0000000..cda7123 --- /dev/null +++ b/spec/core/value_spec.moon @@ -0,0 +1,123 @@ +import Value, Result, Op, Action, Scope from require 'core' +import Logger from require 'logger' +Logger.init 'silent' + +class TestOp extends Op + new: (...) => super ... + +class TestAction extends Action + new: (...) => + +describe 'Value', -> + describe 'wraps', -> + test 'numbers', -> + got = Value.wrap 3 + assert.is.equal 'num', got.type + assert.is.equal 3, got.value + + test 'strings', -> + got = Value.wrap "im a happy string" + assert.is.equal 'str', got.type + assert.is.equal "im a happy string", got.value + + test 'Values', -> + pi = Value 'num', 3.14 + got = Value.wrap pi + + assert.is.equal pi, got + + test 'Opdefs', -> + got = Value.wrap TestOp + + assert.is.equal 'opdef', got.type + assert.is.equal TestOp, got.value + + test 'Bultins', -> + got = Value.wrap TestAction + + assert.is.equal 'builtin', got.type + assert.is.equal TestAction, got.value + + test 'Scopes', -> + sub = Scope! + got = Value.wrap sub + + assert.is.equal 'scope', got.type + assert.is.equal sub, got.value + + test 'tables', -> + pi = Value 'num', 3.14 + got = Value.wrap { :pi } + + assert.is.equal 'scope', got.type + assert.is.equal pi, (got.value\get 'pi')\const! + + describe 'unwraps', -> + test 'unwrap!', -> + assert.is.equal 3.14, (Value.num 3.14)\unwrap! + assert.is.equal 'hi', (Value.str 'hi')\unwrap! + assert.is.equal 'hi', (Value.sym 'hi')\unwrap! + + test 'with type assert', -> + assert.is.equal 3.14, (Value.num 3.14)\unwrap 'num' + assert.is.equal 'hi', (Value.str 'hi')\unwrap 'str' + assert.is.equal 'hi', (Value.sym 'hi')\unwrap 'sym' + assert.has_error -> (Value.num 3.14)\unwrap 'sym' + 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 + assert.is.equal (Value.num 3), val + assert.not.equal (Value.str '3'), val + + val = Value 'str', 'hello' + assert.is.equal (Value.str 'hello'), val + assert.not.equal (Value.sym 'hello'), val + + test 'using the value', -> + val = Value 'num', 3 + assert.is.equal (Value.num 3), val + assert.not.equal (Value.num 4), val + + describe 'evaluates literal', -> + test 'numbers to consts', -> + assert_noop = (val) -> + assert.is.equal val, val\eval!\const! + + assert_noop Value.num 2 + assert_noop Value.str 'hello' + + test 'symbols in the scope', -> + scope = with Scope! + \set 'number', Result value: Value.num 3 + \set 'hello', Result value: Value.str "world" + \set 'goodbye', Result value: Value.sym "again" + + assert_eval = (sym, val) -> + const = Value.sym sym + assert.is.equal val, (const\eval scope)\const! + + assert_eval 'number', Value.num 3 + assert_eval 'hello', Value.str "world" + assert_eval 'goodbye', Value.sym "again" + + describe 'quotes literals', -> + test 'as themselves', -> + assert_noop = (val) -> assert.is.equal val, val\quote! + + assert_noop Value.num 2 + assert_noop Value.str 'hello' + assert_noop Value.sym 'world' diff --git a/spec/parsing_spec.moon b/spec/parsing_spec.moon deleted file mode 100644 index ddf760f..0000000 --- a/spec/parsing_spec.moon +++ /dev/null @@ -1,146 +0,0 @@ -import space, atom, expr, explist, cell, program, comment from require 'core.parsing' -import Value from require 'core' -import Logger from require 'logger' -Logger.init 'silent' - -verify_parse = (parser, str) -> - with assert parser\match str - assert.is.equal str, \stringify! - -verify_parse_nope = (parser, str) -> - with assert parser\match str - without_nope = str\match '^(.*) nope$' - assert.is.equal without_nope, \stringify! - -describe 'atom parsing', -> - test 'symbols', -> - sym = verify_parse_nope atom, 'some-toast nope' - assert.is.equal 'sym', sym.type - assert.is.equal 'some-toast', sym\unwrap! - assert.is.equal 'some-toast', sym\stringify! - - describe 'numbers', -> - it 'parses ints', -> - num = verify_parse_nope atom, '1234 nope' - assert.is.equal 'num', num.type - assert.is.equal 1234, num\unwrap! - assert.is.equal '1234', num\stringify! - - it 'parses floats', -> - num = verify_parse_nope atom, '0.123 nope' - assert.is.equal 'num', num.type - assert.is.equal 0.123, num\unwrap! - - num = verify_parse_nope atom, '.123 nope' - assert.is.equal 'num', num.type - assert.is.equal 0.123, num\unwrap! - - num = verify_parse_nope atom, '0. nope' - assert.is.equal 'num', num.type - assert.is.equal 0, num\unwrap! - - describe 'strings', -> - it 'parses double-quote strings', -> - str = verify_parse_nope atom, '"help some stuff!" nope' - assert.is.equal 'str', str.type - assert.is.equal 'help some stuff!', str\unwrap! - - it 'parses single-quote strings', -> - str = verify_parse_nope atom, "'help some stuff!' nope" - assert.is.equal 'str', str.type - assert.is.equal "help some stuff!", str\unwrap! - - it 'handles escapes', -> - str = verify_parse_nope atom, '"string with \\"quote\\"s and \\\\" nope' - assert.is.equal 'str', str.type - assert.is.equal 'string with \"quote\"s and \\', str\unwrap! - - str = verify_parse_nope atom, "'string with \\'quote\\'s and \\\\' nope" - assert.is.equal 'str', str.type - assert.is.equal "string with \'quote\'s and \\", str\unwrap! - -describe 'Cell', -> - test 'basic parsing', -> - node = verify_parse cell, '( 3 ok-yes - "friend" )' - - assert.is.equal 3, #node.children - assert.is.equal (Value.num 3), node.children[1] - assert.is.equal (Value.sym 'ok-yes'), node.children[2] - assert.is.equal (Value.str 'friend'), node.children[3] - - test 'tag parsing', -> - node = verify_parse cell, '([42]tagged 2)' - - assert.is.equal 2, #node.children - assert.is.equal 42, node.tag.value - - test 'tag parsing with whitespace', -> - node = verify_parse cell, '([42] - tagged 2)' - - assert.is.equal 2, #node.children - assert.is.equal 42, node.tag.value - -describe 'RootCell parsing', -> - describe 'handles whitespace', -> - verify = (str) -> - node = verify_parse program, str - - assert.is.equal 2, #node.children - assert.is.equal (Value.num 3), node.children[1] - assert.is.equal (Value.sym 'ok-yes'), node.children[2] - - it 'at the front of the string', -> - verify ' 3\tok-yes' - - it 'at the end of the string', -> - verify ' 3\tok-yes\n' - - it 'everywhere', -> - verify ' 3\tok-yes\n' - -test 'whitespace', -> - assert.is.equal ' ', space\match ' ' - assert.is.equal '\n\t ', space\match '\n\t ' - -describe 'comments', -> - comment = comment / 1 - it 'are parsed', -> - str = '#(this is a comment)' - assert.is.equal str, comment\match str - - it 'extend to matching braces', -> - str = '#(this is a comment #(with nested comments))' - assert.is.equal str, comment\match str - - it 'can nest', -> - str = '#(this is a comment (with nested parenthesis))' - assert.is.equal str, comment\match str - -describe 'resynthesis', -> - test 'mixed parsing', -> - str = '( 3 ok-yes - "friend" )' - node = verify_parse program, str - assert.is.equal str, node\stringify! - - test 'complex', -> - str = ' - #(send a CC controlled LFO to /radius) - (osc "/radius" (lfo (cc 14))) - - (osc rot - (step - #(whenever a kick is received...) - (note "kick") - - #(..cycle through random rotation values) - (random-rot) - (random-rot) - (random-rot) - (random-rot) - ) - ) ' - matched = assert.is.truthy verify_parse program, str - assert.is.equal str, matched\stringify! diff --git a/spec/registry_spec.moon b/spec/registry_spec.moon deleted file mode 100644 index 6fe2e3a..0000000 --- a/spec/registry_spec.moon +++ /dev/null @@ -1,8 +0,0 @@ -import Registry, Tag from require 'core.registry' -import Logger from require 'logger' -Logger.init 'silent' - -mk = -> - mock destroy: => - -describe 'registry', -> diff --git a/spec/scope_spec.moon b/spec/scope_spec.moon deleted file mode 100644 index 471bbce..0000000 --- a/spec/scope_spec.moon +++ /dev/null @@ -1,114 +0,0 @@ -import Scope, Value, Op from require 'core' -import Logger from require 'logger' -Logger.init 'silent' - -class TestOp extends Op - new: (...) => super ... - -describe 'Scope', -> - describe 'constifies', -> - scope = Scope! - - test 'numbers', -> - scope\set_raw 'num', 3 - - got = (scope\get 'num')\const! - assert.is.equal 'num', got.type - assert.is.equal 3, got.value - - test 'strings', -> - scope\set_raw 'str', "im a happy string" - - got = (scope\get 'str')\const! - assert.is.equal 'str', got.type - assert.is.equal "im a happy string", got.value - - test 'Values', -> - pi = Value 'num', 3.14 - scope\set_raw 'pi', pi - - assert.is.equal pi, (scope\get 'pi')\const! - - test 'Opdefs', -> - scope\set_raw 'test', TestOp - - got = (scope\get 'test')\const! - assert.is.equal 'opdef', got.type - assert.is.equal TestOp, got.value - - test 'Scopes', -> - sub = Scope! - scope\set_raw 'sub', sub - - got = (scope\get 'sub')\const! - assert.is.equal 'scope', got.type - assert.is.equal sub, got.value - - test 'tables', -> - pi = Value 'num', 3.14 - scope\set_raw 'math', { :pi } - - got = (scope\get 'math')\const! - assert.is.equal 'scope', got.type - assert.is.equal Scope, got.value.__class - assert.is.equal pi, (got.value\get 'pi')\const! - assert.is.equal pi, (scope\get 'math/pi')\const! - - it 'wraps Values in from_table', -> - pi = Value 'num', 3.14 - scope = Scope.from_table { - num: 3 - str: "im a happy string" - :pi - math: :pi - test: TestOp - } - - got = (scope\get 'num')\const! - assert.is.equal 'num', got.type - assert.is.equal 3, got.value - - got = (scope\get 'str')\const! - assert.is.equal 'str', got.type - assert.is.equal "im a happy string", got.value - - assert.is.equal pi, (scope\get 'pi')\const! - - got = (scope\get 'test')\const! - assert.is.equal 'opdef', got.type - assert.is.equal TestOp, got.value - - got = (scope\get 'math')\const! - assert.is.equal 'scope', got.type - assert.is.equal pi, (scope\get 'math/pi')\const! - - it 'gets from nested scopes', -> - root = Scope! - a = Scope! - b = Scope! - - pi = Value 'num', 3.14 - b\set_raw 'test', pi - a\set_raw 'child', b - root\set_raw 'deep', a - - assert.is.equal pi, (root\get 'deep/child/test')\const! - - describe 'inheritance', -> - root = Scope! - root\set_raw 'hidden', 1234 - root\set_raw 'inherited', "inherited string" - - scope = Scope nil, root - - it 'allows access', -> - got = (scope\get 'inherited')\const! - assert.is.equal 'str', got.type - assert.is.equal "inherited string", got.value - - it 'can keep defs', -> - scope\set_raw 'hidden', "overwritten" - - got = (scope\get 'hidden')\const! - assert.is.equal 'str', got.type - assert.is.equal "overwritten", got.value diff --git a/spec/value_spec.moon b/spec/value_spec.moon deleted file mode 100644 index bc68c5b..0000000 --- a/spec/value_spec.moon +++ /dev/null @@ -1,112 +0,0 @@ -import Value, Result, Op, Action, Scope from require 'core' -import Logger from require 'logger' -Logger.init 'silent' - -class TestOp extends Op - new: (...) => super ... - -class TestAction extends Action - new: (...) => - -describe 'Value', -> - describe 'wraps', -> - test 'numbers', -> - got = Value.wrap 3 - assert.is.equal 'num', got.type - assert.is.equal 3, got.value - - test 'strings', -> - got = Value.wrap "im a happy string" - assert.is.equal 'str', got.type - assert.is.equal "im a happy string", got.value - - test 'Values', -> - pi = Value 'num', 3.14 - got = Value.wrap pi - - assert.is.equal pi, got - - test 'Opdefs', -> - got = Value.wrap TestOp - - assert.is.equal 'opdef', got.type - assert.is.equal TestOp, got.value - - test 'Bultins', -> - got = Value.wrap TestAction - - assert.is.equal 'builtin', got.type - assert.is.equal TestAction, got.value - - test 'Scopes', -> - sub = Scope! - got = Value.wrap sub - - assert.is.equal 'scope', got.type - assert.is.equal sub, got.value - - test 'tables', -> - pi = Value 'num', 3.14 - got = Value.wrap { :pi } - - assert.is.equal 'scope', got.type - assert.is.equal pi, (got.value\get 'pi')\const! - - describe 'unwraps', -> - test 'unwrap!', -> - assert.is.equal 3.14, (Value.num 3.14)\unwrap! - assert.is.equal 'hi', (Value.str 'hi')\unwrap! - assert.is.equal 'hi', (Value.sym 'hi')\unwrap! - - test 'with type assert', -> - assert.is.equal 3.14, (Value.num 3.14)\unwrap 'num' - assert.is.equal 'hi', (Value.str 'hi')\unwrap 'str' - assert.is.equal 'hi', (Value.sym 'hi')\unwrap 'sym' - assert.has_error -> (Value.num 3.14)\unwrap 'sym' - assert.has_error -> (Value.str 'hi')\unwrap 'num' - assert.has_error -> (Value.sym 'hi')\unwrap 'str' - - describe 'checks equality', -> - test 'using the type', -> - val = Value 'num', 3 - assert.is.equal (Value.num 3), val - assert.not.equal (Value.str '3'), val - - val = Value 'str', 'hello' - assert.is.equal (Value.str 'hello'), val - assert.not.equal (Value.sym 'hello'), val - - test 'using the value', -> - val = Value 'num', 3 - assert.is.equal (Value.num 3), val - assert.not.equal (Value.num 4), val - - describe 'evaluates literal', -> - test 'numbers to consts', -> - assert_noop = (val) -> - assert.is.equal val, val\eval!\const! - - assert_noop Value.num 2 - assert_noop Value.str 'hello' - - test 'symbols in the scope', -> - scope = with Scope! - \set 'number', Result value: Value.num 3 - \set 'hello', Result value: Value.str "world" - \set 'goodbye', Result value: Value.sym "again" - - assert_eval = (sym, val) -> - const = Value.sym sym - assert.is.equal val, (const\eval scope)\const! - - assert_eval 'number', Value.num 3 - assert_eval 'hello', Value.str "world" - assert_eval 'goodbye', Value.sym "again" - - describe 'quotes literals', -> - test 'as themselves', -> - assert_noop = (val) -> assert.is.equal val, val\quote! - - assert_noop Value.num 2 - assert_noop Value.str 'hello' - assert_noop Value.sym 'world' -- cgit v1.2.3