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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
local expr_lexer = require 'expr-lexer'
local function accept(lexer, token_type)
if lexer.token.type == token_type then
lexer:next()
return true
end
return false
end
local function expect(lexer, token_type)
if not accept(lexer, token_type) then
lexer:local_error("expecting " .. token_type)
end
end
local expr
local function factor(lexer, actions)
local token = lexer.token
if token.type == 'ident' then
local id = token.value
lexer:next()
if accept(lexer, '(') then
local arg = expr(lexer, actions, 0)
expect(lexer, ')')
return actions.func_eval(id, arg)
else
return actions.ident(id)
end
elseif token.type == 'literal' then
local x = token.value
lexer:next()
return actions.literal(x)
elseif token.type == 'number' then
local x = token.value
lexer:next()
return actions.number(x)
elseif token.type == '(' then
lexer:next()
local a = expr(lexer, actions, 0)
expect(lexer, ')')
return a
elseif token.type == 'operator' and token.symbol == '%' then
lexer:next()
if lexer.token.type ~= 'ident' then
lexer:local_error("expecting identifier:")
end
local id = lexer.token.value
lexer:next()
return actions.enum(id)
end
lexer:local_error('unexpected symbol:')
end
local function ident_singleton(lexer, actions)
local token = lexer.token
if token.type == 'ident' then
local id = token.value
lexer:next()
if accept(lexer, '(') then
lexer:local_error('expecting simple identifier')
end
return actions.ident(id)
else
lexer:local_error('expecting simple identifier')
end
end
local max_oper_prio = expr_lexer.max_oper_prio
expr = function(lexer, actions, prio)
if prio > max_oper_prio then
return factor(lexer, actions)
end
local a
local token = lexer.token
if prio == 0 and token.type == 'operator' and token.symbol == '-' then
local symbol = token.symbol
lexer:next()
local b = expr(lexer, actions, prio + 1)
a = actions.prefix(symbol, b)
else
a = expr(lexer, actions, prio + 1)
end
token = lexer.token
while token.type == 'operator' and token.priority >= prio do
local symbol = token.symbol
accept(lexer, 'operator')
local b = expr(lexer, actions, prio + 1)
a, token = actions.infix(symbol, a, b), lexer.token
end
return a
end
local function expr_list(lexer, actions)
local a = expr(lexer, actions, 0)
local els = actions.exprlist(a)
while accept(lexer, ',') do
local b = expr(lexer, actions, 0)
els = actions.exprlist(b, els)
end
return els
end
local function ident_list(lexer, actions)
local a = ident_singleton(lexer, actions)
local els = actions.exprlist(a)
while accept(lexer, ',') do
local b = ident_singleton(lexer, actions)
els = actions.exprlist(b, els)
end
return els
end
local function enums(lexer, actions)
if accept(lexer, '|') then
return ident_list(lexer, actions)
end
return {}
end
local function conditions(lexer, actions)
if accept(lexer, ':') then
return expr_list(lexer, actions)
end
return {}
end
local function schema(lexer, actions, accept_enums)
local y = expr(lexer, actions, 0)
expect(lexer, '~')
local x = expr_list(lexer, actions)
local enums = accept_enums and enums(lexer, actions)
local conds = conditions(lexer, actions)
expect(lexer, 'EOF')
return actions.schema(x, y, conds, enums)
end
local function schema_multivar(lexer, actions)
local y = expr_list(lexer, actions, 0)
expect(lexer, '~')
local x = expr_list(lexer, actions)
local enums = enums(lexer, actions)
local conds = conditions(lexer, actions)
expect(lexer, 'EOF')
return actions.schema(x, y, conds, enums)
end
local expr_parse = {}
function expr_parse.schema(formula, actions, accept_enums)
local l = expr_lexer.new(formula)
return schema(l, actions, accept_enums)
end
function expr_parse.schema_multivar(formula, actions)
local l = expr_lexer.new(formula)
return schema_multivar(l, actions)
end
function expr_parse.expr(formula, actions)
local l = expr_lexer.new(formula)
return expr(l, actions, 0)
end
return expr_parse
|