diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/class.nom | 116 | ||||
| -rw-r--r-- | lib/control_flow.nom | 4 | ||||
| -rw-r--r-- | lib/metaprogramming.nom | 55 | ||||
| -rw-r--r-- | lib/operators.nom | 22 | ||||
| -rw-r--r-- | lib/text.nom | 8 |
5 files changed, 179 insertions, 26 deletions
diff --git a/lib/class.nom b/lib/class.nom new file mode 100644 index 0000000..7099d48 --- /dev/null +++ b/lib/class.nom @@ -0,0 +1,116 @@ +use "lib/core.nom" + +compile [@%var] to: + lua> ".." + local key_lua = repr(\%var.value); + local key_attr = (key_lua:match("'([a-zA-Z][a-zA-Z0-9]*)'") + or key_lua:match('"([a-zA-Z][a-zA-Z0-9]*)"')); + if key_attr then + return "_me."..key_attr; + elseif key_lua:sub(1,1) == "[" then + key_lua = " "..key_lua.." "; + end + return "_me["..key_lua.."]"; + +compile [set @%var = %val] to code: + lua> ".." + local val_lua = \(%val as lua); + local key_lua = repr(\%var.value); + local key_attr = (key_lua:match("'([a-zA-Z][a-zA-Z0-9]*)'") + or key_lua:match('"([a-zA-Z][a-zA-Z0-9]*)"')); + if key_attr then + return "_me."..key_attr.." = "..val_lua..";"; + elseif key_lua:sub(1,1) == "[" then + key_lua = " "..key_lua.." "; + end + return "_me["..key_lua.."] = "..val_lua..";"; + +compile [object %classname %class_body] to: + local [%methods] + set %methods = [] + for %line in (%class_body's "value"): + if ((%line's "type") == "Comment"): do next %line + assume (((%line's "type") == "FunctionCall") and ((%line's "stub") == "action % %")) + ..or barf "Only action definitions are supported inside 'object % %', not \(%line's "src")" + lua> ".." + assert(\%line.value[3].type == "Block", + "Invalid type for action definition body. Expected Block, but got: "..tostring(\%line.value[3].type)); + local names, args = nomsu:parse_spec(\%line.value[2]); + local stub = nomsu:get_stub(names[1]); + local body_lua = nomsu:tree_to_lua(\%line.value[3]); + body_lua = body_lua.statements or ("return "..body_lua.expr..";"); + table.insert(\%methods, ([[ + { aliases=%s, + line=%s, + source=%s, + action=function(%s) + %s + end, + compile_to=function(%s) + return {expr="("..nomsu:tree_to_lua(_me).expr..")[ "..%s.."]("..nomsu:tree_to_lua(%s).expr..")"}; + end, + }]]):format(repr(names), repr(\%line:get_line_no()), repr(nomsu:dedent(\%line.src)), + table.concat(args, ", "), body_lua, + table.concat(args, ", "), repr(repr(stub)), table.concat(args, ").expr..nomsu:tree_to_lua("))); + + local %class_identifier + set %class_identifier = (=lua "nomsu:var_to_lua_identifier(\(%classname as value)):sub(2,-1)") + if (%class_identifier == ""): + set %class_identifier = "class" + + return ".." + do -- \%class_identifier + -- Create the class object: + local \%class_identifier = setmetatable({ + name=\(%classname as lua), instances=setmetatable({}, {__mode="k"}), + }, { + __tostring=function(c) return c.name; end, + __call=function(cls, inst) + inst = inst or {}; + inst.id = tostring(inst):match('table: (.*)'); + setmetatable(inst, cls.instance_metatable); + cls.instances[inst] = true; + if inst['set % up'] then + inst['set % up'](inst); + end + return inst; + end, + }); + \%class_identifier.class = \%class_identifier; + + -- Define the methods: + \%class_identifier.methods = { + \(join %methods with ",\n ") + } + + -- Define nomsu compile time actions that rewrite "%foo baz %x" to %foo['% baz %'](%foo, %x) + -- so classes can have overlapping method names: + for i,method in ipairs(\%class_identifier.methods) do + for a_i, alias in ipairs(method.aliases) do + \%class_identifier[nomsu:get_stub(alias)] = method.action; + end + ACTION_METADATA[method.action] = { + fn=method.action, src=method.source, line_no=method.line, aliases=method.aliases, + }; + nomsu:define_compile_action(method.aliases, method.line, method.compile_to, method.source); + end + + -- Define class methods for instantiating and accessing instances: + \%class_identifier.instance_metatable = { + __index=\%class_identifier, + __tostring=\%class_identifier['% as text'] or function(inst) + return "<"..inst.class.name..": "..inst.id..">"; + end, + }; + nomsu:define_action("instances of "..\%class_identifier.name, "lib/class.nom", function() + return utils.keys(\%class_identifier.instances); + end, ""); + nomsu:define_action("new "..\%class_identifier.name.." %instance", "lib/class.nom", function(_instance) + return \%class_identifier(_instance); + end, ""); + nomsu:define_action("new "..\%class_identifier.name, "lib/class.nom", function() + return \%class_identifier({}); + end, ""); + end -- End of definition of \%class_identifier + \("\n\n") + diff --git a/lib/control_flow.nom b/lib/control_flow.nom index 7455ee9..dd602ff 100644 --- a/lib/control_flow.nom +++ b/lib/control_flow.nom @@ -75,7 +75,7 @@ immediately: action [tree %tree has function call %call]: lua> ".." local target = (\%call).stub; - for subtree,_ in coroutine.wrap(function() nomsu:walk_tree(\%tree); end) do + for subtree,depth in coroutine.wrap(function() nomsu:walk_tree(\%tree); end) do if type(subtree) == 'table' and subtree.type == "FunctionCall" and subtree.stub == target then return true; @@ -397,7 +397,7 @@ immediately: # Do/finally: immediately: compile [do %action] to code: - (%action as lua statements) if ((%action's "type") is "Block") + "do\n \(%action as lua statements)\nend" if ((%action's "type") is "Block") ..else "(\(%action as lua))(nomsu);" compile [do %action then always %final_action] to code: ".." diff --git a/lib/metaprogramming.nom b/lib/metaprogramming.nom index a0b8685..ba63c25 100644 --- a/lib/metaprogramming.nom +++ b/lib/metaprogramming.nom @@ -6,26 +6,40 @@ immediately: lua> ".." nomsu.parse_spec = function(nomsu, spec) - local names = {}; - for i, alias in ipairs(spec.value) do - names[i] = alias.src; + if spec.type == 'List' then + local names = {}; + for i, alias in ipairs(spec.value) do + if alias.type == "FunctionCall" then + names[i] = alias.src; + elseif alias.type == "Text" then + names[i] = nomsu:tree_to_value(alias); + end + end + local junk, arg_names, junk = nomsu:get_stub(names[1]); + local args = {}; + for i, a in ipairs(arg_names) do args[i] = nomsu:var_to_lua_identifier(a); end + return names, args; + else + local alias = nomsu:tree_to_value(spec); + print("ALIAS!!! "..repr(alias).." from "..repr(spec)); + local junk, arg_names, junk = nomsu:get_stub(alias); + local args = {}; + for i, a in ipairs(arg_names) do args[i] = nomsu:var_to_lua_identifier(a); end + return {alias}, args; end - local _, arg_names, _ = nomsu:get_stub(spec.value[1]); - local args = {}; - for i, a in ipairs(arg_names) do args[i] = nomsu:var_to_lua_identifier(a); end - names, args = repr(names), table.concat(args, ", "); - return names, args; end # Compile-time action to make compile-time actions: +# TODO: reduce code duplication here immediately: lua> ".." nomsu:define_compile_action("compile %names to %body", \(__line_no__), function(\%names, \%body) - assert(\%names.type == "List", - "Invalid type for compile definition names. Expected List, but got: "..tostring(\%names.type)); + --assert(\%names.type == "List", + -- "Invalid type for compile definition names. Expected List, but got: "..tostring(\%names.type)); assert(\%body.type == "Block", "Invalid type for compile definition body. Expected Block, but got: "..tostring(\%body.type)); local names, args = nomsu:parse_spec(\%names); + names, args = repr(names), table.concat(args, ", "); local body_lua = nomsu:tree_to_lua(\%body); body_lua = body_lua.statements or ("return "..body_lua.expr..";"); local lua = ([[ @@ -36,17 +50,18 @@ immediately: local function compile_action_wrapper(%s) return {expr=compile_action(%s)}; end nomsu:define_compile_action(%s, %s, compile_action_wrapper, %s); end]]):format(args, body_lua, args, args, names, repr(\%names:get_line_no()), - repr(("compile %s\\n..to code %s"):format(\%names.src, \%body.src))); + repr(("compile %s\\n..to %s"):format(\%names.src, \%body.src))); return {statements=lua}; end, \(__src__ 1)); lua> ".." nomsu:define_compile_action("compile %names to code %body", \(__line_no__), function(\%names, \%body) - assert(\%names.type == "List", - "Invalid type for compile definition names. Expected List, but got: "..tostring(\%names.type)); + --assert(\%names.type == "List", + -- "Invalid type for compile definition names. Expected List, but got: "..tostring(\%names.type)); assert(\%body.type == "Block", "Invalid type for compile definition body. Expected Block, but got: "..tostring(\%body.type)); local names, args = nomsu:parse_spec(\%names); + names, args = repr(names), table.concat(args, ", "); local body_lua = nomsu:tree_to_lua(\%body); body_lua = body_lua.statements or ("return "..body_lua.expr..";"); local lua = ([[ @@ -65,11 +80,12 @@ immediately: immediately: compile [action %names %body] to code: lua> ".." - assert(\%names.type == "List", - "Invalid type for action definition names. Expected List, but got: "..tostring(\%names.type)); + --assert(\%names.type == "List", + -- "Invalid type for action definition names. Expected List, but got: "..tostring(\%names.type)); assert(\%body.type == "Block", "Invalid type for action definition body. Expected Block, but got: "..tostring(\%body.type)); local names, args = nomsu:parse_spec(\%names); + names, args = repr(names), table.concat(args, ", "); local body_lua = nomsu:tree_to_lua(\%body); body_lua = body_lua.statements or ("return "..body_lua.expr..";"); local src = nomsu:dedent(nomsu:source_code(0)); @@ -83,17 +99,18 @@ immediately: immediately: lua> ".." nomsu:define_compile_action("parse %shorthand as %longhand", \(__line_no__), (function(\%shorthand, \%longhand) - assert(\%shorthand.type == "List", - "Invalid type for parse definition shorthand. Expected List, but got: "..tostring(\%shorthand.type)); + --assert(\%shorthand.type == "List", + -- "Invalid type for parse definition shorthand. Expected List, but got: "..tostring(\%shorthand.type)); assert(\%longhand.type == "Block", "Invalid type for parse definition body. Expected Block, but got: "..tostring(\%longhand.type)); local names, args = nomsu:parse_spec(\%shorthand); + names, args = repr(names), table.concat(args, ", "); local template = {}; for i, line in ipairs(\%longhand.value) do template[i] = nomsu:dedent(line.src); end template = repr(table.concat(template, "\\n")); - local _, arg_names, _ = nomsu:get_stub(\%shorthand.value[1]); + local junk, arg_names, junk = nomsu:get_stub(\%shorthand.value[1]); local replacements = {}; for i, a in ipairs(arg_names) do replacements[i] = "["..repr(a).."]="..nomsu:var_to_lua_identifier(a); end replacements = "{"..table.concat(replacements, ", ").."}"; @@ -165,7 +182,7 @@ action [help %action]: parse [eval %code, run %code] as: nomsu "run" [%code] action [source code from tree %tree]: lua> ".." - local _,_,leading_space = \%tree.src:find("\\n(%s*)%S"); + local junk,junk,leading_space = \%tree.src:find("\\n(%s*)%S"); if leading_space then local chunk1, chunk2 = \%tree.src:match(":%s*([^\\n]*)(\\n.*)"); chunk2 = chunk2:gsub("\\n"..leading_space, "\\n"); diff --git a/lib/operators.nom b/lib/operators.nom index b697aad..2bbeadf 100644 --- a/lib/operators.nom +++ b/lib/operators.nom @@ -5,7 +5,27 @@ use "lib/metaprogramming.nom" # Indexing: immediately: - compile [%obj'%key, %obj's %key, %obj -> %key] to: "(\(%obj as lua))[\(%key as lua)]" + #.. NOTE!!! It's critical that there are spaces around %key if it's a string, + otherwise, Lua will get confused and interpret %obj[[[foo]]] as %obj("[foo]") + instead of %obj[ "foo" ]. + It's also critical to have parens around %obj, otherwise Lua is too dumb to + realize that {x=1}["x"] is the same as ({x=1})["x"] or that + {x=1}.x is the same as ({x=1}).x + compile [%obj'%key, %obj's %key, %obj -> %key] to: + lua> ".." + local obj_lua = \(%obj as lua); + if not obj_lua:sub(-1,-1):match("[a-zA-Z)]") then + obj_lua = "("..obj_lua..")"; + end + local key_lua = \(%key as lua); + local key_attr = (key_lua:match("'([a-zA-Z][a-zA-Z0-9]*)'") + or key_lua:match('"([a-zA-Z][a-zA-Z0-9]*)"')); + if key_attr then + return obj_lua.."."..key_attr; + elseif key_lua:sub(1,1) == "[" then + key_lua = " "..key_lua.." "; + end + return obj_lua.."["..key_lua.."]"; # Comparison Operators immediately: diff --git a/lib/text.nom b/lib/text.nom index 9db8a07..5cb268d 100644 --- a/lib/text.nom +++ b/lib/text.nom @@ -52,8 +52,8 @@ lua do> ".." local color = "'"..c.."'"; local reset = "'"..colors["reset color"].."'"; nomsu:define_compile_action(name, \(__line_no__), function() return {expr=color}; end, \(__src__ 1)); - nomsu:define_compile_action(name.." %", \(__line_no__), function(_) - return {expr=color..".."..nomsu:tree_to_lua(_).expr..".."..reset}; + nomsu:define_compile_action(name.." %", \(__line_no__), function(\%) + return {expr=color..".."..nomsu:tree_to_lua(\%).expr..".."..reset}; end, \(__src__ 1)); end @@ -85,8 +85,8 @@ lua do> ".." local e = "'"..\%str.."'"; local reset = "'"..\(%colors->"reset color").."'"; nomsu:define_compile_action(\%name, \(__line_no__), function(nomsu) return {expr=e}; end, \(__src__ 1)); - nomsu:define_compile_action(\%name.." %", \(__line_no__), function(nomsu, _) - return {expr=e..".."..nomsu:tree_to_lua(_).expr..".."..reset}; + nomsu:define_compile_action(\%name.." %", \(__line_no__), function(nomsu, \%) + return {expr=e..".."..nomsu:tree_to_lua(\%).expr..".."..reset}; end, \(__src__ 1)); # FIXME |
