@@ -15,7 +15,11 @@ import scala.util.boundary
15
15
import scala .util .boundary .break
16
16
17
17
18
- case class Fail (message : String , position : Int ) extends Throwable (null , null , false , false )
18
+ case class Fail (msg : String , position : Int ) extends Throwable (null , null , false , false )
19
+ object Fail {
20
+ def expectedButGot (expected : String , got : String , position : Int ): Fail =
21
+ Fail (s " Expected ${expected} but got ${got}" , position)
22
+ }
19
23
case class SoftFail (message : String , positionStart : Int , positionEnd : Int )
20
24
21
25
class RecursiveDescent (positions : Positions , tokens : Seq [Token ], source : Source ) {
@@ -67,6 +71,17 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
67
71
case Fail (msg, pos) => kiama.parsing.Error (msg, input.copy(offset = pos))
68
72
}
69
73
74
+ var currentLabel : Option [String ] = None
75
+
76
+ extension[T ](inline p : => T ) inline def labelled (inline label : String ): T = {
77
+ val labelBefore = currentLabel
78
+ if (currentLabel.isEmpty) {
79
+ currentLabel = Some (label)
80
+ }
81
+ val res = p
82
+ currentLabel = labelBefore
83
+ res
84
+ }
70
85
71
86
// Interfacing with the token stream
72
87
// ---------------------------------
@@ -124,6 +139,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
124
139
def skip (): Unit =
125
140
previous = tokens(position)
126
141
position += 1 ;
142
+ currentLabel = None
127
143
spaces()
128
144
129
145
def isSpace (kind : TokenKind ): Boolean =
@@ -139,19 +155,16 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
139
155
}
140
156
141
157
def consume (kind : TokenKind ): Unit =
142
- // if !hasNext() then fail(s"Expected ${kind}, but reached end of file")
143
- val positionBefore = position
144
- val t = next()
145
-
146
- if (t.kind != kind) {
147
- // we need to fail at the position before consuming
148
- position = positionBefore
149
- fail(s " Expected ${explain(kind)} but got ${explain(t.kind)}" )
158
+ if ! hasNext() then fail(s " Expected ${kind}, but reached end of file " )
159
+ if (peek.kind != kind) {
160
+ fail(explain(kind), peek.kind) // s"Expected ${explain(kind)} but got ${explain(t.kind)}")
150
161
}
162
+ val t = next()
163
+ ()
151
164
152
165
inline def expect [T ](expected : String )(inline f : PartialFunction [TokenKind , T ]): T =
153
166
val kind = peek.kind
154
- if f.isDefinedAt(kind) then { skip(); f(kind) } else fail(s " Expected ${ expected} " )
167
+ if f.isDefinedAt(kind) then { skip(); f(kind) } else fail(expected, kind )
155
168
156
169
/* The actual parser itself
157
170
* ------------------------
@@ -180,7 +193,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
180
193
*/
181
194
def stmts (): Stmt =
182
195
nonterminal :
183
- peek.kind match {
196
+ ( peek.kind match {
184
197
case `val` => valStmt()
185
198
case _ if isDefinition => DefStmt (definition(), semi() ~> stmts())
186
199
case `with` => withStmt()
@@ -197,7 +210,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
197
210
semi()
198
211
if returnPosition then Return (e)
199
212
else ExprStmt (e, stmts())
200
- }
213
+ }) labelled " statements "
201
214
202
215
// ATTENTION: here the grammar changed (we added `with val` to disambiguate)
203
216
// with val <ID> (: <TYPE>)? = <EXPR>; <STMTS>
@@ -265,8 +278,10 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
265
278
266
279
def stmt (): Stmt =
267
280
nonterminal :
268
- if peek(`{`) then braces { BlockStmt (stmts()) }
269
- else when(`return`) { Return (expr()) } { Return (expr()) }
281
+ {
282
+ if peek(`{`) then braces { BlockStmt (stmts()) }
283
+ else when(`return`) { Return (expr()) } { Return (expr()) }
284
+ } labelled " statement"
270
285
271
286
272
287
/**
@@ -309,7 +324,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
309
324
Include (`import` ~> moduleName())
310
325
311
326
def moduleName (): String =
312
- some(ident, `/`).mkString(" /" )
327
+ some(ident, `/`).mkString(" /" ) labelled " module name "
313
328
314
329
def isToplevel : Boolean = peek.kind match {
315
330
case `val` | `fun` | `def` | `type` | `effect` | `namespace` |
@@ -450,7 +465,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
450
465
451
466
peek.kind match {
452
467
case `=` => `=` ~> TypeDef (id, tps.unspan, valueType())
453
- case _ => braces { DataDef (id, tps, manyWhile ({ constructor() <~ semi() }, ! peek( `}`) )) }
468
+ case _ => braces { DataDef (id, tps, manyUntil ({ constructor() <~ semi() }, `}`)) }
454
469
}
455
470
456
471
def recordDef (): Def =
@@ -459,7 +474,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
459
474
460
475
def constructor (): Constructor =
461
476
nonterminal :
462
- Constructor (idDef(), maybeTypeParams(), valueParams())
477
+ Constructor (idDef(), maybeTypeParams(), valueParams()) labelled " constructor "
463
478
464
479
// On the top-level both
465
480
// effect Foo = {}
@@ -492,7 +507,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
492
507
493
508
def interfaceDef (): InterfaceDef =
494
509
nonterminal :
495
- InterfaceDef (`interface` ~> idDef(), maybeTypeParams(), `{` ~> manyWhile( `def` ~> operation(), `def `) <~ `}`)
510
+ InterfaceDef (`interface` ~> idDef(), maybeTypeParams(), `{` ~> manyUntil({ `def` ~> operation() } labelled " operation declaration " , `} `) <~ `}`)
496
511
497
512
def namespaceDef (): Def =
498
513
nonterminal :
@@ -570,10 +585,10 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
570
585
def externBody (): ExternBody =
571
586
nonterminal :
572
587
peek.kind match {
573
- case _ : Ident => peek(1 ).kind match {
588
+ case _ : Ident => ( peek(1 ).kind match {
574
589
case `{` => ExternBody .EffektExternBody (featureFlag(), `{` ~> stmts() <~ `}`)
575
590
case _ => ExternBody .StringExternBody (maybeFeatureFlag(), template())
576
- }
591
+ }) labelled " extern body (string or block) "
577
592
case _ => ExternBody .StringExternBody (maybeFeatureFlag(), template())
578
593
}
579
594
@@ -629,18 +644,18 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
629
644
630
645
def returnAnnotation (): Effectful =
631
646
if peek(`:`) then `:` ~> effectful()
632
- else fail(" Expected return type annotation" )
647
+ else fail(" return type annotation" , peek.kind )
633
648
634
649
def valueTypeAnnotation (): ValueType =
635
650
if peek(`:`) then `:` ~> valueType()
636
- else fail(" Expected a type annotation" )
651
+ else fail(" a type annotation" , peek.kind )
637
652
638
653
def blockTypeAnnotation (): BlockType =
639
654
if peek(`:`) then `:` ~> blockType()
640
- else fail(" Expected a type annotation" )
655
+ else fail(" a type annotation" , peek.kind )
641
656
642
657
def expr (): Term = peek.kind match {
643
- case _ => matchExpr()
658
+ case _ => matchExpr() labelled " expression "
644
659
}
645
660
646
661
def ifExpr (): Term =
@@ -722,7 +737,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
722
737
if ! peek(`def`) then fail(" Expected at least one operation definition to implement this interface." )
723
738
tpe
724
739
} map { tpe =>
725
- Implementation (tpe, manyWhile (opClause(), `def `)) <~ `}`
740
+ Implementation (tpe, manyUntil (opClause() labelled " operation clause " , `} `)) <~ `}`
726
741
}
727
742
728
743
// Interface[...] { () => ... }
@@ -735,7 +750,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
735
750
Implementation (interface, List (operation))
736
751
}
737
752
738
- emptyImplementation() orElse interfaceImplementation() getOrElse operationImplementation()
753
+ ( emptyImplementation() orElse interfaceImplementation() getOrElse operationImplementation()) labelled " interface implementation (starting with its name) "
739
754
740
755
def opClause (): OpClause =
741
756
nonterminal :
@@ -809,7 +824,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
809
824
case Many (p :: Nil , _) => fail(" Pattern matching on tuples requires more than one element" )
810
825
case Many (ps, span) => TagPattern (IdRef (List (" effekt" ), s " Tuple ${ps.size}" , span.synthesized), ps)
811
826
}
812
- case _ => fail(" Expected pattern" )
827
+ case k => fail(" pattern" , k )
813
828
}
814
829
815
830
def matchExpr (): Term =
@@ -929,7 +944,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
929
944
// () ()
930
945
def isArguments : Boolean = lookbehind(1 ).kind != Newline && (peek(`(`) || peek(`[`) || peek(`{`))
931
946
def arguments (): (List [ValueType ], List [Term ], List [Term ]) =
932
- if (! isArguments) fail(" Expected at least one argument section (types, values, or blocks)" )
947
+ if (! isArguments) fail(" at least one argument section (types, values, or blocks)" , peek.kind )
933
948
(maybeTypeArgs().unspan, maybeValueArgs(), maybeBlockArgs())
934
949
935
950
def maybeTypeArgs (): Many [ValueType ] =
@@ -1005,7 +1020,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
1005
1020
case _ if isHole => hole()
1006
1021
case _ if isTupleOrGroup => tupleOrGroup()
1007
1022
case _ if isListLiteral => listLiteral()
1008
- case _ => fail(s " Expected variables, literals, tuples, lists, holes or group" )
1023
+ case k => fail(" variables, literals, tuples, lists, holes or group" , k )
1009
1024
}
1010
1025
1011
1026
def isListLiteral : Boolean = peek.kind match {
@@ -1037,7 +1052,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
1037
1052
case `<{` =>
1038
1053
val s = `<{` ~> stmts() <~ `}>`
1039
1054
Hole (IdDef (" hole" , span().synthesized), s, span())
1040
- case _ => fail(" Expected hole" )
1055
+ case k => fail(" hole" , k )
1041
1056
}
1042
1057
}
1043
1058
@@ -1085,7 +1100,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
1085
1100
case `true` => skip(); BooleanLit (true )
1086
1101
case `false` => skip(); BooleanLit (false )
1087
1102
case t if isUnitLiteral => skip(); skip(); UnitLit ()
1088
- case t => fail(" Expected a literal" )
1103
+ case t => fail(" a literal" , t )
1089
1104
}
1090
1105
1091
1106
// Will also recognize ( ) as unit if we do not emit space in the lexer...
@@ -1134,14 +1149,15 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
1134
1149
* SetType ::= Type
1135
1150
* | '{' Type ',' ... '}'
1136
1151
*/
1137
- def effects (): Effects =
1152
+ def effects (): Effects = {
1138
1153
nonterminal :
1139
1154
if (peek(`{`)) {
1140
1155
val effects = many(refType, `{`, `,`, `}`)
1141
1156
Effects (effects.unspan, effects.span)
1142
1157
}
1143
1158
else
1144
1159
Effects (List (refType()), span())
1160
+ } labelled " effect set"
1145
1161
1146
1162
def maybeEffects (): Effects = {
1147
1163
nonterminal :
@@ -1172,8 +1188,10 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
1172
1188
private def functionType (): Type = {
1173
1189
// Complex function type: [T]*(Int, String)*{Exc} => Int / {Effect}
1174
1190
def functionTypeComplex : Maybe [Type ] = backtrack {
1175
- maybeTypeParams() ~ maybeValueTypes() ~ (maybeBlockTypeParams() <~ `=>`) ~ atomicType() ~ maybeEffects() match {
1176
- case tparams ~ vparams ~ bparams ~ t ~ effs => FunctionType (tparams, vparams, bparams, t, effs)
1191
+ maybeTypeParams() ~ maybeValueTypes() ~ (maybeBlockTypeParams() <~ `=>`)
1192
+ } map { case tparams ~ vparams ~ bparams =>
1193
+ (atomicType() labelled " return type" ) ~ maybeEffects() match {
1194
+ case t ~ effs => FunctionType (tparams, vparams, bparams, t, effs)
1177
1195
}
1178
1196
}
1179
1197
@@ -1211,8 +1229,8 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
1211
1229
}
1212
1230
1213
1231
// NOTE: ValueType, BlockType are just aliases for Type.
1214
- def blockType (): BlockType = boxedType()
1215
- def valueType (): ValueType = boxedType()
1232
+ def blockType (): BlockType = boxedType() labelled " block type "
1233
+ def valueType (): ValueType = boxedType() labelled " value type "
1216
1234
1217
1235
// Completely specialized for TypeRef: we only parse `refType` here, we don't go through the whole hierarchy.
1218
1236
// This results in slightly worse errors, but massively simplifies the design.
@@ -1222,11 +1240,11 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
1222
1240
// then pretend the effect set is empty. This seems to work out fine :)
1223
1241
def effectful (): Effectful = {
1224
1242
nonterminal :
1225
- boxedType() match
1243
+ ( boxedType() match
1226
1244
case eff : Effectful => eff
1227
1245
case tpe => {
1228
1246
Effectful (tpe, Effects .Pure (Span (source, pos(), pos(), Synthesized )), span())
1229
- }
1247
+ }) labelled " return-type and effects "
1230
1248
}
1231
1249
1232
1250
def maybeTypeParams (): Many [Id ] =
@@ -1336,7 +1354,11 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
1336
1354
/**
1337
1355
* Aborts parsing with the given message
1338
1356
*/
1339
- def fail (message : String ): Nothing = throw Fail (message, position)
1357
+ def fail (expected : String , got : TokenKind ): Nothing =
1358
+ throw Fail .expectedButGot(currentLabel.getOrElse { expected }, explain(got), position)
1359
+
1360
+ def fail (msg : String ): Nothing =
1361
+ throw Fail (msg, position)
1340
1362
1341
1363
def softFail (message : String , start : Int , end : Int ): Unit = {
1342
1364
softFails += SoftFail (message, start, end)
@@ -1351,10 +1373,12 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
1351
1373
inline def backtrack [T ](inline p : => T ): Maybe [T ] =
1352
1374
val before = position
1353
1375
val beforePrevious = previous
1376
+ val labelBefore = currentLabel
1354
1377
try { Maybe .Some (p, span(tokens(before).end)) } catch {
1355
1378
case Fail (_, _) => {
1356
1379
position = before
1357
1380
previous = beforePrevious
1381
+ currentLabel = labelBefore
1358
1382
Maybe .None (Span (source, previous.end + 1 , previous.end + 1 , Synthesized ))
1359
1383
}
1360
1384
}
@@ -1430,13 +1454,19 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
1430
1454
inline def manyWhile [T ](p : => T , lookahead : TokenKind ): List [T ] =
1431
1455
manyWhile(p, peek(lookahead))
1432
1456
1457
+ inline def manyUntil [T ](p : => T , lookahead : TokenKind ): List [T ] =
1458
+ manyUntil(p, peek(lookahead))
1459
+
1433
1460
inline def manyWhile [T ](p : => T , predicate : => Boolean ): List [T ] =
1434
1461
val components : ListBuffer [T ] = ListBuffer .empty
1435
1462
while (predicate) {
1436
1463
components += p
1437
1464
}
1438
1465
components.toList
1439
1466
1467
+ inline def manyUntil [T ](p : => T , predicate : => Boolean ): List [T ] =
1468
+ manyWhile(p, ! predicate)
1469
+
1440
1470
inline def parens [T ](p : => T ): T =
1441
1471
consume(`(`)
1442
1472
val res = p
0 commit comments