/
parser.ms
88 lines (75 loc) · 2.16 KB
/
parser.ms
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
import "importUtil"
ensureImport "mapUtil"
ensureImport "tokens"
ensureImport "lexer"
ensureImport "parselets"
ensureImport "precedence"
Parser = {}
Parser.tokens = null // a lexer (source of tokens)
Parser.read = null // list of tokens already read
Parser.prefixParselets = null // map, key: TokenType; value: PrefixParselet
Parser.infixParselets = null // map, key: TokenType; value: InfixParselet
Parser.error = null
Parser.init = function(text)
self.tokens = (new Lexer).init(text)
self.read = []
self.prefixParselets = {}
self.infixParselets = {}
return self
end function
Parser.throwError = function(msg)
if not self.error then
self.error = msg
print "Error: " + msg
pprint stackTrace
end if
end function
Parser.register = function(tokenType, parselet)
if parselet isa PrefixParselet then
self.prefixParselets[tokenType] = parselet
else
self.infixParselets[tokenType] = parselet
end if
end function
Parser.parseExpression = function(precedence = 0)
token = self.consume
prefix = self.prefixParselets.get(token.type)
if not prefix then
self.throwError "Could not parse """ + token.text + """."
return
end if
left = prefix.parse(self, token)
while precedence < self.getPrecedence and not self.error
token = self.consume
infix = self.infixParselets.get(token.type)
left = infix.parse(self, left, token)
end while
return left
end function
Parser.match = function(expectedTokenType)
token = self.lookAhead
if token.type != expectedTokenType then return false
self.consume
return true
end function
Parser.consume = function(expectedTokenType=null)
token = self.lookAhead
if expectedTokenType and token.type != expectedTokenType then
self.throwError "Expected token " + expectedTokenType +
" and found " + token.type
end if
return self.read.pull
end function
Parser.lookAhead = function(distance=0)
// Read in as many as needed.
while distance >= self.read.len
self.read.push self.tokens.next
end while
// Get the queued token.
return self.read[distance]
end function
Parser.getPrecedence = function
parser = self.infixParselets.get(self.lookAhead.type)
if parser != null then return parser.precedence
return 0
end function