lgame.lua
· 1.5 KiB · Lua
Raw
Playground
local Space = require("lspace")
local enemies = {}
local r, f, l, box, tuples, rules = Space()
local function p(...)
local args = {...}
return function() print(table.unpack(args)) end
end
function espawn(vars)
print("Spawning "..vars.enemy.." at "..vars.x..", "..vars.y)
table.insert(enemies, {t=vars.enemy, x=vars.x,y=vars.y})
end
f('play level 1')
r('play level 1').so(
p"Started Level 1!",
'spawn a flyer at 60 10',
'spawn a flyer at 60 20',
'spawn a flyer at 60 30',
'playing level 1'
)
r('spawn a $enemy at $x $y').so(espawn)
r('spawn an $enemy at $x $y').so(espawn)
r('playing level 1', 'all enemies are dead').so(p'LEVEL 2', 'play level 2')
r('there are $some enemies').so(
function(v)
-- print("some", v.some, type(v.some))
if v.some == "0" then f('all enemies are dead') end
end
)
r('an enemy died').so(
function(_) print('ded') f('there are '.. #enemies..' enemies') end
)
r('a','b','c').so(p'a,b&c')
f('a')
f('b')
f('letters '..l('a', 'b', 'c'))
f('c')
r('a', 'b').so(p'a&b',"a and b")
r('MYVARR $vals').so(function(vars) print(table.unpack(vars.vals)) end)
box('MYVARR', {1,2,3,4})
print("***************************")
for _, t in ipairs(tuples) do
print(t, table.unpack(t))
end
print("***************************")
function kill()
table.remove(enemies, 1)
f('an enemy died')
end
kill()
kill()
kill()
print("***************************")
for _, t in ipairs(tuples) do
print(table.unpack(t))
end
| 1 | local Space = require("lspace") |
| 2 | local enemies = {} |
| 3 | local r, f, l, box, tuples, rules = Space() |
| 4 | |
| 5 | local function p(...) |
| 6 | local args = {...} |
| 7 | return function() print(table.unpack(args)) end |
| 8 | end |
| 9 | |
| 10 | function 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}) |
| 13 | end |
| 14 | |
| 15 | f('play level 1') |
| 16 | r('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 | ) |
| 23 | r('spawn a $enemy at $x $y').so(espawn) |
| 24 | r('spawn an $enemy at $x $y').so(espawn) |
| 25 | r('playing level 1', 'all enemies are dead').so(p'LEVEL 2', 'play level 2') |
| 26 | r('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 | ) |
| 32 | r('an enemy died').so( |
| 33 | function(_) print('ded') f('there are '.. #enemies..' enemies') end |
| 34 | ) |
| 35 | |
| 36 | r('a','b','c').so(p'a,b&c') |
| 37 | f('a') |
| 38 | f('b') |
| 39 | f('letters '..l('a', 'b', 'c')) |
| 40 | f('c') |
| 41 | r('a', 'b').so(p'a&b',"a and b") |
| 42 | r('MYVARR $vals').so(function(vars) print(table.unpack(vars.vals)) end) |
| 43 | box('MYVARR', {1,2,3,4}) |
| 44 | |
| 45 | print("***************************") |
| 46 | for _, t in ipairs(tuples) do |
| 47 | print(t, table.unpack(t)) |
| 48 | end |
| 49 | |
| 50 | print("***************************") |
| 51 | function kill() |
| 52 | table.remove(enemies, 1) |
| 53 | f('an enemy died') |
| 54 | end |
| 55 | |
| 56 | kill() |
| 57 | kill() |
| 58 | kill() |
| 59 | |
| 60 | print("***************************") |
| 61 | |
| 62 | for _, t in ipairs(tuples) do |
| 63 | print(table.unpack(t)) |
| 64 | end |
| 65 |
lspace.lua
· 6.6 KiB · Lua
Raw
Playground
local symbIdx = 1
local function log(...)
local toLog = {}
for i,v in ipairs({...}) do
print(i, tostring(v))
toLog[i] = tostring(v)
end
print(table.unpack(toLog))
end
local function getenv(env, k)
if env.vars[k] then
return env.vars[k]
elseif env._parent then
return getenv(env._parent, k)
else
return nil
end
end
local function setenv(env, k, v)
env.vars[k] = v
end
local envmt = { __index = getenv }
local function proxy(env)
local ret = {}
local mt = {}
function mt:__index(k)
return getenv(env, k)
end
setmetatable(ret, mt)
return ret
end
local varmt = { __tostring = function(s) return "var="..s.var end }
local litmt = { __tostring = function(s) return "lit="..s.lit end }
local function env(parent)
local ret = { _parent = parent, vars = {} }
-- setmetatable(ret, envmt)
return ret
end
local function LSpace()
local tuples = {}
local toDel = {}
local rules = {}
function genSym() local ret = "_"..symbIdx symbIdx = symbIdx + 1 return ret end
function add(rule) table.insert(rules, rule) end
function matchPhrases(todos, phrases, pidx, vars, tuples)
-- print("PIDX", pidx, #phrases)
local anyMatch = false
local phrase = phrases[pidx]
for ti=#tuples, 1,-1 do
local rowVars = env(vars)
local tuple = tuples[ti]
-- log("Testing Tuple", table.unpack(tuple))
if not tuple then
goto nomatch
end
if #phrase ~= #tuple then
-- print("len nomatch")
goto nomatch
end
if toDel[ti] then
goto nomatch
end
for i=1,#tuple do
local t, w = tuple[i], phrase[i]
if w.lit and t ~= w.lit then
-- print("lit ", t, w, "nomatch")
goto nomatch
end
if w.var then
local v = getenv(rowVars, w.var)
if v and v ~= t then
-- print("var ", t, w, "nomatch")
goto nomatch
elseif not v then
setenv(rowVars, w.var, t)
end
end
end
if #phrases == pidx then
-- print("YO!")
--table.remove(tuples, ti)
toDel[ti] = true
anyMatch = true
for _,todo in ipairs(todos) do
todo(proxy(rowVars))
-- table.insert(matches, ti)
end
elseif pidx < #phrases then
-- print("OY!")
if matchPhrases(todos, phrases, pidx+1, env(rowVars), tuples) then
toDel[ti]=true
anyMatch=true
end
end
::nomatch::
end
return anyMatch
end
function match(rules, tuples)
for _, rule in ipairs(rules) do
local vars = env()
local matched = true
local tuple = tuples[ti]
--local matchIds =
matchPhrases(rule.consequents, rule.phrases, 1, vars, tuples)
local removing = {}
for k in pairs(toDel) do
table.insert(removing, k)
toDel[k] = nil
end
-- print("matched",table.unpack(matchIds))
table.sort(removing)
for i=#removing,1,-1 do
table.remove(tuples, removing[i])
end
end
end
function makeRuleStr(r)
local rule = { }
for w in r:gmatch("%S+") do
if w:match("^%$") then
local p = { var=w:sub(2) }
setmetatable(p, varmt)
table.insert(rule, p)
else
local p = { lit=w }
setmetatable(p, litmt)
table.insert(rule, p)
end
end
return rule
end
function list(...)
local t, vars, parts = {}, {}, {...}
local prevSym = genSym()
local headSym = prevSym
for i,p in ipairs(parts) do
if type(p) == "string" then
t = {}
t[#t+1] = prevSym
for w in p:gmatch("%S+") do
if w:match("^%$") then
vars[w] = vars[w] or genSym()
t[#t+1] = vars[w]
else t[#t+1] = w end
end
prevSym = genSym()
t[#t+1] = prevSym
table.insert(tuples, t)
end
end
t[#t] = nil
match(rules, tuples)
return headSym
end
function box(n, t)
local sym = genSym()
table.insert(tuples, { n, t })
match(rules, tuples)
return n.." "..sym
end
function fact(...)
local t, vars, parts = {}, {}, {...}
for i,p in ipairs(parts) do
if type(p) == "string" then
for w in p:gmatch("%S+") do
if w:match("^%$") then
vars[w] = vars[w] or genSym()
t[#t+1] = vars[w]
else t[#t+1] = w end
end
table.insert(tuples, t)
t = {}
end
end
match(rules, tuples)
end
function rule(...)
local ruleDef = {
phrases = {},
consequents = {},
}
local ruleTemps = {...}
for i,r in ipairs(ruleTemps) do
if type(r) == "string" then
table.insert(ruleDef.phrases, makeRuleStr(r))
else
error("Cannot make rule out of nonstring")
end
end
function so(...)
local consequents = {...}
for i, c in ipairs(consequents) do
if type(c) == "string" then
table.insert(ruleDef.consequents, function(vars)
fact(c:gsub("(%$%S+)", function(var)
vars[var] = vars[var] or genSym()
return vars[var]
end))
end)
elseif type(c) == "function" then
table.insert(ruleDef.consequents, c)
else
error("Cannot add a consequent that isn't a string or function!")
end
end
add(ruleDef)
match(rules, tuples)
end
return { so=so }
end
return rule, fact, list, box, tuples, rules
end
return LSpace
| 1 | local symbIdx = 1 |
| 2 | |
| 3 | local 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)) |
| 10 | end |
| 11 | |
| 12 | local 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 |
| 20 | end |
| 21 | |
| 22 | local function setenv(env, k, v) |
| 23 | env.vars[k] = v |
| 24 | end |
| 25 | |
| 26 | local envmt = { __index = getenv } |
| 27 | |
| 28 | local 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 |
| 36 | end |
| 37 | |
| 38 | local varmt = { __tostring = function(s) return "var="..s.var end } |
| 39 | local litmt = { __tostring = function(s) return "lit="..s.lit end } |
| 40 | |
| 41 | local function env(parent) |
| 42 | local ret = { _parent = parent, vars = {} } |
| 43 | -- setmetatable(ret, envmt) |
| 44 | return ret |
| 45 | end |
| 46 | |
| 47 | local 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 |
| 232 | end |
| 233 | |
| 234 | return LSpace |
| 235 |