最終更新 1737091028

lgame.lua Raw Playground
1local Space = require("lspace")
2local enemies = {}
3local r, f, l, box, tuples, rules = Space()
4
5local function p(...)
6 local args = {...}
7 return function() print(table.unpack(args)) end
8end
9
10function espawn(vars)
11 print("Spawning "..vars.enemy.." at "..vars.x..", "..vars.y)
12 table.insert(enemies, {t=vars.enemy, x=vars.x,y=vars.y})
13end
14
15f('play level 1')
16r('play level 1').so(
17 p"Started Level 1!",
18 'spawn a flyer at 60 10',
19 'spawn a flyer at 60 20',
20 'spawn a flyer at 60 30',
21 'playing level 1'
22)
23r('spawn a $enemy at $x $y').so(espawn)
24r('spawn an $enemy at $x $y').so(espawn)
25r('playing level 1', 'all enemies are dead').so(p'LEVEL 2', 'play level 2')
26r('there are $some enemies').so(
27 function(v)
28 -- print("some", v.some, type(v.some))
29 if v.some == "0" then f('all enemies are dead') end
30 end
31 )
32r('an enemy died').so(
33 function(_) print('ded') f('there are '.. #enemies..' enemies') end
34)
35
36r('a','b','c').so(p'a,b&c')
37f('a')
38f('b')
39f('letters '..l('a', 'b', 'c'))
40f('c')
41r('a', 'b').so(p'a&b',"a and b")
42r('MYVARR $vals').so(function(vars) print(table.unpack(vars.vals)) end)
43box('MYVARR', {1,2,3,4})
44
45print("***************************")
46for _, t in ipairs(tuples) do
47 print(t, table.unpack(t))
48end
49
50print("***************************")
51function kill()
52 table.remove(enemies, 1)
53 f('an enemy died')
54end
55
56kill()
57kill()
58kill()
59
60print("***************************")
61
62for _, t in ipairs(tuples) do
63 print(table.unpack(t))
64end
65
lspace.lua Raw Playground
1local symbIdx = 1
2
3local function log(...)
4 local toLog = {}
5 for i,v in ipairs({...}) do
6 print(i, tostring(v))
7 toLog[i] = tostring(v)
8 end
9 print(table.unpack(toLog))
10end
11
12local function getenv(env, k)
13 if env.vars[k] then
14 return env.vars[k]
15 elseif env._parent then
16 return getenv(env._parent, k)
17 else
18 return nil
19 end
20end
21
22local function setenv(env, k, v)
23 env.vars[k] = v
24end
25
26local envmt = { __index = getenv }
27
28local function proxy(env)
29 local ret = {}
30 local mt = {}
31 function mt:__index(k)
32 return getenv(env, k)
33 end
34 setmetatable(ret, mt)
35 return ret
36end
37
38local varmt = { __tostring = function(s) return "var="..s.var end }
39local litmt = { __tostring = function(s) return "lit="..s.lit end }
40
41local function env(parent)
42 local ret = { _parent = parent, vars = {} }
43 -- setmetatable(ret, envmt)
44 return ret
45end
46
47local function LSpace()
48 local tuples = {}
49 local toDel = {}
50 local rules = {}
51
52 function genSym() local ret = "_"..symbIdx symbIdx = symbIdx + 1 return ret end
53
54 function add(rule) table.insert(rules, rule) end
55
56 function matchPhrases(todos, phrases, pidx, vars, tuples)
57 -- print("PIDX", pidx, #phrases)
58 local anyMatch = false
59 local phrase = phrases[pidx]
60 for ti=#tuples, 1,-1 do
61 local rowVars = env(vars)
62 local tuple = tuples[ti]
63 -- log("Testing Tuple", table.unpack(tuple))
64 if not tuple then
65 goto nomatch
66 end
67 if #phrase ~= #tuple then
68 -- print("len nomatch")
69 goto nomatch
70 end
71 if toDel[ti] then
72 goto nomatch
73 end
74 for i=1,#tuple do
75 local t, w = tuple[i], phrase[i]
76 if w.lit and t ~= w.lit then
77 -- print("lit ", t, w, "nomatch")
78 goto nomatch
79 end
80 if w.var then
81 local v = getenv(rowVars, w.var)
82 if v and v ~= t then
83 -- print("var ", t, w, "nomatch")
84 goto nomatch
85 elseif not v then
86 setenv(rowVars, w.var, t)
87 end
88 end
89 end
90 if #phrases == pidx then
91 -- print("YO!")
92 --table.remove(tuples, ti)
93 toDel[ti] = true
94 anyMatch = true
95 for _,todo in ipairs(todos) do
96 todo(proxy(rowVars))
97 -- table.insert(matches, ti)
98 end
99 elseif pidx < #phrases then
100 -- print("OY!")
101 if matchPhrases(todos, phrases, pidx+1, env(rowVars), tuples) then
102 toDel[ti]=true
103 anyMatch=true
104 end
105 end
106 ::nomatch::
107 end
108 return anyMatch
109 end
110
111 function match(rules, tuples)
112 for _, rule in ipairs(rules) do
113 local vars = env()
114 local matched = true
115 local tuple = tuples[ti]
116 --local matchIds =
117 matchPhrases(rule.consequents, rule.phrases, 1, vars, tuples)
118 local removing = {}
119 for k in pairs(toDel) do
120 table.insert(removing, k)
121 toDel[k] = nil
122 end
123 -- print("matched",table.unpack(matchIds))
124 table.sort(removing)
125 for i=#removing,1,-1 do
126 table.remove(tuples, removing[i])
127 end
128 end
129 end
130
131 function makeRuleStr(r)
132 local rule = { }
133 for w in r:gmatch("%S+") do
134 if w:match("^%$") then
135 local p = { var=w:sub(2) }
136 setmetatable(p, varmt)
137 table.insert(rule, p)
138 else
139 local p = { lit=w }
140 setmetatable(p, litmt)
141 table.insert(rule, p)
142 end
143 end
144 return rule
145 end
146
147 function list(...)
148 local t, vars, parts = {}, {}, {...}
149 local prevSym = genSym()
150 local headSym = prevSym
151 for i,p in ipairs(parts) do
152 if type(p) == "string" then
153 t = {}
154 t[#t+1] = prevSym
155 for w in p:gmatch("%S+") do
156 if w:match("^%$") then
157 vars[w] = vars[w] or genSym()
158 t[#t+1] = vars[w]
159 else t[#t+1] = w end
160 end
161 prevSym = genSym()
162 t[#t+1] = prevSym
163 table.insert(tuples, t)
164 end
165 end
166 t[#t] = nil
167 match(rules, tuples)
168 return headSym
169 end
170
171 function box(n, t)
172 local sym = genSym()
173 table.insert(tuples, { n, t })
174 match(rules, tuples)
175 return n.." "..sym
176 end
177
178 function fact(...)
179 local t, vars, parts = {}, {}, {...}
180 for i,p in ipairs(parts) do
181 if type(p) == "string" then
182 for w in p:gmatch("%S+") do
183 if w:match("^%$") then
184 vars[w] = vars[w] or genSym()
185 t[#t+1] = vars[w]
186 else t[#t+1] = w end
187 end
188 table.insert(tuples, t)
189 t = {}
190 end
191 end
192 match(rules, tuples)
193 end
194
195 function rule(...)
196 local ruleDef = {
197 phrases = {},
198 consequents = {},
199 }
200 local ruleTemps = {...}
201 for i,r in ipairs(ruleTemps) do
202 if type(r) == "string" then
203 table.insert(ruleDef.phrases, makeRuleStr(r))
204 else
205 error("Cannot make rule out of nonstring")
206 end
207 end
208
209 function so(...)
210 local consequents = {...}
211 for i, c in ipairs(consequents) do
212 if type(c) == "string" then
213 table.insert(ruleDef.consequents, function(vars)
214 fact(c:gsub("(%$%S+)", function(var)
215 vars[var] = vars[var] or genSym()
216 return vars[var]
217 end))
218 end)
219 elseif type(c) == "function" then
220 table.insert(ruleDef.consequents, c)
221 else
222 error("Cannot add a consequent that isn't a string or function!")
223 end
224 end
225 add(ruleDef)
226 match(rules, tuples)
227 end
228 return { so=so }
229 end
230
231 return rule, fact, list, box, tuples, rules
232end
233
234return LSpace
235