diff options
| author | s-ol <s-ol@users.noreply.github.com> | 2020-02-10 17:51:24 +0000 |
|---|---|---|
| committer | s-ol <s-ol@users.noreply.github.com> | 2020-02-10 17:51:24 +0000 |
| commit | 6c18ffdcc493bce6bfec4f5e64453ec7d6140253 (patch) | |
| tree | bd3f3fe647a8ad66d7c77c918174a464389a70f3 /lib | |
| parent | closures (diff) | |
| download | alive-6c18ffdcc493bce6bfec4f5e64453ec7d6140253.tar.gz alive-6c18ffdcc493bce6bfec4f5e64453ec7d6140253.zip | |
add doc, import, import*, defn
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/builtin.moon | 175 | ||||
| -rw-r--r-- | lib/debug.moon | 2 | ||||
| -rw-r--r-- | lib/gui.moon | 4 | ||||
| -rw-r--r-- | lib/math.moon | 16 | ||||
| -rw-r--r-- | lib/osc.moon | 4 | ||||
| -rw-r--r-- | lib/string.moon | 18 | ||||
| -rw-r--r-- | lib/time.moon | 11 | ||||
| -rw-r--r-- | lib/util.moon | 62 |
8 files changed, 212 insertions, 80 deletions
diff --git a/lib/builtin.moon b/lib/builtin.moon index f6cde1a..02dbe15 100644 --- a/lib/builtin.moon +++ b/lib/builtin.moon @@ -1,4 +1,4 @@ -import Const, Cell, Action, Scope from require 'core' +import Const, Cell, Action, FnDef, Scope from require 'core' class UpdateChildren new: (@children) => @@ -13,14 +13,25 @@ class UpdateChildren __tostring: => '<forwarder>' --- (def sym1 val-expr1 --- [sym2 val-expr2]...) --- --- declare symbols in parent scope --- --- if val-expr is a expand-time constant, defines a `Const`, --- otherwise places a `Forward` for the expr +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" + + def = L\push tail[1]\eval, scope, @registry + L\print "(doc #{tail[1]\stringify!}):\n#{def\getc!.doc}\n" + nil + 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 "expanding #{@}" assert #tail > 1, "'def' requires at least 2 arguments" @@ -37,45 +48,75 @@ class def extends Action UpdateChildren values --- (require name-str) --- --- require a lua module and return its `Scope` --- name-str has to be an expand-time constant -class require_mod extends Action +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 "expanding #{@}" + for child in *tail + value = L\push child\eval, scope, @registry + L\trace @, "merging #{value} into #{scope}" + assert value.type == 'scope', "'use' only works on scopes" + scope\use value\getc 'scope' + + nil + +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 "expanding #{@}" - assert #tail == 1, "'require' takes only one parameter" + assert #tail == 1, "'require' takes exactly one parameter" name = L\push tail[1]\eval, scope, @registry L\trace @, "loading module #{name}" - scope = Scope.from_table require "lib.#{name\getc 'str'}" - Const 'scope', scope + module = Scope.from_table require "lib.#{name\getc 'str'}" + Const 'scope', module + +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" --- (use scope1 [scope2]...) --- --- merge scopes into parent scope --- scopes have to be expand-time constants -class use extends Action eval: (scope, tail) => L\trace "expanding #{@}" + assert #tail > 0, "'import' requires at least one arguments" + + for child in *tail - value = L\push child\eval, scope, @registry - L\trace @, "merging #{value} into #{scope}" - assert value.type == 'scope', "'use' only works on scopes" - scope\use value\getc 'scope' + name = (child\quote scope, @registry)\getc 'sym' + module = Scope.from_table require "lib.#{name}" + scope\set name, Const 'scope', module + + nil + +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 "expanding #{@}" + assert #tail > 0, "'import' requires at least one arguments" + + + for child in *tail + name = (child\quote scope, @registry)\getc 'sym' + scope\use Scope.from_table require "lib.#{name}" nil --- (fn (p1 [p2]...) body-expr) --- --- declare a function class fn extends Action - class FnDef - new: (@params, @body) => + @doc: "(fn (p1 [p2]...) body-expr) - declare a (lambda) function - __tostring: => - table.concat [p\stringify! for p in *@params], ' ' +the symbols p1, p2, ... will resolve to the arguments passed to the function." eval: (scope, tail) => L\trace "expanding #{@}" @@ -88,54 +129,36 @@ class fn extends Action param\quote scope, @registry body = body\quote scope, @registry - Const 'fndef', FnDef param_symbols, body + Const.wrap FnDef param_symbols, body, scope -class op_invoke extends Action - patch: (head) => - return true if head == @head +class defn extends Action + @doc: "(defn name-sym (p1 [p2]...) body-expr) - define a function - @op\destroy! if @op +declares a lambda (see (doc fn)) and defines it in the current scope" - @head = head - assert @head.type == 'opdef', "cant op-invoke #{@head}" - @op = @head\getc!! - - true - eval: (scope, tail) => - args = [expr\eval scope, @registry for expr in *tail] - -- Const 'op', with @op - with @op - \setup unpack args - -class fn_invoke extends Action - -- @TODO: - -- need to :patch() the case where the new head is a new fndef - -- but corresponds to the last head over time - - patch: (head) => - return true if head == @head - - @head = head - - true - - eval: (scope, tail) => - assert @head.type == 'fndef', "cant fn-invoke #{@head}" - { :params, :body } = @head\getc! + L\trace "expanding #{@}" + assert #tail == 3, "'defn' takes exactly three arguments" + { name, params, body } = tail - assert #params == #tail, "argument count mismatch in #{@head}" + name = (name\quote scope, @registry)\getc '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, @registry - fn_scope = Scope @, scope + body = body\quote scope, @registry + fn = FnDef param_symbols, body, scope - for i=1,#params - name = params[i]\getc! - argm = tail[i] - fn_scope\set name, L\push argm\eval, scope, @registry + scope\set name, Const.wrap fn - body\eval fn_scope, @registry + nil 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." class DoWrapper new: (@children) => @@ -152,11 +175,13 @@ class do_expr extends Action UpdateChildren [(expr\eval scope, @registry) or Const.empty! for expr in *tail] { - 'op-invoke': op_invoke - 'fn-invoke': fn_invoke - 'do': do_expr + :doc - require: require_mod :def, :use - :fn + require: require_ + import: import_ + 'import*': import_star + + :fn, :defn + 'do': do_expr } diff --git a/lib/debug.moon b/lib/debug.moon index 6888d89..ece365f 100644 --- a/lib/debug.moon +++ b/lib/debug.moon @@ -1,6 +1,8 @@ import Op from require 'core' class out extends Op + @doc: "(out name-str value) - log value to the console" + setup: (name, @chld) => @name = name\getc! diff --git a/lib/gui.moon b/lib/gui.moon index 69c97a3..32f23f7 100644 --- a/lib/gui.moon +++ b/lib/gui.moon @@ -4,6 +4,10 @@ import Registry from require 'registry' import Copilot from require 'copilot' class out extends Op + @doc: "(out name-str value) - show the output + +display value as a bar" + setup: (name, @chld) => @@instances[@name] = nil if @name @name = name\getc! diff --git a/lib/math.moon b/lib/math.moon index ca7321c..35ee4de 100644 --- a/lib/math.moon +++ b/lib/math.moon @@ -11,6 +11,9 @@ class BinOp extends Op child\update dt class add extends BinOp + @doc: "(+ a b [c]...) +(add a b [c]...) - add values" + update: (dt) => super\update dt @@ -19,6 +22,11 @@ class add extends BinOp @value += child\get! class sub extends BinOp + @doc: "(- a b [c]...) +(sub a b [c]...) - subtract values + +subtracts all other arguments from a" + update: (dt) => super\update dt @@ -27,6 +35,9 @@ class sub extends BinOp @value -= child\get! class mul extends BinOp + @doc: "(* a b [c]...) +(mul a b [c]...) - multiply values" + update: (dt) => super\update dt @@ -35,6 +46,11 @@ class mul extends BinOp @value *= child\get! class div extends BinOp + @doc: "(/ a b [c]...) +(div a b [c]...) - divide values + +divides a by all other arguments" + update: (dt) => super\update dt diff --git a/lib/osc.moon b/lib/osc.moon index a2c992b..880cb08 100644 --- a/lib/osc.moon +++ b/lib/osc.moon @@ -1,8 +1,10 @@ -import Op from require 'core' +import Const, Op, FnDef from require 'core' import pack, unpack from require 'osc' import dns, udp from require 'socket' class out extends Op + @doc: "(out host port path val) - send a value via OSC" + new: (...) => super ... diff --git a/lib/string.moon b/lib/string.moon new file mode 100644 index 0000000..82e9702 --- /dev/null +++ b/lib/string.moon @@ -0,0 +1,18 @@ +import Op from require 'core' + +class str extends Op + @doc: "(str v1 [v2]...) +(.. v1 [v2]...) - concatenate/stringify values" + + setup: (...) => + @children = { ... } + + update: (dt) => + for child in *@children + child\update dt + + @value = table.concat [tostring child\get! for child in *@children] + +{ + :str, '..': str +} diff --git a/lib/time.moon b/lib/time.moon index 567b16f..dac5063 100644 --- a/lib/time.moon +++ b/lib/time.moon @@ -1,6 +1,14 @@ import Const, Op from require 'core' class lfo extends Op + @doc: "(lfo freq [wave]) - low-frequency oscillator + +oscillates between 0 and 1 at the frequency freq. +wave selects the wave shape from the following (default sin): +- sin +- saw +- tri" + tau = math.pi * 2 new: (...) => super ... @@ -22,6 +30,9 @@ class lfo extends Op else error "unknown wave type" class tick extends Op + @doc: "(tick freq) - count ticks + +counts upwards at freq and returns the number of completed ticks." new: (...) => super ... @phase = 0 diff --git a/lib/util.moon b/lib/util.moon index ed643aa..0f36e02 100644 --- a/lib/util.moon +++ b/lib/util.moon @@ -1,17 +1,71 @@ import Op from require 'core' -class pick extends Op +class switch_ extends Op + @doc: "(switch i v0 [v1 v2...]) - switch between multiple inputs + +when i is true, the first value is reproduced. +when i is false, the second value is reproduced. +when i is a num, it is (floor)ed and the matching argument (starting from 0) is reproduced." + setup: (@i, ...) => @choices = { ... } update: (dt) => @i\update dt + i = @i\get! + for choice in *@choices choice\update dt - i = 1 + (math.floor @i\get!) % #@choices - @value = @choices[i]\get! + active = switch @i\get! + when true + @choices[1] + when false + @choices[2] + else + i = 1 + (math.floor i) % #@choices + @choices[i] + @value = active and active\get! + +class switch_pause extends Op + @doc: "(switch- i v0 [v1 v2...]) - switch and pause multiple inputs + +like (switch ...) except that the unused inputs are paused." + + setup: (@i, ...) => + @choices = { ... } + + update: (dt) => + @i\update dt + i = @i\get! + active = switch @i\get! + when true + @choices[1] + when false + @choices[2] + else + i = 1 + (math.floor i) % #@choices + @choices[i] + + @value = if active + active\update dt + active\get! + +class keep extends Op + @doc: "(keep value) - keep the last non-nil value + +always reproduces the last non-nil value the input produced" + + setup: (@i) => + + update: (dt) => + @i\update dt + + next = @i\get! + @value = next or @value { - :pick + 'switch': switch_ + 'switch-', switch_pause + :keep } |
