diff options
Diffstat (limited to 'lib/object.nom')
| -rw-r--r-- | lib/object.nom | 104 |
1 files changed, 104 insertions, 0 deletions
diff --git a/lib/object.nom b/lib/object.nom new file mode 100644 index 0000000..b7506f3 --- /dev/null +++ b/lib/object.nom @@ -0,0 +1,104 @@ +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 [@%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 + %class_identifier <- (=lua "nomsu:var_to_lua_identifier(\(%classname as value)):sub(2,-1)") + if: %class_identifier is "" + %class_identifier <- "class" + %methods <- [] + for %line in (%class_body's "value") + if: (%line's "type") is "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..";"); + local arg_nomsus = {}; + for i, arg in ipairs(args) do arg_nomsus[i] = "nomsu:tree_to_lua("..arg..").expr"; end + table.insert(\%methods, ([==[ + %s[ %s] = function(%s) + %s + end + nomsu:define_compile_action(%s, %s, function(%s) + return {expr="("..nomsu:tree_to_lua(_me).expr..")[ "..%s.."]("..%s..")"}; + end, %s); + ACTION_METADATA[%s[ %s]] = ACTION_METADATA[ACTIONS[ %s]]; + ]==]):format( + \%class_identifier, repr(stub), table.concat(args, ", "), + body_lua, + repr(names), repr(\%line:get_line_no()), table.concat(args, ", "), + repr(repr(stub)), table.concat(arg_nomsus, ".."), + repr(nomsu:dedent(\%line:get_src())), + \%class_identifier, repr(stub), repr(stub))); + + 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: + \(%methods joined with "\n") + + -- 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") + |
