1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
%globals.METAMETHOD_MAP = {..}
"as text": "__tostring", "clean up": "__gc",
"+": "__add", "-": "__sub", "*": "__mul", "/": "__div",
"negative": "__unm", "//": "__idiv", "mod": "__mod", "^": "__pow",
"&": "__band", "|": "__bor", "~": "__bxor", "~": "__bnot",
"<<": "__bshl", ">>": "__bshr", "==": "__eq", "<": "__lt",
"<=": "__le", "set 1 =": "__newindex", "size": "__len",
"iterate": "__ipairs", "iterate all": "__pairs",
test:
a (Dog) is a thing:
that can (set up) by:
%its.barks or= 0
whose [bark, woof] all mean:
%barks = ("Bark!" for % in 1 to %its.barks)
return (%barks::joined with " ")
that can (get pissed off) by:
%its.barks += 1
(Dog).genus = "Canus"
%d = (a Dog with {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 = (a Dog)
assume (%d2.barks == 0) or barf "Default initializer failed"
with {%d:a Dog with {barks:1}}:
assume ((%d::bark) == "Bark!")
a (Corgi) is a thing:
that can [set up, get pissed off] like a (Dog)
whose (sploot) means "splooted"
whose [bark, woof] all mean:
%barks = ("Yip!" for % in 1 to %its.barks)
return (%barks::joined with " ")
%corg = (a Corgi)
assume (%corg.barks == 0)
with {%d:a Corgi with {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:a Dog with {barks:2}}:
assume ((%d::bark) == "Bark! Bark!")
[..]
that can %actions by %body,
whose %actions means %body, whose %actions all mean %body,
..all compile to:
unless (%actions.type == "List"): %actions = [%actions]
lua> "\
..local fn_name = \%actions[1].stub:as_lua_id()
local \%args = List{\(\%its), unpack(\%actions[1]:get_args())}
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{\(\%its), unpack(alias:get_args())}
lua:append("\\nclass.", alias_name, " = ")
if \%alias_args == \%args then
lua:append("class.", fn_name)
else
lua:append("function(")
lua:concat_append(table.map(\%alias_args, function(a) return compile(a) end), ", ")
lua:append(")\\n return class.", fn_name, "(")
lua:concat_append(table.map(\%args, function(a) return compile(a) end), ", ")
lua:append(")\\nend")
end
end
return lua"
[..]
that can %actions like a %class, that can %actions like an %class,
that has %actions like a %class, that has %actions like an %class,
..all compile to:
%lua = (Lua "")
%class_expr = (%class as lua expr)
%lines = []
for %a in %actions:
%lines::add "class.\(%a.stub::as lua id) = \%class_expr.\(%a.stub::as lua id)"
%lua::add %lines joined with "\n"
return %lua
(a %classname is a thing with %members %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, {
__tostring=function(cls) return cls.name end,
__call=function(cls, inst)
inst = setmetatable(inst or {}, cls)
if inst.set_up then inst:set_up() end
return inst
end,
})
class.__members = \(%members as lua expr)
_ENV[("a "..class.name):as_lua_id()] = class
_ENV[("an "..class.name):as_lua_id()] = class
_ENV[("a "..class.name.." with"):as_lua_id()] = class
_ENV[("an "..class.name.." with"):as_lua_id()] = class
_ENV[class.name:as_lua_id()] = function() return class end
class.__index = class
class.class = class
local dict_tostring = getmetatable(Dict{}).__tostring
class.__tostring = function(inst)
return inst.name..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
if class.__members then
assert(select(2, next(class.__members)) == true)
getmetatable(class).__newindex = function(its, key, value)
if class.__members[key] then
rawset(its, key, value)
else error("Not a valid member: "..tostring(key)) end
end
end
end"
(a %classname is a thing %class_body) parses as (a %classname is a thing with (nil) %class_body)
|