aboutsummaryrefslogtreecommitdiff
path: root/nomic2.moon
diff options
context:
space:
mode:
Diffstat (limited to 'nomic2.moon')
-rw-r--r--nomic2.moon285
1 files changed, 0 insertions, 285 deletions
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