aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authors-ol <s-ol@users.noreply.github.com>2020-02-10 17:51:24 +0000
committers-ol <s-ol@users.noreply.github.com>2020-02-10 17:51:24 +0000
commit6c18ffdcc493bce6bfec4f5e64453ec7d6140253 (patch)
treebd3f3fe647a8ad66d7c77c918174a464389a70f3 /lib
parentclosures (diff)
downloadalive-6c18ffdcc493bce6bfec4f5e64453ec7d6140253.tar.gz
alive-6c18ffdcc493bce6bfec4f5e64453ec7d6140253.zip
add doc, import, import*, defn
Diffstat (limited to 'lib')
-rw-r--r--lib/builtin.moon175
-rw-r--r--lib/debug.moon2
-rw-r--r--lib/gui.moon4
-rw-r--r--lib/math.moon16
-rw-r--r--lib/osc.moon4
-rw-r--r--lib/string.moon18
-rw-r--r--lib/time.moon11
-rw-r--r--lib/util.moon62
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
}