-
Notifications
You must be signed in to change notification settings - Fork 205
/
pratttest.t
82 lines (72 loc) · 2.9 KB
/
pratttest.t
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
--import that Parser object (called P in the lib/parsing.t file)
local Parser = require("parsing")
--define a table that implements our language
local lang = {}
--rule for leftassociative binary operators
--P is the interface to the parser
--it contains (1) all of the functions defined in the lexer object
--(2) methods that invoke the rules for non-terminals in our language
--(e.g. P:exp() will run the exp rule defined below, P:simpleexp() will run the simpleexp rule)
local function leftbinary(P,lhs)
local op = P:next().type
local rhs = P:exp(op) --parse the rhs, passing 'op' to the exp rule indicates we want
--to parse only expressions with higher precedence than 'op'
--this will result in left-associative operators
return { name = op, lhs = lhs, rhs = rhs } --build the ast
end
local function rightbinary(P,lhs)
local op = P:next().type
local rhs = P:exp(op,"right") --parse the rhs, passing 'op' and then specify "right" associativity
--indicates to parse expressions with precedence equal-to or higher-than 'op'
--this will result in right associative operators
return { name = op, lhs = lhs, rhs = rhs }
end
lang.exp = Parser.Pratt()
:prefix("-",function(P)
P:next()
local v = P:exp(3) --precedence can also be specified with a number directly
--here we use 3 to unary minus higher precidence than binary minus
return { name = "uminus", arg = v }
end)
:infix("-",1,leftbinary)
:infix("+",1,leftbinary)
:infix("*",2,leftbinary)
:infix("/",2,leftbinary)
:infix("^",3,rightbinary)
--default rules fire when no other rule is defined for the token
--here we invoke another rule 'simpleexp'
:prefix(Parser.default, function(P) return P:simpleexp() end)
lang.simpleexp = function(P)
local v = P:prefixexp()
if P:nextif("(") then --function application
local arg = P:exp()
P:expect(")")
return { name = "call", fn = v, arg = arg }
else
return v
end
end
lang.prefixexp = function (P)
if P:nextif("(") then --expression in parens
local v = P:exp() --if you do not give a precedence
--it assumes you want to parse an expression of _any_ precedence
P:expect(")")
return v
elseif P:matches(P.name) or P:matches(P.number) then
return P:next().value
else
P:error("unexpected symbol") --the API automatically adds context information to errors.
end
end
return {
name = "pratttest";
entrypoints = {"goexp"};
keywords = {};
expression = function(self,lexer)
lexer:expect("goexp")
--Parse runs our parser by combining our language 'lang' with the lexer
--"exp" indicates we want to start parsing an exp non-terminal.
local ast = Parser.Parse(lang,lexer,"exp")
return function(exp) return ast end
end;
}