116 lines
4.3 KiB
Plaintext
116 lines
4.3 KiB
Plaintext
#!/usr/bin/env nomsu -V4.12.12.8
|
|
#
|
|
This file contains the implementation of an Object-Oriented programming system.
|
|
|
|
%globals.METAMETHOD_MAP = {..}
|
|
"as text": "__tostring", "clean up": "__gc", "+ 1": "__add", "- 1": "__sub"
|
|
"* 1": "__mul", "/ 1": "__div", "-": "__unm", "// 1": "__idiv", "mod 1": "__mod"
|
|
"^ 1": "__pow", "& 1": "__band", "| 1": "__bor", "~ 1": "__bxor", "~": "__bnot"
|
|
"<< 1": "__bshl", ">> 1": "__bshr", "== 1": "__eq", "< 1": "__lt", "<= 1": "__le"
|
|
"set 1 = 2": "__newindex", size: "__len", iterate: "__ipairs"
|
|
"iterate all": "__pairs"
|
|
|
|
test:
|
|
object (Dog):
|
|
(Dog).genus = "Canus"
|
|
my action [set up]:
|
|
%me.barks or= 0
|
|
|
|
my action [bark, woof]:
|
|
%barks = [: for % in 1 to %me.barks: add "Bark!"]
|
|
return (%barks::joined with " ")
|
|
|
|
my action [get pissed off]: %me.barks += 1
|
|
%d = (Dog {barks: 2})
|
|
assume (type of %d) == "Dog"
|
|
assume (%d is a "Dog")
|
|
assume %d.barks == 2
|
|
assume ((%d::bark) == "Bark! Bark!")
|
|
assume ((%d::woof) == "Bark! Bark!")
|
|
%d::get pissed off
|
|
assume (%d.barks == 3)
|
|
assume ((%d::bark) == "Bark! Bark! Bark!")
|
|
assume (%d.genus == "Canus")
|
|
assume ("\(%d.class)" == "Dog")
|
|
assume (%d.genus == "Canus")
|
|
assume (%d.barks == 3)
|
|
%d2 = (Dog {})
|
|
assume (%d2.barks == 0) or barf "Default initializer failed"
|
|
with {%d: Dog {barks: 1}}:
|
|
assume ((%d::bark) == "Bark!")
|
|
|
|
object (Corgi) extends (Dog):
|
|
my action [sploot] "splooted"
|
|
my action [bark, woof]:
|
|
%barks = [: for % in 1 to %me.barks: add "Yip!"]
|
|
return (%barks::joined with " ")
|
|
|
|
%corg = (Corgi {})
|
|
assume (%corg.barks == 0)
|
|
with {%d: Corgi {barks: 1}}:
|
|
assume ((%d::sploot) == "splooted") or barf "subclass method failed"
|
|
assume ((%d::bark) == "Yip!") or barf "inheritance failed"
|
|
assume ((%d::woof) == "Yip!")
|
|
|
|
with {%d: Dog {barks: 2}}:
|
|
assume ((%d::bark) == "Bark! Bark!")
|
|
|
|
(my action %actions %body) compiles to:
|
|
lua> "\
|
|
..local fn_name = \%actions[1].stub:as_lua_id()
|
|
local \%args = List(\%actions[1]:get_args())
|
|
table.insert(\%args, 1, \(\%me))
|
|
local lua = LuaCode("class.", fn_name, " = ", \(what (%args -> %body) compiles to))
|
|
for i=2,#\%actions do
|
|
local alias = \%actions[i]
|
|
local alias_name = alias.stub:as_lua_id()
|
|
local \%alias_args = List(alias:get_args())
|
|
table.insert(\%alias_args, 1, \(\%me))
|
|
lua:append("\\nclass.", alias_name, " = ")
|
|
if \%args == \%alias_args then
|
|
lua:append("class.", fn_name)
|
|
else
|
|
lua:append(\(what (%alias_args -> %actions.1) compiles to))
|
|
end
|
|
end
|
|
return lua"
|
|
|
|
(object %classname extends %parent %class_body) compiles to:
|
|
unless (%classname.type == "Action"):
|
|
compile error at %classname "\
|
|
..Expected this to be an action, not a \%classname.type"
|
|
|
|
for % in %classname:
|
|
unless (% is text):
|
|
compile error at % "Class names should not have arguments."
|
|
|
|
return (..)
|
|
Lua "\
|
|
..do
|
|
local class = {name=\(quote %classname.stub)}
|
|
class.__type = class.name
|
|
setmetatable(class, {
|
|
__index=\(%parent as lua expr),
|
|
__tostring=function(cls) return cls.name end,
|
|
__call=function(cls, inst)
|
|
if inst == nil then return cls end
|
|
inst = setmetatable(inst, cls)
|
|
if inst.set_up then inst:set_up() end
|
|
return inst
|
|
end,
|
|
})
|
|
_ENV[class.name:as_lua_id()] = class
|
|
class.__index = class
|
|
class.class = class
|
|
class.__tostring = function(inst)
|
|
return inst.name..getmetatable(Dict{}).__tostring(inst)
|
|
end
|
|
\(%class_body as lua)
|
|
for stub,metamethod in pairs(globals.METAMETHOD_MAP) do
|
|
class[metamethod] = class[stub:as_lua_id()]
|
|
end
|
|
end"
|
|
|
|
(object %classname %class_body) parses as (..)
|
|
object %classname extends (nil) %class_body
|