Misc changes, fixed up Object lib and tests.
This commit is contained in:
parent
ad94ed3653
commit
2e345e271f
@ -288,7 +288,7 @@ immediately
|
||||
assume (not %seen_else) or barf "'else' clause needs to be last in 'when' block"
|
||||
lua> "table.insert(\%fallthroughs, \(%condition as lua expr));"
|
||||
to %code write "\("if" if %is_first else "\nelseif") "
|
||||
for %i=%condition in %fallthroughs
|
||||
for %i = %condition in %fallthroughs
|
||||
if (%i > 1): to %code write " or "
|
||||
to %code write %condition
|
||||
to %code write " then\n "
|
||||
|
@ -24,7 +24,7 @@ compile [tangent %, tan %] to: Lua value "math.tan(\(% as lua expr))"
|
||||
compile [arc sine %, asin %] to: Lua value "math.asin(\(% as lua expr))"
|
||||
compile [arc cosine %, acos %] to: Lua value "math.acos(\(% as lua expr))"
|
||||
compile [arc tangent %, atan %] to: Lua value "math.atan(\(% as lua expr))"
|
||||
compile [arc tangent %y/%x, atan2 %y %x] to: Lua value "math.atan2(\(%y as lua expr), \(%x as lua expr))"
|
||||
compile [arc tangent %y / %x, atan2 %y %x] to: Lua value "math.atan2(\(%y as lua expr), \(%x as lua expr))"
|
||||
compile [hyperbolic sine %, sinh %] to: Lua value "math.sinh(\(% as lua expr))"
|
||||
compile [hyperbolic cosine %, cosh %] to: Lua value "math.cosh(\(% as lua expr))"
|
||||
compile [hyperbolic tangent %, tanh %] to: Lua value "math.tanh(\(% as lua expr))"
|
||||
|
@ -21,6 +21,8 @@ say "Hello world!"
|
||||
%str <- "Hello world"
|
||||
# Expressions that are more than just literal values require parentheses:
|
||||
%x <- (2 + 3)
|
||||
%one-two <- 12
|
||||
say %one-two
|
||||
|
||||
# How do I modify a variable?
|
||||
%x <- (%x + 1)
|
||||
@ -28,50 +30,50 @@ say "Hello world!"
|
||||
%x +<- 1
|
||||
|
||||
# How do I define a mutli-line string?
|
||||
%mutli_str <- ".."
|
||||
%mutli-str <- ".."
|
||||
Start with "..", then put lines below it
|
||||
that are indented one level.
|
||||
The string will continue until the indentation ends.
|
||||
|
||||
# How do I put values inside a string?
|
||||
%format_str <- ".."
|
||||
%format-str <- ".."
|
||||
Strings can contain a backslash followed by a variable, list, dict, or parenthesized
|
||||
expression. This escaped value will be converted to a readable string, like so:
|
||||
The value of %x is \%x, isn't that nice?
|
||||
These are some numbers: \[1+1,2+1,3+1]
|
||||
The sum of 2 and 4 is \(2 + 4).
|
||||
If you need to use a plain ol' backslash, you can do \\ <-- that
|
||||
%format_str2 <- "Single-line strings can contain escape sequences like \", \\, \n, \065, and \x0A"
|
||||
%format-str2 <- "Single-line strings can contain escape sequences like \", \\, \n, \065, and \x0A"
|
||||
|
||||
# How do I define a list?
|
||||
%my_list <- [1,2,"hello"]
|
||||
%my-list <- [1,2,"hello"]
|
||||
# Really long lists can use [..] followed by a bunch of indented values delimited
|
||||
by commas and/or newlines
|
||||
%my_really_long_list <- [..]
|
||||
%my-really-long-list <- [..]
|
||||
1,2,3,4
|
||||
5,6
|
||||
7
|
||||
8,9,10
|
||||
|
||||
# How do I use a list?
|
||||
%my_list <- ["first item", "second item", "third item"]
|
||||
%my-list <- ["first item", "second item", "third item"]
|
||||
# Lists are 1-indexed because they're implemented as Lua tables, so this prints "first item"
|
||||
say %my_list.1
|
||||
say %my-list.1
|
||||
# List entries can be modified like this:
|
||||
%my_list.1 <- "ONE!!!"
|
||||
say (length of %my_list)
|
||||
%my-list.1 <- "ONE!!!"
|
||||
say (length of %my-list)
|
||||
|
||||
# How do I define a dictionary/hash map?
|
||||
%my_dict <- {x: 99, y: 101}
|
||||
%my_dict <- {..}
|
||||
%my-dict <- {x: 99, y: 101}
|
||||
%my-dict <- {..}
|
||||
x: 101, y: 2
|
||||
"99 bottles": 99
|
||||
653: 292
|
||||
|
||||
# How do I use a dict?
|
||||
# Dicts are also implemented as Lua tables, so they're accessed and modified the same way as lists
|
||||
say %my_dict.x
|
||||
%my_dict.x <- 9999
|
||||
say %my-dict.x
|
||||
%my-dict.x <- 9999
|
||||
|
||||
# How do I do conditional branching?
|
||||
if: 1 < 10
|
||||
@ -173,11 +175,11 @@ say (first fibonacci above 10)
|
||||
|
||||
# Actions can have aliases, which may or may not have the arguments in different order
|
||||
action [..]
|
||||
I hate %worse_things more than %better_things
|
||||
I think %worse_things are worse than %better_things
|
||||
I like %better_things more than %worse_things
|
||||
I hate %worse-things more than %better-things
|
||||
I think %worse-things are worse than %better-things
|
||||
I like %better-things more than %worse-things
|
||||
..
|
||||
say "\(%better_things capitalized) rule and \%worse_things drool!"
|
||||
say "\(%better-things capitalized) rule and \%worse-things drool!"
|
||||
|
||||
I like "dogs" more than "cats"
|
||||
I think "chihuahuas" are worse than "corgis"
|
||||
@ -188,16 +190,16 @@ I think "chihuahuas" are worse than "corgis"
|
||||
say both "Hello" and also "again!"
|
||||
|
||||
# Actions can even start with a parameter
|
||||
action [%what_she_said is what she said]
|
||||
say %what_she_said
|
||||
action [%what-she-said is what she said]
|
||||
say %what-she-said
|
||||
say "-- she said"
|
||||
|
||||
"Howdy pardner" is what she said
|
||||
|
||||
# The language only reserves []{}().,:;% as special characters, so actions
|
||||
can have really funky names!
|
||||
action [>> %foo_bar $$$^ --> % @& _~-^-~_~-^ %1 !]
|
||||
say %foo_bar
|
||||
action [>> %foo-bar $$$^ --> % @& _~-^-~_~-^ %1 !]
|
||||
say %foo-bar
|
||||
say %
|
||||
say %1
|
||||
|
||||
@ -283,12 +285,12 @@ if (1 > (TWENTY)) on opposite day
|
||||
|
||||
# How do I use an action as a value?
|
||||
# Well... it's always *possible* to fall back to Lua behavior for something like this:
|
||||
action [best of %items according to %key_fn]
|
||||
<- {%best:nil, %best_key:nil}
|
||||
action [best of %items according to %key-fn]
|
||||
<- {%best:nil, %best-key:nil}
|
||||
for % in %items
|
||||
%key <- (=lua "\%key_fn(\%)")
|
||||
if: (%best is (nil)) or (%key > %best_key)
|
||||
<- {%best:%, %best_key:%key}
|
||||
%key <- (=lua "\%key-fn(\%)")
|
||||
if: (%best is (nil)) or (%key > %best-key)
|
||||
<- {%best:%, %best-key:%key}
|
||||
return %best
|
||||
|
||||
immediately
|
||||
@ -305,13 +307,13 @@ say: best of [2,-3,4,-8] according to (function %: % * %)
|
||||
could use a macro to generate a single block of code that inlines the expression you
|
||||
want to use:
|
||||
immediately
|
||||
parse [best of %items according to %key_expr] as
|
||||
parse [best of %items according to %key-expr] as
|
||||
result of
|
||||
<- {%best:nil, %best_key:nil}
|
||||
<- {%best:nil, %best-key:nil}
|
||||
for % in %items
|
||||
%key <- %key_expr
|
||||
if: (%best is (nil)) or (%key > %best_key)
|
||||
<- {%best:%, %best_key:%key}
|
||||
%key <- %key-expr
|
||||
if: (%best is (nil)) or (%key > %best-key)
|
||||
<- {%best:%, %best-key:%key}
|
||||
return %best
|
||||
# This results in generated code that is more efficient (no function calls in the
|
||||
inner loop)
|
||||
@ -322,7 +324,7 @@ say: best of [2,-3,4,-8] according to (% * %)
|
||||
to get a new list with every entry multiplied by 2, but it's *much* more readable to
|
||||
do something like:
|
||||
%nums <- [1,2,3,4,5]
|
||||
%double_nums <- ((2 * %num) for %num in %nums)
|
||||
%double-nums <- ((2 * %num) for %num in %nums)
|
||||
|
||||
# Nomsu comes with built-in list comprehensions, but the flexible macro system makes it
|
||||
incredibly easy to make similar constructs.
|
||||
@ -335,5 +337,5 @@ immediately
|
||||
%result.(%N - %i + 1) <- %expr
|
||||
return %result
|
||||
|
||||
%double_nums <- ((2 * %num) for %num in %nums BACKWARDS!)
|
||||
say %double_nums
|
||||
%double-nums <- ((2 * %num) for %num in %nums BACKWARDS!)
|
||||
say %double-nums
|
||||
|
206
lib/object.nom
206
lib/object.nom
@ -1,100 +1,91 @@
|
||||
use "core"
|
||||
|
||||
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="_me."..key_attr};
|
||||
elseif key_lua:sub(1,1) == "[" then
|
||||
key_lua = " "..key_lua.." ";
|
||||
end
|
||||
return {expr="_me["..key_lua.."]"};
|
||||
compile [@, me] to: Lua value "self"
|
||||
|
||||
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="_me."..key_attr.." = "..val_lua..";"};
|
||||
elseif key_lua:sub(1,1) == "[" then
|
||||
key_lua = " "..key_lua.." ";
|
||||
compile [as %instance %body] to
|
||||
Lua ".."
|
||||
do
|
||||
local self = \(%instance as lua expr);
|
||||
local global_actions = ACTIONS;
|
||||
local ACTIONS = setmetatable({}, {__index=function(_,key)
|
||||
local method = self[key];
|
||||
if method then return (function(...) return method(self, ...); end); end
|
||||
return global_actions[key];
|
||||
end});
|
||||
\(%body as lua statements)
|
||||
end
|
||||
return {statements="_me["..key_lua.."] = "..val_lua..";"};
|
||||
|
||||
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 <- []
|
||||
for %line in (%class_body's "value")
|
||||
if: (%line's "type") is "Comment"
|
||||
compile [object %classname %class_body] to
|
||||
%class_id <- (=lua "Var(\(%classname as value)):as_lua_id():sub(2,-1)")
|
||||
if: %class_id is ""
|
||||
%class_id <- "class"
|
||||
%methods <-: Lua ""
|
||||
%__index <- %class_id
|
||||
%__newindex <- "nil"
|
||||
for %line in %class_body
|
||||
if: %line.type is "Comment"
|
||||
do next %line
|
||||
assume (((%line's "type") == "FunctionCall") and ((%line's stub) == "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"))
|
||||
if: (%line.type is "Action") and ((%line's stub) is "slots %")
|
||||
%slot_index_clauses <- []
|
||||
%slot_newindex_clauses <- []
|
||||
%slots <- %line.2
|
||||
for %slot_index = %slot_var in %slots
|
||||
to %slot_index_clauses add ".."
|
||||
if key == \(repr %slot_var.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.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_id[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.type is "Action") and ((%line's stub) is "action % %"))
|
||||
..or barf "Only action definitions are supported inside 'object % %'"
|
||||
%actions <- %line.2
|
||||
%body <- %line.3
|
||||
lua> ".."
|
||||
local stubs = {};
|
||||
for i, action in ipairs(\%actions.value) do
|
||||
stubs[i] = nomsu:tree_to_named_stub(action);
|
||||
end
|
||||
local args = {};
|
||||
for i,tok in ipairs(\%actions.value[1].value) do
|
||||
if tok.type == "Var" then args[#args+1] = nomsu:var_to_lua_identifier(tok.value); end
|
||||
end
|
||||
local arg_set = {};
|
||||
for i, arg in ipairs(args) 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);
|
||||
do
|
||||
local stubs = {}
|
||||
for i, action in ipairs(\%actions) do
|
||||
stubs[i] = action:get_stub(true)
|
||||
end
|
||||
end
|
||||
if #undeclared_locals > 0 then
|
||||
body_code = "local "..table.concat(undeclared_locals, ", ")..";\\n"..body_code;
|
||||
end
|
||||
local lua_fn_args = table.concat(args, ", ");
|
||||
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(args) 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
|
||||
local lua = Lua(nil, \%class_id, "[ ", repr(stubs[1]), "] = function(self")
|
||||
local args = {}
|
||||
for i,tok in ipairs(\%actions[1]) do
|
||||
if tok.type == "Var" then args[#args+1] = tok end
|
||||
end
|
||||
nomsu:define_compile_action(%s, %s, function(%s)
|
||||
return {expr="("..nomsu:tree_to_lua(_me).expr..")[ "..%s.."]("..%s..")"};
|
||||
end);
|
||||
ACTION_METADATA[%s[ %s]] = ACTION_METADATA[ACTION[ %s]];
|
||||
]==]):format(
|
||||
\%class_identifier, repr(stubs[1]), lua_fn_args,
|
||||
body_code,
|
||||
repr(stubs), repr(code_location), lua_fn_args,
|
||||
repr(repr(stubs[1])), compiled_args,
|
||||
\%class_identifier, repr(stubs[1]), repr(stubs[1])));
|
||||
for i, arg in ipairs(args) do
|
||||
lua:append(", ", nomsu:tree_to_lua(arg))
|
||||
end
|
||||
local body_lua = nomsu:tree_to_lua(\%body):as_statements("return ")
|
||||
body_lua:remove_free_vars(args)
|
||||
body_lua:declare_locals()
|
||||
lua:append(")\n ", body_lua, "\nend;\n")
|
||||
\%methods:append(lua)
|
||||
end
|
||||
|
||||
return {..}
|
||||
statements:".."
|
||||
do -- \%class_identifier
|
||||
return
|
||||
Lua ".."
|
||||
do -- \%class_id
|
||||
-- Create the class object
|
||||
local \%class_identifier = setmetatable({
|
||||
local \%class_id = setmetatable({
|
||||
name=\(%classname as lua expr), 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);
|
||||
__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);
|
||||
@ -102,27 +93,44 @@ compile [define object %classname %class_body] to
|
||||
return inst;
|
||||
end,
|
||||
});
|
||||
\%class_identifier.class = \%class_identifier;
|
||||
\%class_id.class = \%class_id;
|
||||
|
||||
-- Define the methods
|
||||
\(%methods joined with "\n")
|
||||
\%methods
|
||||
|
||||
-- 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..">";
|
||||
\%class_id.instance_metatable = {
|
||||
__index=\%__index,
|
||||
__newindex=\%__newindex,
|
||||
__tostring=\%class_id['as text'] or function(inst)
|
||||
return "<"..inst.class.name..": "..nomsu.ids[inst]..">";
|
||||
end,
|
||||
__len=\%class_id['size of'],
|
||||
__unm=\%class_id['-'],
|
||||
__add=\%class_id['+ %'],
|
||||
__sub=\%class_id['- %'],
|
||||
__mul=\%class_id['* %'],
|
||||
__div=\%class_id['/ %'],
|
||||
__mod=\%class_id['wrapped around %'],
|
||||
__pow=\%class_id['^ %'],
|
||||
__band=\%class_id['AND %'],
|
||||
__bor=\%class_id['OR %'],
|
||||
__bxor=\%class_id['XOR %'],
|
||||
__bshl=\%class_id['<< %'],
|
||||
__bshr=\%class_id['>> %'],
|
||||
__eq=\%class_id['= %'],
|
||||
__lt=\%class_id['< %'],
|
||||
__le=\%class_id['<= %'],
|
||||
};
|
||||
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
|
||||
nomsu:define_action("instances of "..\%class_id.name, function()
|
||||
return utils.keys(\%class_id.instances);
|
||||
end);
|
||||
nomsu:define_action("new "..\%class_id.name.." %instance", function(_instance)
|
||||
return \%class_id(_instance);
|
||||
end);
|
||||
nomsu:define_action("new "..\%class_id.name, function()
|
||||
return \%class_id({});
|
||||
end);
|
||||
end -- End of definition of \%class_id
|
||||
\("\n\n")
|
||||
|
||||
|
175
lib/object2.nom
175
lib/object2.nom
@ -1,175 +0,0 @@
|
||||
use "core"
|
||||
|
||||
compile [@] to: Lua value "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 Lua.value(tree.source, "self."..key_attr);
|
||||
elseif key_lua:sub(1,1) == "[" then
|
||||
key_lua = " "..key_lua;
|
||||
end
|
||||
return Lua.Value(tree.source, "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 Lua(tree.source, "self.", key_attr, " = ", val_lua, ";");
|
||||
elseif key_lua:sub(1,1) == "[" then
|
||||
key_lua = " "..key_lua.." ";
|
||||
end
|
||||
return Lua(tree.source, "self[", key_lua, "] = ", val_lua, ";");
|
||||
|
||||
compile [as %instance %body] to
|
||||
%body_lua <- (%body as lua)
|
||||
lua> "\%body_lua:convert_to_statements();"
|
||||
return
|
||||
Lua ".."
|
||||
do
|
||||
local self = \(%instance as lua expr);
|
||||
local global_actions = ACTIONS;
|
||||
local ACTIONS = 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
|
||||
end
|
||||
|
||||
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 <- %line.value.2.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.type is "FunctionCall") and ((%line's stub) is "action % %"))
|
||||
..or barf "Only action definitions are supported inside 'define object % %', not \(%line's "src")"
|
||||
%actions <- %line.value.2
|
||||
%body <- %line.value.3
|
||||
lua> ".."
|
||||
do
|
||||
local stubs = {};
|
||||
for i, action in ipairs(\%actions.value) do
|
||||
stubs[i] = nomsu:tree_to_named_stub(action);
|
||||
end
|
||||
local args = {};
|
||||
for i,tok in ipairs(\%actions.value[1].value) do
|
||||
if tok.type == "Var" then args[#args+1] = nomsu:var_to_lua_identifier(tok.value); end
|
||||
end
|
||||
local arg_set = {};
|
||||
for i, arg in ipairs(args) do arg_set[arg] = true; end
|
||||
local body_lua = nomsu:tree_to_lua(\%body);
|
||||
body_lua:convert_to_statements();
|
||||
body_lua:declare_locals();
|
||||
local lua_fn_args = table.concat({"self", unpack(args)}, ", ");
|
||||
local def_tree = nomsu.compilestack[#nomsu.compilestack];
|
||||
|
||||
local compiled_args = {};
|
||||
for i, arg in ipairs(args) do
|
||||
compiled_args[i] = "nomsu:tree_to_lua("..arg..")";
|
||||
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_lua));
|
||||
end
|
||||
|
||||
return
|
||||
Lua ".."
|
||||
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(__callsite)
|
||||
return utils.keys(\%class_identifier.instances);
|
||||
end, "");
|
||||
nomsu:define_action("new "..\%class_identifier.name.." %instance", "lib/class.nom", function(__callsite, _instance)
|
||||
return \%class_identifier(_instance);
|
||||
end, "");
|
||||
nomsu:define_action("new "..\%class_identifier.name, "lib/class.nom", function(__callsite)
|
||||
return \%class_identifier({});
|
||||
end, "");
|
||||
end -- End of definition of \%class_identifier
|
||||
\("\n\n")
|
||||
|
@ -28,8 +28,8 @@ end
|
||||
re = require('re')
|
||||
lpeg = require('lpeg')
|
||||
lpeg.setmaxstack(10000)
|
||||
local P, R, V, S, Cg, C, Cp, B, Cmt
|
||||
P, R, V, S, Cg, C, Cp, B, Cmt = lpeg.P, lpeg.R, lpeg.V, lpeg.S, lpeg.Cg, lpeg.C, lpeg.Cp, lpeg.B, lpeg.Cmt
|
||||
local P, R, V, S, Cg, C, Cp, B
|
||||
P, R, V, S, Cg, C, Cp, B = lpeg.P, lpeg.R, lpeg.V, lpeg.S, lpeg.Cg, lpeg.C, lpeg.Cp, lpeg.B
|
||||
local utils = require('utils')
|
||||
local new_uuid = require('uuid')
|
||||
local immutable = require('immutable')
|
||||
@ -1303,7 +1303,7 @@ do
|
||||
stub_defs = {
|
||||
space = (P(' ') + P('\n..')) ^ 0,
|
||||
word = (NOMSU_DEFS.ident_char ^ 1 + NOMSU_DEFS.operator),
|
||||
varname = (R('az', 'AZ', '09') + P('_') + NOMSU_DEFS.utf8_char) ^ 0
|
||||
varname = (R('az', 'AZ', '09') + P('_') + NOMSU_DEFS.utf8_char + (-P("'") * NOMSU_DEFS.operator)) ^ 0
|
||||
}
|
||||
stub_pattern = re.compile([=[ {~ (%space->'') (('%' (%varname->'')) / %word)? ((%space->' ') (('%' (%varname->'')) / %word))* (%space->'') ~}
|
||||
]=], stub_defs)
|
||||
|
@ -33,7 +33,7 @@ if jit
|
||||
re = require 're'
|
||||
lpeg = require 'lpeg'
|
||||
lpeg.setmaxstack 10000
|
||||
{:P,:R,:V,:S,:Cg,:C,:Cp,:B,:Cmt} = lpeg
|
||||
{:P,:R,:V,:S,:Cg,:C,:Cp,:B} = lpeg
|
||||
utils = require 'utils'
|
||||
new_uuid = require 'uuid'
|
||||
immutable = require 'immutable'
|
||||
@ -285,7 +285,7 @@ class NomsuCompiler
|
||||
stub_defs = {
|
||||
space:(P(' ') + P('\n..'))^0
|
||||
word:(NOMSU_DEFS.ident_char^1 + NOMSU_DEFS.operator)
|
||||
varname:(R('az','AZ','09') + P('_') + NOMSU_DEFS.utf8_char)^0
|
||||
varname:(R('az','AZ','09') + P('_') + NOMSU_DEFS.utf8_char + (-P("'") * NOMSU_DEFS.operator))^0
|
||||
}
|
||||
stub_pattern = re.compile [=[
|
||||
{~ (%space->'') (('%' (%varname->'')) / %word)? ((%space->' ') (('%' (%varname->'')) / %word))* (%space->'') ~}
|
||||
|
@ -87,7 +87,7 @@ number (Number): (("-"? (([0-9]+ "." [0-9]+) / ("." [0-9]+) / ([0-9]+)))-> tonum
|
||||
|
||||
-- Variables can be nameless (i.e. just %) and can't contain operators like apostrophe
|
||||
-- which is a hack to allow %'s to parse as "%" and "' s" separately
|
||||
variable (Var): "%" { plain_word? }
|
||||
variable (Var): "%" { ((!"'" %operator) / plain_word)* }
|
||||
|
||||
inline_list (List):
|
||||
!('[..]')
|
||||
@ -132,4 +132,4 @@ dedent: eol (%nl ignored_line)* (((!.) &%dedent) / (&(%nl %dedent)))
|
||||
non_dedent_error: (!dedent .)* eol (%nl ignored_line)* (!. / &%nl)
|
||||
comma: %ws* "," %ws*
|
||||
dotdot: nodent ".."
|
||||
plain_word: ([a-zA-Z0-9_] / %utf8_char)+
|
||||
plain_word: ([a-zA-Z0-9_-] / %utf8_char)+
|
||||
|
@ -1,24 +1,27 @@
|
||||
use "core"
|
||||
use "lib/object2.nom"
|
||||
use "lib/object.nom"
|
||||
|
||||
#..
|
||||
immediately
|
||||
define object "Dog"
|
||||
action [bark]
|
||||
%barks <- ("Bark!" for all 1 to (@%barks))
|
||||
return (%barks joined with " ")
|
||||
action [get pissed off]
|
||||
(@%barks) +<- 1
|
||||
immediately
|
||||
object "Dog"
|
||||
action [bark]
|
||||
%barks <- ("Bark!" for % in 1 to ((me).barks))
|
||||
return: %barks joined with " "
|
||||
|
||||
%d <- (new Dog {barks:2})
|
||||
as %d
|
||||
assume ((@) = %d)
|
||||
assume ((@%barks) = 2)
|
||||
assume ((bark) = "Bark! Bark!")
|
||||
get pissed off
|
||||
assume ((@%barks) = 3)
|
||||
assume ((bark) = "Bark! Bark! Bark!")
|
||||
assume ("\(%d's "class")" = "Dog")
|
||||
assume ((%d's "barks") = 3)
|
||||
action [get pissed off]
|
||||
((me).barks) +<- 1
|
||||
|
||||
say "Object test passed."
|
||||
%d <-: new Dog {barks:2}
|
||||
as %d
|
||||
assume: (me) = %d
|
||||
assume: ((me).barks) = 2
|
||||
assume: (bark) = "Bark! Bark!"
|
||||
get pissed off
|
||||
assume: ((me).barks) = 3
|
||||
assume: (bark) = "Bark! Bark! Bark!"
|
||||
assume: "\(%d's "class")" = "Dog"
|
||||
assume: (%d's "barks") = 3
|
||||
|
||||
as: new Dog {barks:1}
|
||||
assume: (bark) = "Bark!"
|
||||
|
||||
say "Object test passed."
|
||||
|
Loading…
Reference in New Issue
Block a user