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, %class_identifier] set %class_identifier = (=lua "nomsu:var_to_lua_identifier(\(%classname as value)):sub(2,-1)") if (%class_identifier == ""): set %class_identifier = "class" 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..";"); 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.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: \(join %methods 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")