Skip to content

Commit b1570df

Browse files
Fix off-by-one-token bugs (#1015)
Fixes #958. --------- Co-authored-by: Jiří Beneš <[email protected]>
1 parent e41c91f commit b1570df

File tree

11 files changed

+32
-14
lines changed

11 files changed

+32
-14
lines changed

effekt/shared/src/main/scala/effekt/RecursiveDescent.scala

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,9 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
149149
fail(s"Expected ${explain(kind)} but got ${explain(t.kind)}")
150150
}
151151

152+
inline def expect[T](expected: String)(inline f: PartialFunction[TokenKind, T]): T =
153+
val kind = peek.kind
154+
if f.isDefinedAt(kind) then { skip(); f(kind) } else fail(s"Expected ${expected}")
152155

153156
/* The actual parser itself
154157
* ------------------------
@@ -517,12 +520,12 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
517520
case _ => externFun()
518521
}
519522

520-
def featureFlag(): FeatureFlag =
521-
next().kind match {
523+
def featureFlag(): FeatureFlag = {
524+
expect("feature flag identifier") {
522525
case Ident("default") => FeatureFlag.Default
523526
case Ident(flag) => FeatureFlag.NamedFeatureFlag(flag)
524-
case _ => fail("Expected identifier")
525527
}
528+
}
526529

527530
def maybeFeatureFlag(): FeatureFlag =
528531
nonterminal:
@@ -549,9 +552,8 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
549552
consume(`extern`)
550553
val posAfterExtern = pos()
551554
val ff = maybeFeatureFlag()
552-
next().kind match {
555+
expect("string literal") {
553556
case Str(contents, _) => ExternInclude(ff, "", Some(contents), IdDef("", Span(source, posAfterExtern, posAfterExtern, Synthesized)))
554-
case _ => fail("Expected string literal.")
555557
}
556558

557559
def externFun(): Def =
@@ -600,19 +602,16 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
600602

601603
def path(): String =
602604
nonterminal:
603-
next().kind match {
605+
expect("path as string literal") {
604606
case Str(s, false) => s
605-
case _ => fail("Expected path as string literal.")
606607
}
607608

608609
def string(): String =
609610
nonterminal:
610-
next().kind match {
611+
expect("string literal") {
611612
case Str(s, _) => s
612-
case _ => fail("Expected string literal.")
613613
}
614614

615-
616615
def maybeValueTypeAnnotation(): Option[ValueType] =
617616
nonterminal:
618617
if peek(`:`) then Some(valueTypeAnnotation()) else None
@@ -1071,6 +1070,8 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
10711070
Call(IdTarget(target), Nil, Nil, List(blk))
10721071
}
10731072

1073+
// TODO: This should use `expect` as it follows the same pattern.
1074+
// However, we currently cannot use `expect` here as the unit literal consists of two tokens
10741075
def literal(): Literal =
10751076
nonterminal:
10761077
peek.kind match {
@@ -1110,10 +1111,7 @@ class RecursiveDescent(positions: Positions, tokens: Seq[Token], source: Source)
11101111
}
11111112
def ident(): String =
11121113
nonterminal:
1113-
next().kind match {
1114-
case Ident(id) => id
1115-
case _ => fail(s"Expected identifier")
1116-
}
1114+
expect("identifier") { case Ident(id) => id }
11171115

11181116
/*
11191117
* Type grammar by precedence:
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[error] examples/neg/parsing/extern-def-string.effekt:1:35: Expected string literal
2+
extern def foo(): Bool = whatever here
3+
^^^^
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extern def foo(): Bool = whatever here
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[error] examples/neg/parsing/extern-path.effekt:1:16: Expected path as string literal
2+
extern include 42
3+
^^
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extern include 42
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[error] examples/neg/parsing/extern-string.effekt:1:11: Expected string literal
2+
extern js 42
3+
^^
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extern js 42
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[error] examples/neg/parsing/feature-flag.effekt:1:29: Unexpected end of input
2+
extern def whatever: Unit = 42 "whatever"
3+
^^
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
extern def whatever: Unit = 42 "whatever"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[error] examples/neg/parsing/identifiers.effekt:1:5: Expected identifier
2+
val 42 = 42
3+
^^

0 commit comments

Comments
 (0)