aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2017-08-18 17:08:15 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2017-08-18 17:08:15 -0700
commitb2d49dde55522429f805590c40f96a95bfc67106 (patch)
treede07c02be2f4ecb256f84c9bbfe7f4216cb404f7
parent73051b34d9ea46710d1e36be4b867a50ccc01eac (diff)
Got rid of old versions.
-rwxr-xr-x[-rw-r--r--]core.moon208
-rwxr-xr-xcore2.moon230
-rwxr-xr-xgame1.moon416
-rwxr-xr-xgame2.moon317
-rw-r--r--nomic.moon372
-rw-r--r--nomic2.moon285
6 files changed, 662 insertions, 1166 deletions
diff --git a/core.moon b/core.moon
index d62cf9e..7155829 100644..100755
--- a/core.moon
+++ b/core.moon
@@ -18,23 +18,52 @@ repr = (x)->
else
tostring(x)
-game\def {[[print $str]], [[say $str]]}, (locals)=>
- with locals
- print(repr(.str))
- return nil
+game\def {[[print $str]], [[say $str]]}, (args)=> print(repr(args.str))
+game\def {[[printf $str]]}, (args)=>
+ for s in *args.str do io.write(repr(s))
+ io.write("\n")
+
+game\def [[return $value]], (args)=> args.value
+
+game\macro [[let $var = $value]], (var, value)->
+ "locals[#{var}] = #{value}"
+
+game\def [[$signature := $body]], (args)=>
+ invocations = if type(args.signature) == 'table' then args.signature else {args.signature}
+ for i in *invocations
+ unless @check_authorization(i)
+ print "You are not permitted to redefine this function"
+ return
+
+ @\def args.signature, args.body
+ print "Defined new rule: \"#{game.repr(args.signature)}\""
+ --print debug.getinfo(args.body, "S").source
+ return nil
-game\def [[$invocations := $body]], (locals)=>
- game\def locals.invocations, locals.body
+game\def [[compile $body]], (args)=>
+ print debug.getinfo(args.body, "S").source
return nil
-game\def [[help $invocation]], (locals)=>
- with locals
- if @rules[.invocation\gsub(" ",";")]
- print(@rules[.invocation\gsub(" ",";")])
+game\def [[help $invocation]], (args)=>
+ print_rule = (invocation, rule)->
+ print "\"#{invocation}\" :="
+ info = debug.getinfo(rule, "S")
+ i = 0
+ for line in info.source\gmatch("[^\n]+")
+ i+=1
+ if i >= info.linedefined+1
+ print(line)
+ if i >= info.lastlinedefined-1
+ return
+ print " #{info.short_src}:#{info.linedefined}-#{info.lastlinedefined}"
+
+ with args
+ if rule = @rules[.invocation]
+ print_rule .invocation, rule
return nil
words = [w for w in .invocation\gmatch("%S+")]
match_count = (i)->
- iws = [w for w in i\gmatch("[^;$]+")]
+ iws = [w for w in i\gmatch("[^ $]+")]
count = 0
for w in *words
for iw in *iws
@@ -42,26 +71,32 @@ game\def [[help $invocation]], (locals)=>
count += 1/#iws
return count
rules = {}
+ invocations = {}
for i,r in pairs(@rules)
- rules[r] = math.max((rules[r] or 0), match_count(i))
+ c = match_count(i)
+ if c > (rules[r] or 0)
+ rules[r] = c
+ invocations[r] = i
best = [r for r in pairs rules]
table.sort best, ((a,b)-> rules[a] > rules[b])
if rules[best[1]] > 0
for r in *best
if rules[r] < rules[best[1]]
break
- print("Closest match for \"#{.invocation}\" is:\n#{r}")
+ print_rule invocations[r], r
return nil
-
-game\def [[return $retval]], ((locals)=> locals.retval), "... returns the specified value ..."
-
-game\def {[[true]], [[yes]]}, ((locals)=> true), "... returns true ..."
-game\def {[[false]], [[no]]}, ((locals)=> false), "... returns false ..."
-game\def {[[nil]], [[None]], [[nop]], [[done]]}, ((locals)=> nil), "... does nothing, returns nil ..."
-
-game\def {[[$x == $y]], [[equal $x $y]]}, (locals)=>
- with locals
+game\macro "true", -> "true"
+game\macro "yes", -> "true"
+game\macro "false", -> "false"
+game\macro "no", -> "false"
+game\macro "nil", -> "nil"
+game\macro "None", -> "nil"
+game\macro "null", -> "nil"
+game\def [[nop]], ((args)=> nil), "... does nothing, returns nil ..."
+
+game\def [[$x == $y]], (args)=>
+ with args
if .x == .y then return true
if type(.x) != type(.y) then return false
if type(.x) != 'table' then return false
@@ -72,81 +107,124 @@ game\def {[[$x == $y]], [[equal $x $y]]}, (locals)=>
if .x[k] != v
return false
return true
-
-game\def [[not $x]], (locals)=> not locals.x
-game\run [["$x != $y" := {return (not (x == y))}]]
-game\def [[$x < $y]], (locals)=> locals.x < locals.y
-game\def [[$x <= $y]], (locals)=> locals.x <= locals.y
-game\def [[$x > $y]], (locals)=> locals.x > locals.y
-game\def [[$x >= $y]], (locals)=> locals.x >= locals.y
-
-game\def {[[$x + $y]], [[$x plus $y]]}, (locals)=> locals.x + locals.y
-game\def {[[$x - $y]], [[$x minus $y]]}, (locals)=> locals.x - locals.y
-game\def {[[$x * $y]], [[$x times $y]]}, (locals)=> locals.x * locals.y
-game\def {[[$x / $y]], [[$x divided by $y]]}, (locals)=> locals.x / locals.y
-game\def {[[$x ^ $y]], [[$x to the power of $y]]}, (locals)=> locals.x ^ locals.y
-
-
-game\def [[if $condition then $body else $else_body]], (locals)=>
- with locals
+game\run [=[
+ ["$x != $y", "$x <> $y", "$x ~= $y"] := {return (not (x == y))}
+]=]
+game\def [[$x < $y]], (args)=> args.x < args.y
+game\def [[$x <= $y]], (args)=> args.x <= args.y
+game\def [[$x > $y]], (args)=> args.x > args.y
+game\def [[$x >= $y]], (args)=> args.x >= args.y
+
+game\macro [[$x + $y]], (x,y)-> "(#{x} + #{y})"
+game\macro [[$x - $y]], (x,y)-> "(#{x} - #{y})"
+game\macro [[$x * $y]], (x,y)-> "(#{x} * #{y})"
+game\macro [[$x / $y]], (x,y)-> "(#{x} / #{y})"
+game\macro [[$x ^ $y]], (x,y)-> "(#{x} ^ #{y})"
+
+game\macro [[$x < $y]], (x,y)-> "(#{x} < #{y})"
+game\macro [[$x <= $y]], (x,y)-> "(#{x} <= #{y})"
+game\macro [[$x > $y]], (x,y)-> "(#{x} > #{y})"
+game\macro [[$x >= $y]], (x,y)-> "(#{x} >= #{y})"
+
+game\macro [[not $x]], (x)-> "(not #{x})"
+game\macro [[$x and $y]], (x,y)-> "(#{x} and #{y})"
+game\macro [[$x or $y]], (x,y)-> "(#{x} or #{y})"
+
+
+[==[
+game\def [[if $condition $body else $else_body]], (args)=>
+ with args
if .condition
- return .body\run(@, locals)
- else return .else_body\run(@, locals)
+ return .body(@, args)
+ else return .else_body(@, args)
-game\run [[
-["if $condition then $body", "when $condition do $body"] := {if $condition then $body else {}}
-]]
-game\run [[
-["unless $condition do $body"] := {if (not $condition) then $body else {}}
-]]
-game\run [[
-["unless $condition do $body else $else_body"] := {if (not $condition) then $body else $else_body}
-]]
+game\run [=[
+ ["if $condition $body", "when $condition $body"] := {if $condition $body else {}}
+ ["unless $condition $body"] := {if (not $condition) $body else {}}
+ ["unless $condition $body else $else_body"] := {if (not $condition) $body else $else_body}
+]=]
+]==]
+game\def [[random]], -> math.random()
-game\def [[sum $items]], (locals)=>
+game\def [[sum $items]], (args)=>
tot = 0
- for x in *locals.items do tot += x
+ for x in *args.items do tot += x
return tot
-game\def {[[average $items]], [[avg $items]]}, (locals)=>
+game\def [[all $items]], (args)=>
+ for x in *args.items
+ if not x then return false
+ return true
+
+game\def [[any $items]], (args)=>
+ for x in *args.items
+ if x then return true
+ return false
+
+game\def {[[average $items]], [[avg $items]]}, (args)=>
tot = 0
- for x in *locals.items do tot += x
- return tot / #locals.items
+ for x in *args.items do tot += x
+ return tot / #args.items
-game\def {[[min $items]], [[smallest $items]], [[lowest $items]], [[fewest $items]]}, (locals)=>
- with locals
+game\def {[[min $items]], [[smallest $items]], [[lowest $items]], [[fewest $items]]}, (args)=>
+ with args
min = .items[1]
for i=2,#.items
if .items[i] < min
min = .items[i]
return min
-game\def {[[max $items]], [[largest $items]], [[highest $items]], [[most $items]]}, (locals)=>
- with locals
+game\def {[[max $items]], [[largest $items]], [[highest $items]], [[most $items]]}, (args)=>
+ with args
max = .items[1]
for i=2,#.items
if .items[i] > max
max = .items[i]
return max
-game\def {[[argmin $items]]}, (locals)=>
- with locals
+game\def {[[argmin $items]]}, (args)=>
+ with args
min = .items[1]
for i=2,#.items
if .items[i][2] < min[2]
min = .items[i]
return min
-game\def {[[argmax $items]]}, (locals)=>
- with locals
+game\def {[[argmax $items]]}, (args)=>
+ with args
max = .items[1]
for i=2,#.items
if .items[i][2] > max[2]
max = .items[i]
return max
-game\def {[[$index st in $list]], [[$index nd in $list]], [[$index rd in $list]], [[$index th in $list]]}, (locals)=>
- locals.list[locals.index]
+game\def {[[$index st in $list]], [[$index nd in $list]], [[$index rd in $list]], [[$index th in $list]]}, (args)=>
+ with args
+ if type(.list) != 'table'
+ print "Not a list: #{.list}"
+ return
+ .list[.index]
+
+game\def {[[index of $item in $list]]}, (args)=>
+ with args
+ if type(.list) != 'table'
+ print "Not a list: #{.list}"
+ return
+ for i,x in ipairs .list
+ if x == .item
+ return i
+ return nil
+game\run [=[
+ ["$item is in $list", "$list contains $item"] := {(index of $item in $list) != (nil)}
+]=]
+
+game\def {[[# $list]], [[length of $list]], [[size of $list]]}, (args)=>
+ with args
+ if type(.list) != 'table'
+ print "Not a list: #{.list}"
+ return
+ #.list
+
return game
diff --git a/core2.moon b/core2.moon
deleted file mode 100755
index 6298426..0000000
--- a/core2.moon
+++ /dev/null
@@ -1,230 +0,0 @@
-#!/usr/bin/env moon
-nomic = require 'nomic2'
-game = nomic()
-
-is_list = (t)->
- i = 0
- for _ in pairs(t)
- i += 1
- if t[i] == nil then return false
- return true
-
-repr = (x)->
- if type(x) == 'table'
- if is_list x
- "[#{table.concat([repr(i) for i in *x], ", ")}]"
- else
- "{#{table.concat(["#{k}: #{v}" for k,v in pairs x], ", ")}}"
- else
- tostring(x)
-
-game\def {[[print $str]], [[say $str]]}, (args)=> print(repr(args.str))
-game\def {[[printf $str]]}, (args)=>
- for s in *args.str do io.write(repr(s))
- io.write("\n")
-
-game\def [[return $value]], (args)=> args.value
-
-game\macro [[let $var = $value]], (var, value)->
- "locals[#{var}] = #{value}"
-
-game\def [[$signature := $body]], (args)=>
- invocations = if type(args.signature) == 'table' then args.signature else {args.signature}
- for i in *invocations
- unless @check_authorization(i)
- print "You are not permitted to redefine this function"
- return
-
- @\def args.signature, args.body
- print "Defined new rule: \"#{game.repr(args.signature)}\""
- --print debug.getinfo(args.body, "S").source
- return nil
-
-game\def [[compile $body]], (args)=>
- print debug.getinfo(args.body, "S").source
- return nil
-
-game\def [[help $invocation]], (args)=>
- print_rule = (invocation, rule)->
- print "\"#{invocation}\" :="
- info = debug.getinfo(rule, "S")
- i = 0
- for line in info.source\gmatch("[^\n]+")
- i+=1
- if i >= info.linedefined+1
- print(line)
- if i >= info.lastlinedefined-1
- return
- print " #{info.short_src}:#{info.linedefined}-#{info.lastlinedefined}"
-
- with args
- if rule = @rules[.invocation]
- print_rule .invocation, rule
- return nil
- words = [w for w in .invocation\gmatch("%S+")]
- match_count = (i)->
- iws = [w for w in i\gmatch("[^ $]+")]
- count = 0
- for w in *words
- for iw in *iws
- if w == iw then count += 1
- count += 1/#iws
- return count
- rules = {}
- invocations = {}
- for i,r in pairs(@rules)
- c = match_count(i)
- if c > (rules[r] or 0)
- rules[r] = c
- invocations[r] = i
- best = [r for r in pairs rules]
- table.sort best, ((a,b)-> rules[a] > rules[b])
- if rules[best[1]] > 0
- for r in *best
- if rules[r] < rules[best[1]]
- break
- print_rule invocations[r], r
- return nil
-
-game\macro "true", -> "true"
-game\macro "yes", -> "true"
-game\macro "false", -> "false"
-game\macro "no", -> "false"
-game\macro "nil", -> "nil"
-game\macro "None", -> "nil"
-game\macro "null", -> "nil"
-game\def [[nop]], ((args)=> nil), "... does nothing, returns nil ..."
-
-game\def [[$x == $y]], (args)=>
- with args
- if .x == .y then return true
- if type(.x) != type(.y) then return false
- if type(.x) != 'table' then return false
- for k,v in pairs(.x)
- if .y[k] != v
- return false
- for k,v in pairs(.y)
- if .x[k] != v
- return false
- return true
-game\run [=[
- ["$x != $y", "$x <> $y", "$x ~= $y"] := {return (not (x == y))}
-]=]
-game\def [[$x < $y]], (args)=> args.x < args.y
-game\def [[$x <= $y]], (args)=> args.x <= args.y
-game\def [[$x > $y]], (args)=> args.x > args.y
-game\def [[$x >= $y]], (args)=> args.x >= args.y
-
-game\macro [[$x + $y]], (x,y)-> "(#{x} + #{y})"
-game\macro [[$x - $y]], (x,y)-> "(#{x} - #{y})"
-game\macro [[$x * $y]], (x,y)-> "(#{x} * #{y})"
-game\macro [[$x / $y]], (x,y)-> "(#{x} / #{y})"
-game\macro [[$x ^ $y]], (x,y)-> "(#{x} ^ #{y})"
-
-game\macro [[$x < $y]], (x,y)-> "(#{x} < #{y})"
-game\macro [[$x <= $y]], (x,y)-> "(#{x} <= #{y})"
-game\macro [[$x > $y]], (x,y)-> "(#{x} > #{y})"
-game\macro [[$x >= $y]], (x,y)-> "(#{x} >= #{y})"
-
-game\macro [[not $x]], (x)-> "(not #{x})"
-game\macro [[$x and $y]], (x,y)-> "(#{x} and #{y})"
-game\macro [[$x or $y]], (x,y)-> "(#{x} or #{y})"
-
-
-[==[
-game\def [[if $condition $body else $else_body]], (args)=>
- with args
- if .condition
- return .body(@, args)
- else return .else_body(@, args)
-
-game\run [=[
- ["if $condition $body", "when $condition $body"] := {if $condition $body else {}}
- ["unless $condition $body"] := {if (not $condition) $body else {}}
- ["unless $condition $body else $else_body"] := {if (not $condition) $body else $else_body}
-]=]
-]==]
-
-game\def [[random]], -> math.random()
-
-game\def [[sum $items]], (args)=>
- tot = 0
- for x in *args.items do tot += x
- return tot
-
-game\def [[all $items]], (args)=>
- for x in *args.items
- if not x then return false
- return true
-
-game\def [[any $items]], (args)=>
- for x in *args.items
- if x then return true
- return false
-
-game\def {[[average $items]], [[avg $items]]}, (args)=>
- tot = 0
- for x in *args.items do tot += x
- return tot / #args.items
-
-game\def {[[min $items]], [[smallest $items]], [[lowest $items]], [[fewest $items]]}, (args)=>
- with args
- min = .items[1]
- for i=2,#.items
- if .items[i] < min
- min = .items[i]
- return min
-
-game\def {[[max $items]], [[largest $items]], [[highest $items]], [[most $items]]}, (args)=>
- with args
- max = .items[1]
- for i=2,#.items
- if .items[i] > max
- max = .items[i]
- return max
-
-game\def {[[argmin $items]]}, (args)=>
- with args
- min = .items[1]
- for i=2,#.items
- if .items[i][2] < min[2]
- min = .items[i]
- return min
-
-game\def {[[argmax $items]]}, (args)=>
- with args
- max = .items[1]
- for i=2,#.items
- if .items[i][2] > max[2]
- max = .items[i]
- return max
-
-game\def {[[$index st in $list]], [[$index nd in $list]], [[$index rd in $list]], [[$index th in $list]]}, (args)=>
- with args
- if type(.list) != 'table'
- print "Not a list: #{.list}"
- return
- .list[.index]
-
-game\def {[[index of $item in $list]]}, (args)=>
- with args
- if type(.list) != 'table'
- print "Not a list: #{.list}"
- return
- for i,x in ipairs .list
- if x == .item
- return i
- return nil
-game\run [=[
- ["$item is in $list", "$list contains $item"] := {(index of $item in $list) != (nil)}
-]=]
-
-game\def {[[# $list]], [[length of $list]], [[size of $list]]}, (args)=>
- with args
- if type(.list) != 'table'
- print "Not a list: #{.list}"
- return
- #.list
-
-
-return game
diff --git a/game1.moon b/game1.moon
index 0f40053..11bc8ce 100755
--- a/game1.moon
+++ b/game1.moon
@@ -1,169 +1,317 @@
#!/usr/bin/env moon
Game = require 'nomic'
core_game = require 'core'
-game = Game(core_game)
-
------------------- BASIC TESTS ---------------------
-game\run [=[
-
-say "=========== INITIALIZING GAME ============"
-
-"fart" := {say "poot"}
-fart
-
-"fart twice" := {
- fart
- fart
-}
-
-fart twice
-
-["greet", "say hello"] := { say "Hello!" }
-
-greet
-
-say (return "returned value")
-say 6
-say -6
-say []
-say [1,2,3,4]
-say [[1,2],[3,[4,5]]]
-say (sum [1,2,3,4])
-help "fart"
-help "fart twice"
+game = Game(core_game)
-"fart thrice" := {
- fart
- fart
- fart
+game\def "# $key $relation = $value", (args)=>
+ --print "Setting #{args.key} #{args.relation} = #{args.value}"
+ @relations[args.relation][args.key] = args.value
+ return args.value
+
+game\def "set all * $relation = $value", (args)=>
+ rels = @relations[args.relation]
+ for k,_ in pairs rels
+ rels[k] = args.value
+ if next(rels) == nil
+ @relations[args.relation] = nil
+ return args.value
+
+game\def "$key $relation ?", (args)=>
+ return @relations[args.relation][args.key]
+
+deep_pairs = (t)->
+ coroutine.wrap ->
+ for k,v in pairs(t)
+ coroutine.yield k, v
+ mt = getmetatable(t)
+ return unless mt and mt.__index and type(mt.__index) == 'table' and mt.__index != t
+ for k,v in deep_pairs mt.__index
+ if t[k] == nil
+ coroutine.yield k,v
+
+game\def "* $relation = $value", (args)=>
+ --print "Finding all * #{args.relation} = #{args.value}"
+ [key for key, value in deep_pairs(@relations[args.relation]) when value == args.value]
+
+game\def {"restrict $actions to $whitelist"}, (args)=>
+ with args
+ actions = @canonicalize(if type(.actions) == 'table' then .actions else {.actions})
+ whitelist = @all_aliases(if type(.whitelist) == 'table' then .whitelist else {.whitelist})
+ @\set_whitelist actions, whitelist
+ for action in *actions
+ print("Restricting #{Game.repr(action)} to #{Game.repr(whitelist)}")
+
+game\def {"permit $whitelist to $actions"}, (args)=>
+ with args
+ actions = @canonicalize(if type(.actions) == 'table' then .actions else {.actions})
+ whitelist = @all_aliases(if type(.whitelist) == 'table' then .whitelist else {.whitelist})
+ for action in *actions
+ if not @authorized[action]
+ print "#{action} is already available to everyone."
+ continue
+ print("Permitting #{Game.repr(action)} to #{Game.repr(whitelist)}")
+ for w in *whitelist
+ @authorized[action][w] = true
+
+game\def {"revoke $actions rights from $whitelist"}, (args)=>
+ with args
+ actions = @canonicalize(if type(.actions) == 'table' then .actions else {.actions})
+ whitelist = @all_aliases(if type(.whitelist) == 'table' then .whitelist else {.whitelist})
+ for action in *actions
+ if not @authorized[action]
+ print "#{action} is available to everyone, it can't be restricted."
+ continue
+ print("Revoking the right of #{Game.repr(action)} to use #{Game.repr(whitelist)}")
+ for w in *whitelist
+ @authorized[action][w] = nil
+
+game\def "print callstack", (args)=>
+ print("Callstack:")
+ for fn in *@callstack
+ print fn
+
+game\def {"do $action"}, (args)=>
+ (args.action)(@, {})
+
+game\def {"make $who $action"}, (args)=>
+ with args
+ old_you = @you
+ print("Setting you=#{.who}")
+ rawset(@, "you", .who)
+ (.action)(@, {})
+ rawset(@, "you", old_you)
+
+game\def "you", (args)=> @you
+
+game\run[=[
+say "===================================================="
+say " NEW GAME"
+say "===================================================="
+"everyone approves $action" := {yes}
+
+"sudo $action" := {
+ if (everyone approves $action) {
+ do $action
+ } else {
+ say "You do not have the will of the people! >:("
+ }
}
-help "fart lol"
-help "yes"
-
-"five" := {return 5}
-say (6 times 6)
-"fitz" := {say (return 99)}
-fitz
-"bazwiz $x" := {say (sum $x)}
-bazwiz [10,20,30]
-"foobar $x" := {say (return $x)}
-foobar 55
-
-"$x squared" := {$x times $x}
-"$x plus one" := {$x + 1}
-"$x foo" := {($x * $x) + 1}
-say (5 foo)
-
-say (1 st in [1,2,3,4,5])
-say (2 nd in [1,2,3,4,5])
-say (3 rd in [1,2,3,4,5])
-say (4 th in [1,2,3,4,5])
-
-]=]
-
-game\def [[you]], (_)=> @you
-game\run [[you]]
-game\run [[say (you)]]
-
-game\run [[
- "five" := {return 5}
-]]
-game\run [[say (five)]]
-game\def [[$x squared]], (locals)=> locals.x^2
-game\run [[say ((five) squared)]]
+restrict "$ := $" to "sudo $"
+restrict "make $ $" to "sudo $"
+restrict "set all * $ = $" to "sudo $"
+restrict "# $ $ = $" to "sudo $"
+restrict "restrict $ to $" to "sudo $"
+
+sudo {
+ "propose $action" := {
+ if ("pending proposal" "is" ?) {
+ say "Sorry, an action is already pending."
+ } else {
+ say "Proposing..."
+ # "pending proposal" "is" = $action
+ }
+ }
+ "unpropose" := {
+ let "pending" = ("pending proposal" "is" ?)
+ set all * $pending = (nil)
+ # "pending proposal" "is" = (nil)
+ }
-game\def [[remember that $key $relation $value]], (locals)=>
- with locals
- assert .relation, "no relation!!"
- if not @relations[.relation] then @relations[.relation] = {}
- @relations[.relation][.key] = .value
- return nil
+ "mark $who as approving $action" := {
+ # $who $action = "approved"
+ }
-game\run [[
- "remember that $key $relation" := {remember that $key $relation (true)}
-]]
+ "mark $who as rejecting $action" := {
+ # $who $action = "rejected"
+ }
-game\def [[forget about $key $relation]], (locals)=>
- with locals
- if not @relations[.relation] then @relations[.relation] = {}
- @relations[.relation][.key] = nil
- return nil
+ ["approve", "vote yes", "vote yea"] := {
+ let "pending" = ("pending proposal" "is" ?)
+ mark (you) as approving $pending
+ say "Voted yes."
+ if (everyone approves $pending) {
+ sudo $pending
+ unpropose
+ }
+ }
-game\def [[the value of $key $relation]], (locals)=>
- with locals
- return (@relations[.relation] or {})[.key]
+ ["reject", "vote no", "vote nay", "veto", "disapprove"] := {
+ let "pending" = ("pending proposal" "is" ?)
+ mark (you) as rejecting $pending
+ say "Voted no."
+ unpropose
+ }
-game\run [["it is true that $key $relation $value" := {(the value of $key $relation) == $value}]]
-game\run [["it is true that $key $relation" := {(the value of $key $relation) == (true)}]]
+ ["players", "everyone", "everybody", "all players"] := {
+ * "is a player" = (yes)
+ }
-game\run[[
- remember that "socrates" "is mortal"
- say (it is true that "socrates" "is mortal"))
-]]
+ "join" := {
+ # (you) "is a player" = (yes)
+ printf ["Welcome to the game, ",(you),"!"]
+ }
+ permit "unpropose" to "set all * $ = $"
+ permit ["join", "mark $ as approving $", "mark $ as rejecting $", "propose $", "unpropose"] to "# $ $ = $"
+ restrict "unpropose" to ["approve", "reject"]
+ restrict "mark $ as approving $" to ["propose $", "approve"]
+ restrict "mark $ as rejecting $" to ["propose $", "reject"]
+
+ "everyone approves $action" := {
+ (# (players)) == (# (* $action = "approved"))
+ }
+}
+join
-game\run [[remember that "socrates" "is mortal"]]
-game\run [[say (the value of "socrates" "is mortal")]]
+propose {
+ say "fart"
+}
+approve
-game\def [[all keys where $relation is $value]], (locals)=>
- with locals
- result = {}
- for k,v in pairs(@relations[.relation] or {})
- if v == .value
- table.insert(result, k)
- return result
+"cheat" := {
+ say "CHEATER!!!"
+}
+sudo {
+ say "CHEATER!!!"
+}
-game\run [[if (1 == 1) then {say "Affirmative"} else {say "Negatory"}]]
-game\run [[if (1 == 2) then {say "Affirmative"} else {say "Negatory"}]]
-game\run [[if (1 == 2) then {say "Affirmative"}]]
+propose {
+ # "democracy" "is possible" = (yes)
+ if ("democracy" "is possible" ?) {
+ say "DEMOCRACY WORKS!!!"
+ }
+}
+approve
-game\run [[say (if (1 == 1) then {return "Ternary yes"} else {return "Ternary no"})]]
+propose {
+ "fart" := {
+ say "poot"
+ }
+}
+approve
+fart
-game\run [["$who is a member" := {return (it is true that $who "is a member")}]]
-game\run [["you are a member" := {return ((you) is a member)}]]
-game\run [[say (you are a member)]]
+propose {
+ "open election $candidates" := {
+ if ("candidates" "are" ?) {
+ say "An election is already in progress."
+ } else {
+ # "candidates" "are" = $candidates
+ }
+ }
-game\run [[
- if (you are a member) then {say "youre a member!"} else {say "youre not a member"}
-]]
+ "close election" := {
+ let "pending" = ("pending proposal" "is" ?)
+ set all * "votes for" = (nil)
+ # "candidates" "are" = (nil)
+ }
+ "vote for $candidate" := {
+ # (you) "votes for" = $candidate
+ let "vote-percent" = ((# (* "votes for" = $candidate)) / (# (players)))
+ printf ["Vote cast. ",$candidate," now has ",(100 * $vote-percent),"% of the votes."]
+ if ($vote-percent > 0.5) {
+ printf ["The winner of the election is:", $candidate]
+ close election
+ }
+ }
+ permit ["open election $", "close election", "vote for $"] to ["# $ $ = $"]
+ permit ["close election"] to ["set all * $ = $"]
+}
+approve
+
+propose {
+ "as bill: $action" := {
+ if ((you) == "Anonymous") {
+ make "bill" $action
+ } else {
+ printf ["Who do you think you are?", (you)]
+ }
+ }
+ permit ["as bill: $"] to ["make $ $"]
+}
+approve
+as bill: {join}
+
+propose {
+ "as dave: $action" := {
+ if ((you) == "Anonymous") {
+ make "dave" $action
+ } else {
+ printf ["Who do you think you are?", (you)]
+ }
+ }
+ permit ["as dave: $"] to ["make $ $"]
+}
+approve
+as bill: {approve}
+as dave: {join}
+open election ["tom", "dick", "harry"]
+vote for "dick"
+as bill: {vote for "dick"}
-[[
-def: $who is a member
- return it is true that $who "is a member"
+propose {
+ "take a shit" := {say "shit taken."}
+}
+approve
+as bill: {approve}
+as dave: {approve}
-def: you are a member
- return (you) is a member
-def: members
-alias: all members
- return all keys where "is a member" is "yes"
-def: let $someone join
- if (you are a member) then {
- remember that $someone "is a member"
+sudo {
+ "everyone approves" := {
+ (# (players)) == (# (* "votes" (yes)))
+ }
+ ["approve", "vote yes", "vote yea"] := {
+ # (you) "votes" = (yes)
+ if (everyone approves) {
+ do pending action
+ }
+ }
+ ["disapprove", "vote no", "vote nay", "veto"] := {
+ say "The proposal has failed."
+ # (you) "approves" = (yes)
+ if (everyone approves) {
+ do pending action
+ }
}
+}
-def: propose $def
- if (you are a member) then {
- remember that $def "is pending"
- vote yes on $def
+sudo {
+ "everyone approves" := {
+ say "Going into this code"
+ no
}
+}
+sudo {
+ say "BROKEN"
+}
-def: make $voter vote yes on $def
-alias: make $voter approve $def
- remember $def "is approved by" $voter
- if ((all members) == (all $def "is approved by" ?)) then {
- forget $def "is approved by" ?
- add def $def
+
+propose {
+ "arbitrarily define $signature := $body" := {
+ if ($signature == "butts") {
+ $signature := $body
+ } else {
+ say "Not my style."
+ }
}
+ permit "arbitrarily define $ := $" to "$ := $"
+ say "Arbitrary is a go."
+}
+as bill: {approve}
+as dave: {approve}
+approve
+arbitrarily define "butts" := {say "BUTTS"}
+butts
-def: vote yes on $def
- make (you) vote yes on $def
+arbitrarily define "ass" := {say "ASS"}
+ass
-]]
+]=]
diff --git a/game2.moon b/game2.moon
deleted file mode 100755
index 4227faa..0000000
--- a/game2.moon
+++ /dev/null
@@ -1,317 +0,0 @@
-#!/usr/bin/env moon
-Game = require 'nomic2'
-core_game = require 'core2'
-
-game = Game(core_game)
-
-game\def "# $key $relation = $value", (args)=>
- --print "Setting #{args.key} #{args.relation} = #{args.value}"
- @relations[args.relation][args.key] = args.value
- return args.value
-
-game\def "set all * $relation = $value", (args)=>
- rels = @relations[args.relation]
- for k,_ in pairs rels
- rels[k] = args.value
- if next(rels) == nil
- @relations[args.relation] = nil
- return args.value
-
-game\def "$key $relation ?", (args)=>
- return @relations[args.relation][args.key]
-
-deep_pairs = (t)->
- coroutine.wrap ->
- for k,v in pairs(t)
- coroutine.yield k, v
- mt = getmetatable(t)
- return unless mt and mt.__index and type(mt.__index) == 'table' and mt.__index != t
- for k,v in deep_pairs mt.__index
- if t[k] == nil
- coroutine.yield k,v
-
-game\def "* $relation = $value", (args)=>
- --print "Finding all * #{args.relation} = #{args.value}"
- [key for key, value in deep_pairs(@relations[args.relation]) when value == args.value]
-
-game\def {"restrict $actions to $whitelist"}, (args)=>
- with args
- actions = @canonicalize(if type(.actions) == 'table' then .actions else {.actions})
- whitelist = @all_aliases(if type(.whitelist) == 'table' then .whitelist else {.whitelist})
- @\set_whitelist actions, whitelist
- for action in *actions
- print("Restricting #{Game.repr(action)} to #{Game.repr(whitelist)}")
-
-game\def {"permit $whitelist to $actions"}, (args)=>
- with args
- actions = @canonicalize(if type(.actions) == 'table' then .actions else {.actions})
- whitelist = @all_aliases(if type(.whitelist) == 'table' then .whitelist else {.whitelist})
- for action in *actions
- if not @authorized[action]
- print "#{action} is already available to everyone."
- continue
- print("Permitting #{Game.repr(action)} to #{Game.repr(whitelist)}")
- for w in *whitelist
- @authorized[action][w] = true
-
-game\def {"revoke $actions rights from $whitelist"}, (args)=>
- with args
- actions = @canonicalize(if type(.actions) == 'table' then .actions else {.actions})
- whitelist = @all_aliases(if type(.whitelist) == 'table' then .whitelist else {.whitelist})
- for action in *actions
- if not @authorized[action]
- print "#{action} is available to everyone, it can't be restricted."
- continue
- print("Revoking the right of #{Game.repr(action)} to use #{Game.repr(whitelist)}")
- for w in *whitelist
- @authorized[action][w] = nil
-
-game\def "print callstack", (args)=>
- print("Callstack:")
- for fn in *@callstack
- print fn
-
-game\def {"do $action"}, (args)=>
- (args.action)(@, {})
-
-game\def {"make $who $action"}, (args)=>
- with args
- old_you = @you
- print("Setting you=#{.who}")
- rawset(@, "you", .who)
- (.action)(@, {})
- rawset(@, "you", old_you)
-
-game\def "you", (args)=> @you
-
-game\run[=[
-say "===================================================="
-say " NEW GAME"
-say "===================================================="
-"everyone approves $action" := {yes}
-
-"sudo $action" := {
- if (everyone approves $action) {
- do $action
- } else {
- say "You do not have the will of the people! >:("
- }
-}
-restrict "$ := $" to "sudo $"
-restrict "make $ $" to "sudo $"
-restrict "set all * $ = $" to "sudo $"
-restrict "# $ $ = $" to "sudo $"
-restrict "restrict $ to $" to "sudo $"
-
-sudo {
- "propose $action" := {
- if ("pending proposal" "is" ?) {
- say "Sorry, an action is already pending."
- } else {
- say "Proposing..."
- # "pending proposal" "is" = $action
- }
- }
- "unpropose" := {
- let "pending" = ("pending proposal" "is" ?)
- set all * $pending = (nil)
- # "pending proposal" "is" = (nil)
- }
-
-
- "mark $who as approving $action" := {
- # $who $action = "approved"
- }
-
- "mark $who as rejecting $action" := {
- # $who $action = "rejected"
- }
-
- ["approve", "vote yes", "vote yea"] := {
- let "pending" = ("pending proposal" "is" ?)
- mark (you) as approving $pending
- say "Voted yes."
- if (everyone approves $pending) {
- sudo $pending
- unpropose
- }
- }
-
- ["reject", "vote no", "vote nay", "veto", "disapprove"] := {
- let "pending" = ("pending proposal" "is" ?)
- mark (you) as rejecting $pending
- say "Voted no."
- unpropose
- }
-
- ["players", "everyone", "everybody", "all players"] := {
- * "is a player" = (yes)
- }
-
- "join" := {
- # (you) "is a player" = (yes)
- printf ["Welcome to the game, ",(you),"!"]
- }
- permit "unpropose" to "set all * $ = $"
- permit ["join", "mark $ as approving $", "mark $ as rejecting $", "propose $", "unpropose"] to "# $ $ = $"
- restrict "unpropose" to ["approve", "reject"]
- restrict "mark $ as approving $" to ["propose $", "approve"]
- restrict "mark $ as rejecting $" to ["propose $", "reject"]
-
- "everyone approves $action" := {
- (# (players)) == (# (* $action = "approved"))
- }
-}
-
-join
-
-propose {
- say "fart"
-}
-approve
-
-
-"cheat" := {
- say "CHEATER!!!"
-}
-sudo {
- say "CHEATER!!!"
-}
-
-propose {
- # "democracy" "is possible" = (yes)
- if ("democracy" "is possible" ?) {
- say "DEMOCRACY WORKS!!!"
- }
-}
-approve
-
-propose {
- "fart" := {
- say "poot"
- }
-}
-approve
-fart
-
-propose {
- "open election $candidates" := {
- if ("candidates" "are" ?) {
- say "An election is already in progress."
- } else {
- # "candidates" "are" = $candidates
- }
- }
-
- "close election" := {
- let "pending" = ("pending proposal" "is" ?)
- set all * "votes for" = (nil)
- # "candidates" "are" = (nil)
- }
-
- "vote for $candidate" := {
- # (you) "votes for" = $candidate
- let "vote-percent" = ((# (* "votes for" = $candidate)) / (# (players)))
- printf ["Vote cast. ",$candidate," now has ",(100 * $vote-percent),"% of the votes."]
- if ($vote-percent > 0.5) {
- printf ["The winner of the election is:", $candidate]
- close election
- }
- }
-
- permit ["open election $", "close election", "vote for $"] to ["# $ $ = $"]
- permit ["close election"] to ["set all * $ = $"]
-}
-approve
-
-propose {
- "as bill: $action" := {
- if ((you) == "Anonymous") {
- make "bill" $action
- } else {
- printf ["Who do you think you are?", (you)]
- }
- }
- permit ["as bill: $"] to ["make $ $"]
-}
-approve
-as bill: {join}
-
-propose {
- "as dave: $action" := {
- if ((you) == "Anonymous") {
- make "dave" $action
- } else {
- printf ["Who do you think you are?", (you)]
- }
- }
- permit ["as dave: $"] to ["make $ $"]
-}
-approve
-as bill: {approve}
-as dave: {join}
-
-open election ["tom", "dick", "harry"]
-vote for "dick"
-as bill: {vote for "dick"}
-
-propose {
- "take a shit" := {say "shit taken."}
-}
-approve
-as bill: {approve}
-as dave: {approve}
-
-
-
-sudo {
- "everyone approves" := {
- (# (players)) == (# (* "votes" (yes)))
- }
- ["approve", "vote yes", "vote yea"] := {
- # (you) "votes" = (yes)
- if (everyone approves) {
- do pending action
- }
- }
- ["disapprove", "vote no", "vote nay", "veto"] := {
- say "The proposal has failed."
- # (you) "approves" = (yes)
- if (everyone approves) {
- do pending action
- }
- }
-}
-
-sudo {
- "everyone approves" := {
- say "Going into this code"
- no
- }
-}
-sudo {
- say "BROKEN"
-}
-
-
-propose {
- "arbitrarily define $signature := $body" := {
- if ($signature == "butts") {
- $signature := $body
- } else {
- say "Not my style."
- }
- }
- permit "arbitrarily define $ := $" to "$ := $"
- say "Arbitrary is a go."
-}
-as bill: {approve}
-as dave: {approve}
-approve
-arbitrarily define "butts" := {say "BUTTS"}
-butts
-
-arbitrarily define "ass" := {say "ASS"}
-ass
-
-]=]
diff --git a/nomic.moon b/nomic.moon
index cca67e0..2a03080 100644
--- a/nomic.moon
+++ b/nomic.moon
@@ -3,173 +3,273 @@ lpeg = require 'lpeg'
moon = require 'moon'
type = moon.type
+is_list = (t)->
+ i = 0
+ for _ in pairs(t)
+ i += 1
+ if t[i] == nil then return false
+ return true
+
+repr = (x)->
+ if type(x) == 'table'
+ if is_list x
+ "[#{table.concat([repr(i) for i in *x], ", ")}]"
+ else
+ "{#{table.concat(["#{k}: #{v}" for k,v in pairs x], ", ")}}"
+ else
+ tostring(x)
+
currently_parsing = nil
+macros = nil
+indentation = 0
+indents = ->
+ (" ")\rep(indentation)
+indent = ->
+ export indentation
+ indentation += 1
+dedent = ->
+ export indentation
+ indentation -= 1
+indent_block = (block)->
+ block = block\gsub("\n", "\n"..indents!)
+ return indents!..block
+add_line = (lines, new_line)->
+ table.insert lines, (indents!..new_line)
-as_value = (x, game, locals)->
- assert (game and locals), "Shit's fucked"
- if type(x) == 'number' or type(x) == 'string' or type(x) == 'table'
- return x
- ret = x\as_value game, locals
- return ret
-
-class Var
- new:(@name)=>
- as_value:(game, locals)=>
- if locals[@name] == nil
- error("Attempt to access undefined variable: #{@name}")
- locals[@name]
- __tostring:=> "Var(#{@text})"
-
-class Word
- new:(@text)=>
- __tostring:=> "Word(#{@text})"
-
-class Action
- new:(tokens)=>
- words = [(if type(t) == Word then t.text else "$") for t in *tokens]
- @name = table.concat(words, ";")
- @args = [t for t in *tokens when type(t) != Word]
-
- __tostring:=> "Action(#{@name})"
-
- as_value:(game, locals)=>
- assert((game and locals), "f'd up")
- ret = @\run game, locals
- return ret
+compactify_invocation = (raw_invocation)->
+ name_bits = {}
+ arg_names = {}
+ for chunk in raw_invocation\gmatch("%S+")
+ if chunk\sub(1,1) == "$"
+ table.insert name_bits, "$"
+ table.insert arg_names, chunk\sub(2,-1)
+ else
+ table.insert name_bits, chunk
+ invocation = table.concat name_bits, " "
+ return invocation, arg_names
- run:(game, locals)=>
- assert((game and locals), "f'd up")
- rule = game.rules[@name]
- unless rule
- error("Tried to run rule, but couldn't find: #{@name}")
- arg_names = rule.arg_names
- new_locals = {}
- for i, arg in ipairs(@args)
- new_locals[arg_names[i]] = as_value(arg, game, locals)
-
- ret = rule.fn(game, new_locals)
- return ret
+Number = (s)-> s
-class Thunk
- new:(@actions, @body_str)=>
- if @actions.startPos
- assert currently_parsing, "Not currently parsing!"
- unless @body_str
- @body_str = currently_parsing\sub(@actions.startPos, @actions.endPos-1)
+String = (s)-> '"'..s..'"'
- as_value:=>@
+List = (t)-> "{" .. table.concat(t, ", ") .. "}"
- run:(game, locals)=>
- assert((game and locals), "f'd up")
- ret = nil
- for a in *@actions
- ret = a\run game,locals
- return ret
+Var = (s)-> "locals[\"#{s}\"]"
+
+Word = (s)-> setmetatable({type:'word', text:s}, {__tostring:=> error("Cannot convert word \"#{@text}\" to string")})
+
+Conditional = (condition, if_block, else_block)->
+ ret = {}
+ add_line ret, "(function()"
+ indent!
+ add_line ret, "local ret"
+ table.insert ret, indent_block("local condition = #{condition}")
- __tostring:=>
- --"Thunk(#{table.concat([tostring(a) for a in *@actions], ", ") .. tostring(@actions.returnValue or "") })"
- "{#{@body_str}}"
+ add_line ret, "if condition then"
+ indent!
+ table.insert ret, indent_block("ret = (#{if_block})(game, locals)")
+ if else_block
+ dedent!
+ add_line ret, "else"
+ indent!
+ table.insert ret, indent_block("ret = (#{else_block})(game, locals)")
+ dedent!
+ add_line ret, "end"
+ add_line ret, "return ret"
+ dedent!
+ add_line ret, "end)()"
+ code = table.concat(ret, "\n")
+ return code
+
+FunctionCall = (tokens)->
+ words = [(if t.type == 'word' then t.text else "$") for t in *tokens]
+ args = [t for t in *tokens when t.type != 'word']
+ rule_name = table.concat(words, " ")
+ if rule_name == "$"
+ error("Empty rule: #{repr(tokens)}")
+
+ if macros[rule_name]
+ return macros[rule_name](unpack(args))
+
+ if #args == 0
+ return indent_block("game:call(\"#{rule_name}\")")
+
+ ret = {}
+ add_line ret, "game:call(\"#{rule_name}\","
+ indent!
+ arg_strs = [indent_block(arg) for arg in *args]
+ dedent!
+ table.insert ret, table.concat(arg_strs, ",\n")
+ add_line ret, ")"
+
+ code = table.concat(ret, "\n")
+ return code
+
+Thunk = (lines)->
+ ret = {}
+ add_line ret, "function(game, locals)"
+ indent!
+ for i,line in ipairs lines
+ if line\match "locals%[\".*\"%] = .*"
+ table.insert ret, indent_block(line)
+ elseif i == #lines
+ table.insert ret, indent_block("return "..line..";")
+ else
+ table.insert ret, indent_block(line..";")
+ dedent!
+ add_line ret, "end"
+ return table.concat(ret, "\n")
lingo = [[
actions <- {| {:startPos: {}:} (%ws*) (%nl %ws*)* (action ((%nl %ws*)+ action)*)? (%nl %ws*)* {:endPos: {}:} |} -> Thunk
- action <- {| token (%ws+ token)* %ws* |} -> Action
+ action <- (&conditional conditional) / ({| token (%ws+ token)* %ws* |} -> FunctionCall)
+ conditional <- ("if" !%wordchars %ws* expression %ws* thunk (%ws* "else" %ws* thunk %ws*)?) -> Conditional
token <- expression / (!"$" {%wordchars+} -> Word)
expression <- number / string / list / variable / thunk / subexpression
- number <- ('-'? [0-9]+ ("." [0-9]+)?) -> tonumber
- string <- ('"' {(("\\" .) / [^"])*} '"') -> tostring
- list <- {| '[' (expression (',' (%ws*) expression)*)? ']' |}
+ number <- ('-'? [0-9]+ ("." [0-9]+)?) -> Number
+ string <- ('"' {(("\\" .) / [^"])*} '"') -> String
+ list <- ({| '[' %ws* (%nl %ws*)* (expression (',' %ws* (%nl %ws*)* expression)*)? %ws* (%nl %ws*)* ']' |}) -> List
variable <- ("$" {%wordchars+}) -> Var
subexpression <- ("(" %ws* action ")")
thunk <- ("{" actions "}")
+ keywords <- "if" / "else" / "let"
]]
defs = {
- Var: (...)->Var(...)
- Word: (...)->Word(...)
- Action: (...)->Action(...)
- Thunk: (...)->Thunk(...)
- tostring: tostring
- tonumber: tonumber
+ :Var
+ :Word
+ :String
+ :Number
+ :List
+ :FunctionCall
+ :Thunk
+ :Conditional
ws: lpeg.S(" \t")
- wordchars: lpeg.P(1)-lpeg.S(' \t\n{}[]()"')
+ wordchars: lpeg.P(1)-lpeg.S(' \t\n,{}[]()"')
}
lingo = re.compile lingo, defs
-class Rule
- new:(invocations, action, docstring)=>
- if type(action) == Thunk
- @body_str = docstring or tostring(action)
- @fn = (game,locals)-> action\run(game, locals)
- elseif type(action) == 'function'
- @body_str = docstring or "<lua function>"
- @fn = action
- else
- error("Invalid action type: #{type(action)}")
+cross_compile = (nomic_code)->
+ export currently_parsing
+ old_parsing = currently_parsing
+ currently_parsing = nomic_code
+ lua_code = lingo\match nomic_code
+ currently_parsing = old_parsing
+ return lua_code
- eq = (x,y)->
- if #x != #y then return false
- for i=1,#x
- if x[i] != y[i] then return false
- return true
+defaulttable = (table,key)->
+ new = {}
+ table[key] = new
+ return new
- @raw_invocations = invocations
- @invocations = {}
+class Game
+ new:(@parent)=>
+ @rules = setmetatable({}, {__index:parent and parent.rules or nil})
+ @macros = setmetatable({}, {__index:parent and parent.macros or nil})
+ @arg_names = setmetatable({}, {__index:parent and parent.arg_names or nil})
+ @relations = setmetatable({}, {__index:parent and parent.relations or defaulttable})
+ @invocations = setmetatable({}, {__index:parent and parent.invocations or nil})
+ @authorized = setmetatable({}, {__index:parent and parent.authorized or nil})
+ @callstack = {}
+ @debug = false
+ @you = "Anonymous"
+
+ def: (invocations, fn)=>
+ if not fn then fn = false
+ invocations = if type(invocations) == 'table' then invocations else {invocations}
+ if fn then @invocations[fn] = {}
+ else @invocations[fn] = false
for raw_invocation in *invocations
- name_bits = {}
- arg_names = {}
- for chunk in raw_invocation\gmatch("%S+")
- if chunk\sub(1,1) == "$"
- table.insert name_bits, "$"
- table.insert arg_names, chunk\sub(2,-1)
- else
- table.insert name_bits, chunk
- if @arg_names
- assert(eq(arg_names, @arg_names), "Attempt to use an alias with different variables")
+ invocation, arg_names = compactify_invocation raw_invocation
+ if invocation == "$"
+ error("Anonymous function: #{raw_invocation}")
+ @rules[invocation] = fn
+ if fn
+ table.insert @invocations[fn], invocation
+ @arg_names[invocation] = arg_names
else
- @arg_names = arg_names
- invocation = table.concat name_bits, ";"
- table.insert @invocations, invocation
-
- __tostring:=>
- "Rule: #{table.concat(@raw_invocations, " | ")} :=\n #{@body_str\gsub("\n","\n ")}"
-
+ @arg_names[invocation] = false
+
+ macro: (invocation, fn)=>
+ invocation, _ = compactify_invocation invocation
+ @macros[invocation] = fn
+
+ undefine: (invocations)=>
+ @\def invocations, false
+
+ all_aliases: (invocations)=>
+ if type(invocations) != 'table' then invocations = {invocations}
+ all_aliases = {}
+ for i in *invocations
+ all_aliases[i] = true
+ if not @invocations[@rules[i]]
+ error "Could not find aliases of [[#{i}]]"
+ for alias in *@invocations[@rules[i]]
+ all_aliases[alias] = true
+ return [a for a in pairs(all_aliases)]
-class Game
- new:(parent)=>
- @rules = setmetatable({}, {__index:parent and parent.rules or nil})
- @relations = setmetatable({}, {__index:parent and parent.relations or nil})
+ canonicalize: (invocations)=>
+ if type(invocations) == 'string'
+ return @invocations[@rules[invocations]][1]
+ canonicals = {}
+ for i in *invocations
+ if @rules[i] == nil
+ error "Attempt to canonicalize invalid invocation: #{i}"
+ canonicals[@invocations[@rules[i]][1]] = true
+ return [c for c in pairs canonicals]
- def: (invocation, action, docstring)=>
- invocations = if type(invocation) == 'table' then invocation else {invocation}
- rule = Rule(invocations, action, docstring)
- for invocation in *rule.invocations
- @rules[invocation] = rule
+ set_whitelist: (actions, whitelist)=>
+ if is_list whitelist then whitelist = {w,true for w in *whitelist}
+ for action in *@all_aliases(actions)
+ @authorized[action] = whitelist
- proxy: (rule)=>
- for i in *rule.invocations
- @rules[i] = rule
+ check_authorization:(action)=>
+ authority = @authorized[action]
+ return true if authority == nil
+ for call in *@callstack
+ if authority[call] then return true
+ return false
run: (str, user)=>
- export currently_parsing
- old_parsing = currently_parsing
- currently_parsing = str
- ok,thunk = pcall lingo.match, lingo, str
- currently_parsing = old_parsing
- if not ok
- error(thunk)
-
- unless thunk
- error("failed to parse nomic:\n#{str}")
-
- prev_you = @you
- @you = user or "anon"
- ok,ret = pcall thunk.run, thunk, @, {}
- @you = prev_you
- if not ok
- error(ret)
- if ret != nil
- print("= #{ret}")
+ user or= "anon"
+
+ if @debug
+ print("SOURCE NOMIC CODE:\n#{str}")
+ export macros
+ old_macros = macros
+ macros = (self.macros)
+ lua_code = cross_compile str
+ macros = old_macros
+ if @debug
+ print("\nGENERATED LUA CODE:\n#{lua_code}")
+
+ lua_thunk, err = loadstring("return "..lua_code)
+ if not lua_thunk
+ print("Parsing: "..lua_code)
+ error(err)
+ lua_fn = lua_thunk!
+
+ ret = lua_fn @, {}
return ret
+ call: (invocation, ...)=>
+ if not @rules[invocation]
+ error "Could not find rule: '#{invocation}'"
+ if not @\check_authorization invocation
+ print "Not authorized to #{invocation} from callstack: #{repr(@callstack)}"
+ return
+ table.insert @callstack, invocation
+ arg_names = @arg_names[invocation]
+ args = {...}
+ ret = (@rules[invocation])(@, {arg_names[i],arg for i, arg in ipairs(args)})
+ table.remove @callstack
+ return ret
+
+ run_debug:(...)=>
+ @debug = true
+ print("Debugging:")
+ @run ...
+ @debug = false
+
repl:=>
while true
io.write(">> ")
@@ -180,4 +280,6 @@ class Game
break
@\run buf
+ repr: repr
+
return Game
diff --git a/nomic2.moon b/nomic2.moon
deleted file mode 100644
index 2a03080..0000000
--- a/nomic2.moon
+++ /dev/null
@@ -1,285 +0,0 @@
-re = require 're'
-lpeg = require 'lpeg'
-moon = require 'moon'
-type = moon.type
-
-is_list = (t)->
- i = 0
- for _ in pairs(t)
- i += 1
- if t[i] == nil then return false
- return true
-
-repr = (x)->
- if type(x) == 'table'
- if is_list x
- "[#{table.concat([repr(i) for i in *x], ", ")}]"
- else
- "{#{table.concat(["#{k}: #{v}" for k,v in pairs x], ", ")}}"
- else
- tostring(x)
-
-currently_parsing = nil
-macros = nil
-indentation = 0
-indents = ->
- (" ")\rep(indentation)
-indent = ->
- export indentation
- indentation += 1
-dedent = ->
- export indentation
- indentation -= 1
-indent_block = (block)->
- block = block\gsub("\n", "\n"..indents!)
- return indents!..block
-add_line = (lines, new_line)->
- table.insert lines, (indents!..new_line)
-
-compactify_invocation = (raw_invocation)->
- name_bits = {}
- arg_names = {}
- for chunk in raw_invocation\gmatch("%S+")
- if chunk\sub(1,1) == "$"
- table.insert name_bits, "$"
- table.insert arg_names, chunk\sub(2,-1)
- else
- table.insert name_bits, chunk
- invocation = table.concat name_bits, " "
- return invocation, arg_names
-
-Number = (s)-> s
-
-String = (s)-> '"'..s..'"'
-
-List = (t)-> "{" .. table.concat(t, ", ") .. "}"
-
-Var = (s)-> "locals[\"#{s}\"]"
-
-Word = (s)-> setmetatable({type:'word', text:s}, {__tostring:=> error("Cannot convert word \"#{@text}\" to string")})
-
-Conditional = (condition, if_block, else_block)->
- ret = {}
- add_line ret, "(function()"
- indent!
- add_line ret, "local ret"
- table.insert ret, indent_block("local condition = #{condition}")
-
- add_line ret, "if condition then"
- indent!
- table.insert ret, indent_block("ret = (#{if_block})(game, locals)")
- if else_block
- dedent!
- add_line ret, "else"
- indent!
- table.insert ret, indent_block("ret = (#{else_block})(game, locals)")
- dedent!
- add_line ret, "end"
- add_line ret, "return ret"
- dedent!
- add_line ret, "end)()"
- code = table.concat(ret, "\n")
- return code
-
-FunctionCall = (tokens)->
- words = [(if t.type == 'word' then t.text else "$") for t in *tokens]
- args = [t for t in *tokens when t.type != 'word']
- rule_name = table.concat(words, " ")
- if rule_name == "$"
- error("Empty rule: #{repr(tokens)}")
-
- if macros[rule_name]
- return macros[rule_name](unpack(args))
-
- if #args == 0
- return indent_block("game:call(\"#{rule_name}\")")
-
- ret = {}
- add_line ret, "game:call(\"#{rule_name}\","
- indent!
- arg_strs = [indent_block(arg) for arg in *args]
- dedent!
- table.insert ret, table.concat(arg_strs, ",\n")
- add_line ret, ")"
-
- code = table.concat(ret, "\n")
- return code
-
-Thunk = (lines)->
- ret = {}
- add_line ret, "function(game, locals)"
- indent!
- for i,line in ipairs lines
- if line\match "locals%[\".*\"%] = .*"
- table.insert ret, indent_block(line)
- elseif i == #lines
- table.insert ret, indent_block("return "..line..";")
- else
- table.insert ret, indent_block(line..";")
- dedent!
- add_line ret, "end"
- return table.concat(ret, "\n")
-
-lingo = [[
- actions <- {| {:startPos: {}:} (%ws*) (%nl %ws*)* (action ((%nl %ws*)+ action)*)? (%nl %ws*)* {:endPos: {}:} |} -> Thunk
- action <- (&conditional conditional) / ({| token (%ws+ token)* %ws* |} -> FunctionCall)
- conditional <- ("if" !%wordchars %ws* expression %ws* thunk (%ws* "else" %ws* thunk %ws*)?) -> Conditional
- token <- expression / (!"$" {%wordchars+} -> Word)
- expression <- number / string / list / variable / thunk / subexpression
- number <- ('-'? [0-9]+ ("." [0-9]+)?) -> Number
- string <- ('"' {(("\\" .) / [^"])*} '"') -> String
- list <- ({| '[' %ws* (%nl %ws*)* (expression (',' %ws* (%nl %ws*)* expression)*)? %ws* (%nl %ws*)* ']' |}) -> List
- variable <- ("$" {%wordchars+}) -> Var
- subexpression <- ("(" %ws* action ")")
- thunk <- ("{" actions "}")
- keywords <- "if" / "else" / "let"
-]]
-defs = {
- :Var
- :Word
- :String
- :Number
- :List
- :FunctionCall
- :Thunk
- :Conditional
- ws: lpeg.S(" \t")
- wordchars: lpeg.P(1)-lpeg.S(' \t\n,{}[]()"')
-}
-lingo = re.compile lingo, defs
-
-cross_compile = (nomic_code)->
- export currently_parsing
- old_parsing = currently_parsing
- currently_parsing = nomic_code
- lua_code = lingo\match nomic_code
- currently_parsing = old_parsing
- return lua_code
-
-defaulttable = (table,key)->
- new = {}
- table[key] = new
- return new
-
-class Game
- new:(@parent)=>
- @rules = setmetatable({}, {__index:parent and parent.rules or nil})
- @macros = setmetatable({}, {__index:parent and parent.macros or nil})
- @arg_names = setmetatable({}, {__index:parent and parent.arg_names or nil})
- @relations = setmetatable({}, {__index:parent and parent.relations or defaulttable})
- @invocations = setmetatable({}, {__index:parent and parent.invocations or nil})
- @authorized = setmetatable({}, {__index:parent and parent.authorized or nil})
- @callstack = {}
- @debug = false
- @you = "Anonymous"
-
- def: (invocations, fn)=>
- if not fn then fn = false
- invocations = if type(invocations) == 'table' then invocations else {invocations}
- if fn then @invocations[fn] = {}
- else @invocations[fn] = false
- for raw_invocation in *invocations
- invocation, arg_names = compactify_invocation raw_invocation
- if invocation == "$"
- error("Anonymous function: #{raw_invocation}")
- @rules[invocation] = fn
- if fn
- table.insert @invocations[fn], invocation
- @arg_names[invocation] = arg_names
- else
- @arg_names[invocation] = false
-
- macro: (invocation, fn)=>
- invocation, _ = compactify_invocation invocation
- @macros[invocation] = fn
-
- undefine: (invocations)=>
- @\def invocations, false
-
- all_aliases: (invocations)=>
- if type(invocations) != 'table' then invocations = {invocations}
- all_aliases = {}
- for i in *invocations
- all_aliases[i] = true
- if not @invocations[@rules[i]]
- error "Could not find aliases of [[#{i}]]"
- for alias in *@invocations[@rules[i]]
- all_aliases[alias] = true
- return [a for a in pairs(all_aliases)]
-
- canonicalize: (invocations)=>
- if type(invocations) == 'string'
- return @invocations[@rules[invocations]][1]
- canonicals = {}
- for i in *invocations
- if @rules[i] == nil
- error "Attempt to canonicalize invalid invocation: #{i}"
- canonicals[@invocations[@rules[i]][1]] = true
- return [c for c in pairs canonicals]
-
- set_whitelist: (actions, whitelist)=>
- if is_list whitelist then whitelist = {w,true for w in *whitelist}
- for action in *@all_aliases(actions)
- @authorized[action] = whitelist
-
- check_authorization:(action)=>
- authority = @authorized[action]
- return true if authority == nil
- for call in *@callstack
- if authority[call] then return true
- return false
-
- run: (str, user)=>
- user or= "anon"
-
- if @debug
- print("SOURCE NOMIC CODE:\n#{str}")
- export macros
- old_macros = macros
- macros = (self.macros)
- lua_code = cross_compile str
- macros = old_macros
- if @debug
- print("\nGENERATED LUA CODE:\n#{lua_code}")
-
- lua_thunk, err = loadstring("return "..lua_code)
- if not lua_thunk
- print("Parsing: "..lua_code)
- error(err)
- lua_fn = lua_thunk!
-
- ret = lua_fn @, {}
- return ret
-
- call: (invocation, ...)=>
- if not @rules[invocation]
- error "Could not find rule: '#{invocation}'"
- if not @\check_authorization invocation
- print "Not authorized to #{invocation} from callstack: #{repr(@callstack)}"
- return
- table.insert @callstack, invocation
- arg_names = @arg_names[invocation]
- args = {...}
- ret = (@rules[invocation])(@, {arg_names[i],arg for i, arg in ipairs(args)})
- table.remove @callstack
- return ret
-
- run_debug:(...)=>
- @debug = true
- print("Debugging:")
- @run ...
- @debug = false
-
- repl:=>
- while true
- io.write(">> ")
- buf = ""
- while buf\sub(-2,-1) != "\n\n"
- buf ..= io.read("*line").."\n"
- if buf == "exit\n\n" or buf == "quit\n\n"
- break
- @\run buf
-
- repr: repr
-
-return Game