-
Notifications
You must be signed in to change notification settings - Fork 52
Expand file tree
/
Copy pathAstPositionsTests.scala
More file actions
204 lines (194 loc) · 7.11 KB
/
Copy pathAstPositionsTests.scala
File metadata and controls
204 lines (194 loc) · 7.11 KB
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2011-2020 ETH Zurich.
import org.scalatest.funsuite.AnyFunSuite
import viper.silver.ast.Program
import viper.silver.frontend._
import viper.silver.logger.ViperStdOutLogger
import viper.silver.reporter.StdIOReporter
class AstPositionsTests extends AnyFunSuite {
object AstProvider extends ViperAstProvider(StdIOReporter(), ViperStdOutLogger("AstPositionsTestsLogger").get) {
def setCode(code: String): Unit = {
_input = Some(code)
}
override def reset(input: java.nio.file.Path): Unit = {
if (state < DefaultStates.Initialized) sys.error("The translator has not been initialized.")
_state = DefaultStates.InputSet
_inputFile = Some(input)
/** must be set by [[setCode]] */
// _input = None
_errors = Seq()
_parsingResult = None
_semanticAnalysisResult = None
_verificationResult = None
_program = None
resetMessages()
}
}
def generateViperAst(code: String): Option[Program] = {
val code_id = code.hashCode.asInstanceOf[Short].toString
AstProvider.setCode(code)
AstProvider.execute(Seq("--ignoreFile", code_id))
if (AstProvider.errors.isEmpty) {
Some(AstProvider.translationResult)
} else {
AstProvider.logger.error(s"An error occurred while translating ${AstProvider.errors}")
None
}
}
test("Correct positions for methods in a parsed program") {
import viper.silver.ast._
val code =
"""field foo: Int
|method sum(x: Ref, g: Set[Ref])
| returns (res: Bool)
| ensures false && 4/x.foo > 0
| ensures 3 < 4 < 5
|{
| inhale forall r: Ref :: r in g ==> acc(r.foo)
| assert acc(x.foo)
| var r1: Ref
| assume r1 in g
|}
|method bar(r: Ref)
| requires 0 > r . foo
|// Comment
|function end(): Ref""".stripMargin
val res: Program = generateViperAst(code).get
// Check position of field
assert(res.fields.length === 1)
val f: Field = res.fields(0)
f.pos match {
case spos: AbstractSourcePosition =>
assert(spos.start.line === 1 && spos.end.get.line === 1)
// Here it is unclear if we want to include the `field ` part in the pos
assert(spos.start.column === 1 || spos.start.column === 7)
assert( spos.end.get.column === 15)
case _ =>
fail("fields must have start and end positions set")
}
// Check position of method
assert(res.methods.length === 2)
val m: Method = res.methods(0)
m.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 2 && spos.end.get.line === 11)
assert(spos.start.column === 1 && spos.end.get.column === 2)
}
case _ =>
fail("methods must have start and end positions set")
}
// Check position of method arg
assert(m.formalArgs.length === 2)
val fa: LocalVarDecl = m.formalArgs(0)
fa.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 2 && spos.end.get.line === 2)
assert(spos.start.column === 12 && spos.end.get.column === 13)
}
case _ =>
fail("method args must have start and end positions set")
}
// Check positions of method posts
assert(m.posts.length === 2)
val post1: Exp = m.posts(0).asInstanceOf[BinExp].args(1);
post1.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 4 && spos.end.get.line === 4)
assert(spos.start.column === 20 && spos.end.get.column === 31)
}
case _ =>
fail("method posts must have start and end positions set")
}
val post2: BinExp = m.posts(1).asInstanceOf[BinExp]
post2.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 5 && spos.end.get.line === 5)
assert(spos.start.column === 11 && spos.end.get.column === 20)
}
case _ =>
fail("method posts must have start and end positions set")
}
post2.left.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 5 && spos.end.get.line === 5)
assert(spos.start.column === 11 && spos.end.get.column === 16)
}
case _ =>
fail("method posts must have start and end positions set")
}
post2.right.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 5 && spos.end.get.line === 5)
assert(spos.start.column === 15 && spos.end.get.column === 20)
}
case _ =>
fail("method posts must have start and end positions set")
}
// Check position of body
val block = m.body.get
block.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 6 && spos.end.get.line === 11)
assert(spos.start.column === 1 && spos.end.get.column === 2)
}
case _ =>
fail("statements must have start and end positions set")
}
// Check position of forall
assert(block.ss.length === 4)
val forall: Stmt = block.ss(0)
forall.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 7 && spos.end.get.line === 7)
assert(spos.start.column === 3 && spos.end.get.column === 48)
}
case _ =>
fail("forall must have start and end positions set")
};
// Check position of assert
val assert_exp: Exp = block.ss(1).asInstanceOf[Assert].exp
assert_exp.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 8 && spos.end.get.line === 8)
assert(spos.start.column === 10 && spos.end.get.column === 20)
}
case _ =>
fail("forall must have start and end positions set")
}
// Check position of second method
val m2: Method = res.methods(1);
m2.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 12 && spos.end.get.line === 13)
assert(spos.start.column === 1 && spos.end.get.column === 26)
}
case _ =>
fail("methods must have start and end positions set")
}
// Check position of second method precond
val pre: Exp = m2.pres(0);
pre.pos match {
case spos: AbstractSourcePosition => {
assert(spos.start.line === 13 && spos.end.get.line === 13)
assert(spos.start.column === 13 && spos.end.get.column === 26)
}
case _ =>
fail("methods must have start and end positions set")
}
// Check position of function
assert(res.functions.length === 1)
val fn: Function = res.functions(0)
fn.pos match {
case spos: AbstractSourcePosition =>
assert(spos.start.line === 15 && spos.end.get.line === 15)
// Here it is unclear if we want to include the `function ` part in the pos
assert(spos.start.column === 1 || spos.start.column === 10)
assert(spos.end.get.column === 20)
case _ =>
fail("functions must have start and end positions set")
}
}
}