use "core" compile [@] to {expr:"self"} 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 {expr="self."..key_attr}; elseif key_lua:sub(1,1) == "[" then key_lua = " "..key_lua.." "; end return {expr="self["..key_lua.."]"}; compile [@%var <- %val] to: lua> ".." local val_lua = \(%val as lua expr); 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 {statements="self."..key_attr.." = "..val_lua..";"}; elseif key_lua:sub(1,1) == "[" then key_lua = " "..key_lua.." "; end return {statements="self["..key_lua.."] = "..val_lua..";"}; compile [as %instance %body] to: %body_lua <- (%body as lua) return {..} statements: ".." do local self = \(%instance as lua expr); local global_actions = ACTION; local ACTION = setmetatable({}, {__index=function(_,key) local method = self[key]; if method then return (function(...) return method(self, ...); end); end return global_actions[key]; end}); \((%body_lua's "statements") or "\(%body_lua's "expr");") end locals: %body_lua's "locals" compile [define 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 <- [] %__index <- %class_identifier %__newindex <- "nil" for %line in (%class_body's "value"): if: (%line's "type") is "Comment" do next %line if: ((%line's "type") is "FunctionCall") and ((%line's "stub") is "slots %") %slot_index_clauses <- [] %slot_newindex_clauses <- [] %slots <- ("value" in (2nd in (%line's "value"))) for %slot_index = %slot_var in %slots: to %slot_index_clauses add ".." if key == \(repr (%slot_var's "value")) or key == \(repr (%slot_var as lua expr)) then return rawget(self, \%slot_index); end to %slot_newindex_clauses add ".." if key == \(repr (%slot_var's "value")) or key == \(repr (%slot_var as lua expr)) or key == \%slot_index then rawset(self, \%slot_index, value); end %__index <- ".." function(self, key) \(%slot_index_clauses joined with "\n") return \%class_identifier[key]; end %__newindex <- ".." function(self, key, value) \(%slot_newindex_clauses joined with "\n") error("Attempt to store data in "..repr(key)..", which is not a valid slot on "..tostring(self.class)); end do next %line assume (((%line's "type") is "FunctionCall") and ((%line's "stub") is "action % %")) ..or barf "Only action definitions are supported inside 'define object % %', not \(%line's "src")" %actions <- (2nd in (%line's "value")) %body <- (3rd in (%line's "value")) lua> ".." local signature = {}; for i, action in ipairs(\%actions.value) do signature[i] = action:get_src(); end local stubs = nomsu:get_stubs_from_signature(signature); local stub_args = nomsu:get_args_from_signature(signature); local arg_set = {}; for i, arg in ipairs(stub_args[1]) do arg_set[arg] = true; end local body_lua = nomsu:tree_to_lua(\%body); local body_code = body_lua.statements or ("return "..body_lua.expr..";"); local undeclared_locals = {}; for i, body_local in ipairs(body_lua.locals or {}) do if not arg_set[body_local] then table.insert(undeclared_locals, body_local); end end if #undeclared_locals > 0 then body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code; end local lua_fn_args = table.concat({"self", unpack(stub_args[1])}, ", "); local def_tree = nomsu.compilestack[#nomsu.compilestack]; local code_location = ("%s:%s,%s"):format(def_tree.filename, def_tree.start, def_tree.stop); local compiled_args = {}; for i, arg in ipairs(stub_args[1]) do compiled_args[i] = "nomsu:tree_to_lua("..arg..").expr"; end compiled_args = table.concat(compiled_args, "..', '.."); table.insert(\%methods, ([==[ %s[ %s] = function(%s) %s end ]==]):format( \%class_identifier, repr(stubs[1]), lua_fn_args, body_code)); return {..} statements:".." do -- \%class_identifier -- Create the class object: local \%class_identifier = setmetatable({ name=\(%classname as lua expr), instances=setmetatable({}, {__mode="k"}), }, { __tostring=function(c) return c.name; end, __call=function(cls, initial_values) local inst = setmetatable({}, cls.instance_metatable); for k,v in pairs(initial_values) do inst[k] = v; end 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=\%__index, __newindex=\%__newindex, __tostring=\%class_identifier['as text'] or function(inst) return "<"..inst.class.name..": "..nomsu.ids[inst]..">"; end, __len=\%class_identifier['size of'], __unm=\%class_identifier['-'], __add=\%class_identifier['+ %'], __sub=\%class_identifier['- %'], __mul=\%class_identifier['* %'], __div=\%class_identifier['/ %'], __mod=\%class_identifier['wrapped around %'], __pow=\%class_identifier['^ %'], __band=\%class_identifier['AND %'], __bor=\%class_identifier['OR %'], __bxor=\%class_identifier['XOR %'], __bshl=\%class_identifier['<< %'], __bshr=\%class_identifier['>> %'], __eq=\%class_identifier['= %'], __lt=\%class_identifier['< %'], __le=\%class_identifier['<= %'], }; 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")