-
Notifications
You must be signed in to change notification settings - Fork 6
/
metalanguage-smoketest.lua
137 lines (120 loc) · 3.1 KB
/
metalanguage-smoketest.lua
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
local metalanguage = require "metalanguage"
local testlanguage = require "testlanguage"
local format = require "test-format-adapter"
---@class Env
---@field dict { [any]: any }
local Env = {}
local env_mt
---@param name any
---@return any
function Env:get(name)
return self.dict[name]
end
function Env:without(name)
local res = {}
for k, v in pairs(self.dict) do
if k ~= name then
res[k] = v
end
end
return setmetatable({ dict = res }, env_mt)
end
env_mt = {
__add = function(self, other)
local res = {}
for k, v in pairs(self.dict) do
res[k] = v
end
for k, v in pairs(other.dict) do
if res[k] ~= nil then
error("names in environments being merged must be disjoint, but both environments have " .. k)
end
res[k] = v
end
return setmetatable({ dict = res }, env_mt)
end,
__index = Env,
__tostring = function(self)
local message = "env{"
local fields = {}
for k, v in pairs(self.dict) do
fields[#fields + 1] = tostring(k) .. " = " .. tostring(v)
end
message = message .. table.concat(fields, ", ") .. "}"
return message
end,
}
---@param dict any
---@return Env
local function newenv(dict)
return setmetatable({ dict = dict }, env_mt)
end
-- for k, v in pairs(lang) do print(k, v) end
local symbol, value, list = metalanguage.symbol, metalanguage.value, metalanguage.list
--[[
local code =
list(
symbol "+",
value(1),
value(2)
)
--]]
local src = "do (val x = 6) (+ x 3)"
local code = format.read(src, "inline")
local function do_block_pair_handler(env, a, b)
local ok, val, newenv = a:match({
testlanguage.evaluates(metalanguage.accept_handler, env),
}, metalanguage.failure_handler, nil)
if not ok then
return false, val
end
--print("do block pair handler", ok, val, newenv, b)
return true, true, val, newenv, b
end
local function do_block_nil_handler(env)
return true, false
end
local function do_block(syntax, env)
local res = nil
local ok, ispair, val, newenv, tail = true, true, nil, env, nil
while ok and ispair do
ok, ispair, val, newenv, tail = syntax:match({
metalanguage.ispair(do_block_pair_handler),
metalanguage.isnil(do_block_nil_handler),
}, metalanguage.failure_handler, newenv)
--print("do block", ok, ispair, val, newenv, tail)
if not ok then
return false, ispair
end
if ispair then
res = val
syntax = tail
end
end
return true, res, env
end
local function val_bind(syntax, env)
local ok, name, val = syntax:match({
metalanguage.listmatch(
metalanguage.accept_handler,
metalanguage.issymbol(metalanguage.accept_handler),
metalanguage.symbol_exact(metalanguage.accept_handler, "="),
testlanguage.evaluates(metalanguage.accept_handler, env)
),
}, metalanguage.failure_handler, nil)
--print("val bind", ok, name, _, val)
if not ok then
return false, name
end
return true, value(nil), env + newenv { [name] = val }
end
local env = newenv {
["+"] = testlanguage.primitive_applicative(function(a, b)
return a + b
end),
["do"] = testlanguage.primitive_operative(do_block),
val = testlanguage.primitive_operative(val_bind),
}
local ok, res = testlanguage.eval(code, env)
print(ok, res)
print(res[1])