forked from regb/scala-smtlib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathParserUtils.scala
122 lines (102 loc) · 2.96 KB
/
ParserUtils.scala
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
package smtlib
package parser
import lexer.Tokens
import Tokens.{Token, TokenKind}
import lexer.Lexer
import scala.collection.mutable.ListBuffer
trait ParserUtils {
val lexer: Lexer
import Parser._
private var _currentToken: Token = null
/* lookAhead token is Some(null) if we reached eof */
private var _lookAhead: Option[Token] = None
//return a next token or throw UnexpectedEOFException if the next token is null
protected def nextToken(): Token = {
_lookAhead match {
case Some(t) => {
_lookAhead = None
_currentToken = t
t
}
case None => {
_currentToken = lexer.nextToken
_lookAhead = None
_currentToken
}
}
}
/*
* return the look ahead token, or null if EOF
* Note: do not throw an exception as it is okay to lookahead into EOF
*/
protected def peekToken: Token = {
_lookAhead match {
case Some(t) => t
case None => {
_lookAhead = Some(lexer.nextToken)
_lookAhead.get
}
}
}
/*
* Same as peekToken, but expect a token to be present
* and result in a UnexpectedEOFException if the token is null
*/
protected def getPeekToken: Token = {
val tmp = peekToken
if(tmp == null)
throw new UnexpectedEOFException(Seq())
tmp
}
/*
* Make sure the next token has the expected kind and read it
*/
protected def eat(expected: TokenKind): Unit = {
val token = nextToken
check(token, expected)
}
/*
* Make sure the next token is exactly ``expected`` (usually a symbol lit)
*/
protected def eat(expected: Token): Unit = {
val token = nextToken
if(token != expected)
throw new UnexpectedTokenException(token, Seq(expected.kind))
}
protected def check(current: Token, exp: TokenKind): Unit = {
if(current == null)
throw new UnexpectedEOFException(Seq(exp))
if(current.kind != exp) {
expected(current, exp)
}
}
protected def parseUntil[A](endKind: TokenKind, eatEnd: Boolean = true)(parseFun: () => A): Seq[A] = {
val items = new ListBuffer[A]
while(peekToken != null && peekToken.kind != endKind)
items.append(parseFun())
if(eatEnd)
eat(endKind)
items.toList
}
protected def parseMany[A](parseFun: () => A): Seq[A] = {
eat(Tokens.OParen)
parseUntil(Tokens.CParen)(parseFun)
}
/* Parse a sequence of A inside () */
protected def parseOneOrMore[A](parseFun: () => A): (A, Seq[A]) = {
val items = new ListBuffer[A]
eat(Tokens.OParen)
val head = parseFun()
while(peekToken != null && peekToken.kind != Tokens.CParen)
items.append(parseFun())
eat(Tokens.CParen)
(head, items.toList)
}
//TODO: we need a token class/type, instead of precise token with content + position
protected def expected(found: Token, expected: TokenKind*): Nothing = {
if(found == null)
throw new UnexpectedEOFException(expected)
else
throw new UnexpectedTokenException(found, expected)
}
}