Skip to content

Commit f326fe0

Browse files
committed
Improve parsing of newlines where possibly indented blocks are expected
1 parent 5a639fa commit f326fe0

File tree

18 files changed

+177
-73
lines changed

18 files changed

+177
-73
lines changed

hkmc2/shared/src/main/scala/hkmc2/semantics/Elaborator.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,7 @@ extends Importer:
623623
case Block(sts) :: trees =>
624624
go(acc, sts ::: trees)
625625
case tree :: trees =>
626-
raise(ErrorReport(msg"Illegal juxtaposition right-hand side." -> tree.toLoc :: Nil))
626+
raise(ErrorReport(msg"Illegal juxtaposition right-hand side (${tree.describe})." -> tree.toLoc :: Nil))
627627
go(acc, trees)
628628

629629
go(term(lhs), rhs :: Nil)

hkmc2/shared/src/main/scala/hkmc2/syntax/Parser.scala

Lines changed: 34 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,17 @@ abstract class Parser(
240240

241241
final def maybeIndented[R](f: (Parser, Bool) => R): R =
242242
yeetSpaces match
243+
case (NEWLINE, l0) :: _ =>
244+
consume
245+
while yeetSpaces.headOption.exists(_._1 === NEWLINE) do consume
246+
cur match
247+
case Nil =>
248+
case (tok, loc) :: _ =>
249+
raise(WarningReport(
250+
msg"This ${tok.describe} should be indented" -> S(loc) ::
251+
msg"since it is a continuation of the new line here" -> S(l0) ::
252+
Nil))
253+
maybeIndented(f)
243254
case (br @ BRACKETS(Indent | Curly, toks), _) :: _ =>
244255
consume
245256
rec(toks, S(br.innerLoc), br.describe).concludeWith(f(_, true))
@@ -278,7 +289,7 @@ abstract class Parser(
278289
consume
279290
val blk = rec(toks, S(tok.innerLoc), tok.describe).concludeWith(_.blockOf(subRule, Nil, allowNewlines)) // FIXME allowNewlines?
280291
if blk.isEmpty then
281-
err((msg"Expected ${subRule.whatComesAfter} ${subRule.mkAfterStr}; found end of block instead" -> S(loc) :: Nil))
292+
err(msg"Expected ${subRule.whatComesAfter} ${subRule.mkAfterStr}; found end of block instead" -> S(loc) :: Nil)
282293
errExpr
283294
blk.map(annotations.annotate) ::: blockContOf(rule)
284295
case _ =>
@@ -307,10 +318,10 @@ abstract class Parser(
307318
annotations.annotate(parseRule(CommaPrecNext, exprAlt.rest).map(res => exprAlt.k(e, res)).getOrElse(errExpr)) :: blockContOf(rule)
308319
case N =>
309320
// TODO dedup?
310-
err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> S(loc) :: Nil))
321+
err(msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> S(loc) :: Nil)
311322
annotations.annotate(errExpr) :: blockContOf(rule)
312323
case N =>
313-
err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> S(loc) :: Nil))
324+
err(msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> S(loc) :: Nil)
314325
annotations.annotate(errExpr) :: blockContOf(rule)
315326
case N =>
316327
val lhs = tryParseExp(CommaPrecNext, tok, loc, rule).getOrElse(errExpr)
@@ -336,7 +347,7 @@ abstract class Parser(
336347
case S(res) =>
337348
S(res)
338349
case N =>
339-
err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> S(loc) :: Nil))
350+
err(msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> S(loc) :: Nil)
340351
N
341352

342353

@@ -348,7 +359,7 @@ abstract class Parser(
348359
case S(res) => S(res)
349360
case N =>
350361
consume
351-
err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> S(loc) :: Nil))
362+
err(msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> S(loc) :: Nil)
352363
N
353364
yeetSpaces match
354365
// case (tok @ (id: IDENT), loc) :: _ if Keyword.all.get(id.name).exists(_.leftPrecOrMin < prec) =>
@@ -358,7 +369,7 @@ abstract class Parser(
358369
// case S(res) =>
359370
// S(res)
360371
// case N =>
361-
// err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found end of phrase instead" -> S(loc.left) :: Nil))
372+
// err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found end of phrase instead" -> S(loc.left) :: Nil)
362373
// N
363374
case (tok @ (id: IDENT), loc) :: _ =>
364375
Keyword.all.get(id.name) match
@@ -397,14 +408,14 @@ abstract class Parser(
397408
rule.emptyAlt match
398409
case S(res) => S(res)
399410
case N =>
400-
// err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> lastLoc :: Nil))
401-
err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> S(l0) :: Nil))
411+
//err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> lastLoc :: Nil)
412+
err(msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> S(l0) :: Nil)
402413
N
403414
case (br @ BRACKETS(Indent | Curly, toks), loc) :: _ =>
404415
// rule.blkAlt match
405416
// case S(res) => S(res)
406417
// case N =>
407-
// err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> lastLoc :: Nil))
418+
// err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${tok.describe} instead" -> lastLoc :: Nil)
408419
// N
409420

410421
if verbose then printDbg("$ found an indented" + (toks match
@@ -445,7 +456,7 @@ abstract class Parser(
445456
case S(res) =>
446457
S(res)
447458
case N =>
448-
err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found end of input instead" -> lastLoc :: Nil))
459+
err(msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found end of input instead" -> lastLoc :: Nil)
449460
N
450461

451462

@@ -462,7 +473,7 @@ abstract class Parser(
462473
yeetSpaces match
463474
case (IDENT("=", _), l1) :: _ => consume
464475
case (tk, l1) :: _ =>
465-
err((msg"Expected `=` after ${nme}; found ${tk.toString} instead" -> S(l1) :: Nil))
476+
err(msg"Expected `=` after ${nme}; found ${tk.toString} instead" -> S(l1) :: Nil)
466477
val rhs = simpleExprImpl(0)
467478
val v = Tree.Ident(nme).withLoc(S(l0))
468479
cur match {
@@ -495,7 +506,7 @@ abstract class Parser(
495506
Keyword.all.get(nme) match
496507
case S(kw) => // * Expressions starting with keywords should be handled in parseRule
497508
// * I guess this case is not really supposed to be ever reached (?)
498-
err((msg"Unexpected ${kw.toString} in this position" -> S(loc) :: Nil))
509+
err(msg"Unexpected ${kw.toString} in this position" -> S(loc) :: Nil)
499510
errExpr
500511
case N =>
501512
consume
@@ -554,7 +565,7 @@ abstract class Parser(
554565
consume
555566
simpleExpr(0)
556567
case (tk, loc) :: _ =>
557-
err((msg"Expected an expression; found ${tk.toString} instead" -> S(loc) :: Nil))
568+
err(msg"Expected an expression; found ${tk.toString} instead" -> S(loc) :: Nil)
558569
errExpr
559570
case Nil =>
560571
err(msg"Expected '`in'; found end of input instead" -> lastLoc :: Nil)
@@ -578,7 +589,7 @@ abstract class Parser(
578589
err(msg"Expected '`in'; found ${tk.toString} instead" -> tk.toLoc :: Nil)
579590
errExpr
580591
case (tk, loc) :: _ =>
581-
err((msg"Expected 'else'; found ${tk.toString} instead" -> S(loc) :: Nil))
592+
err(msg"Expected 'else'; found ${tk.toString} instead" -> S(loc) :: Nil)
582593
errExpr
583594
case Nil =>
584595
err(msg"Expected 'else'; found end of input instead" -> lastLoc :: Nil)
@@ -594,19 +605,23 @@ abstract class Parser(
594605
case _ => unsupportedQuote(S(loc))
595606
}
596607
case (BRACKETS(Indent | Curly, _), loc) :: _ =>
597-
err((msg"Expected an expression; found block instead" -> lastLoc :: Nil))
608+
err(msg"Expected an expression; found block instead" -> lastLoc :: Nil)
598609
errExpr
599610
case (SUSPENSION(dotDotDot), loc) :: _ =>
600611
consume
601612
val bod = yeetSpaces match
602613
case Nil | (COMMA, _) :: _ => N
603614
case _ => S(expr(prec))
604615
Spread(if dotDotDot then Keyword.`...` else Keyword.`..`, S(loc), bod)
616+
// case (NEWLINE, loc) :: _ => // this seems to never be reached
617+
// raise(WarningReport(msg"???" -> S(loc) :: Nil))
618+
// consume
619+
// simpleExprImpl(prec)
605620
case (tok, loc) :: _ =>
606-
err((msg"Expected an expression; found new line instead" -> S(loc) :: Nil))
621+
err(msg"Expected an expression; found ${tok.describe} instead" -> S(loc) :: Nil)
607622
errExpr
608623
case Nil =>
609-
err((msg"Expected an expression; found end of input instead" -> lastLoc :: Nil))
624+
err(msg"Expected an expression; found end of input instead" -> lastLoc :: Nil)
610625
errExpr
611626

612627

@@ -727,7 +742,7 @@ abstract class Parser(
727742
}
728743
case (COMMA, l0) :: _ if prec === 0 =>
729744
consume
730-
err((msg"Unexpected comma in this position" -> S(l0) :: Nil))
745+
err(msg"Unexpected comma in this position" -> S(l0) :: Nil)
731746
acc
732747
/*
733748
case (KEYWORD(opStr @ "=>"), l0) :: (NEWLINE, l1) :: _ if opPrec(opStr)._1 > prec =>
@@ -986,7 +1001,7 @@ abstract class Parser(
9861001
.getOrElse(errExpr)
9871002
case N =>
9881003
// TODO other alts...?
989-
err((msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${kw.name} instead" -> S(l0) :: Nil))
1004+
err(msg"Expected ${rule.whatComesAfter} ${rule.mkAfterStr}; found ${kw.name} instead" -> S(l0) :: Nil)
9901005
acc
9911006
case _ => acc
9921007
case _ =>

hkmc2/shared/src/main/scala/hkmc2/syntax/Token.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ sealed abstract class Token:
1010
case SPACE => "space"
1111
case COMMA => "comma"
1212
case SEMI => "semicolon"
13-
case NEWLINE => "newline"
13+
case NEWLINE => "new line"
1414
case INDENT => "indentation"
1515
case DEINDENT => "deindentation"
1616
case ERROR => "error"

hkmc2/shared/src/main/scala/hkmc2/syntax/Tree.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,9 @@ enum Tree extends AutoLocated:
133133
case IntLit(value) => "integer literal"
134134
case DecLit(value) => "decimal literal"
135135
case StrLit(value) => "string literal"
136-
case UnitLit(value) => if value then "null" else "undefined"
137136
case BoolLit(value) => s"$value literal"
137+
case UnitLit(value) => if value then "null" else "undefined"
138+
case Unt() => "unit"
138139
case Bra(k, _) => k.name + " section"
139140
case Block(stmts) => "block"
140141
case OpBlock(_) => "operator block"

hkmc2/shared/src/test/mlscript/backlog/ToTriage.mls

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"a" +
2020
// a
2121
"b"
22-
//│ ╔══[PARSE ERROR] Expected start of statement in this position; found newline instead
22+
//│ ╔══[PARSE ERROR] Expected start of statement in this position; found new line instead
2323
//│ ║ l.20: // a
2424
//│ ║ ^
2525
//│ ║ l.21: "b"
@@ -276,7 +276,7 @@ class Foo' with
276276
module Example with
277277
// whoops
278278
val a = this
279-
//│ ╔══[PARSE ERROR] Expected block after type declaration body; found newline instead
279+
//│ ╔══[PARSE ERROR] Expected block after type declaration body; found new line instead
280280
//│ ║ l.276: module Example with
281281
//│ ║ ^
282282
//│ ║ l.277: // whoops

hkmc2/shared/src/test/mlscript/basics/BlockArgs.mls

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ foo(1){x => x}
1111
//│ ╔══[ERROR] Name not found: foo
1212
//│ ║ l.10: foo(1){x => x}
1313
//│ ╙── ^^^
14-
//│ ╔══[ERROR] Illegal juxtaposition right-hand side.
14+
//│ ╔══[ERROR] Illegal juxtaposition right-hand side (infix operation).
1515
//│ ║ l.10: foo(1){x => x}
1616
//│ ╙── ^^^^^^
1717

@@ -20,15 +20,15 @@ foo(1)
2020
//│ ╔══[ERROR] Name not found: foo
2121
//│ ║ l.18: foo(1)
2222
//│ ╙── ^^^
23-
//│ ╔══[ERROR] Illegal juxtaposition right-hand side.
23+
//│ ╔══[ERROR] Illegal juxtaposition right-hand side (infix operation).
2424
//│ ║ l.19: x => x
2525
//│ ╙── ^^^^^^
2626

2727
foo(1) { x => x }
2828
//│ ╔══[ERROR] Name not found: foo
2929
//│ ║ l.27: foo(1) { x => x }
3030
//│ ╙── ^^^
31-
//│ ╔══[ERROR] Illegal juxtaposition right-hand side.
31+
//│ ╔══[ERROR] Illegal juxtaposition right-hand side (infix operation).
3232
//│ ║ l.27: foo(1) { x => x }
3333
//│ ╙── ^^^^^^
3434

hkmc2/shared/src/test/mlscript/basics/Indentation.mls

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,54 @@ tuple(
3232
tuple()
3333
//│ = []
3434

35-
:fixme
3635
tuple(
36+
id(2
37+
+2))
38+
tuple()
39+
tuple()
40+
//│ = [[[4]]]
41+
42+
// 🤔
43+
:e
44+
tuple(
45+
id(2
46+
+2))
47+
tuple()
48+
tuple()
49+
tuple()
50+
//│ ╔══[ERROR] Illegal juxtaposition right-hand side (juxtaposition).
51+
//│ ║ l.47: tuple()
52+
//│ ║ ^^^^^^^
53+
//│ ║ l.48: tuple()
54+
//│ ║ ^^^^^^^^^^^
55+
//│ ║ l.49: tuple()
56+
//│ ╙── ^^
57+
//│ = [[4]]
58+
59+
module A with {
60+
}
61+
62+
:p
63+
tuple(
64+
)
65+
//│ |tuple|(|↵|)|
66+
//│ Parsed:
67+
//│ App(Ident(tuple),Tup(List()))
68+
//│ = []
69+
70+
:w
71+
tuple(
72+
1
3773
)
38-
//│ ╔══[PARSE ERROR] Expected an expression; found new line instead
39-
//│ ║ l.36: tuple(
74+
//│ ╔══[WARNING] This literal should be indented
75+
//│ ║ l.72: 1
76+
//│ ║ ^
77+
//│ ╟── since it is a continuation of the new line here
78+
//│ ║ l.71: tuple(
4079
//│ ║ ^
41-
//│ ║ l.37: )
80+
//│ ║ l.72: 1
4281
//│ ╙──
82+
//│ = [1]
4383

4484
tuple(
4585
)
@@ -98,9 +138,9 @@ id
98138
//│ |id|→|1|←|
99139
//│ Parsed:
100140
//│ Jux(Ident(id),Block(List(IntLit(1))))
101-
//│ ╔══[ERROR] Illegal juxtaposition right-hand side.
102-
//│ ║ l.97: 1
103-
//│ ╙── ^
141+
//│ ╔══[ERROR] Illegal juxtaposition right-hand side (integer literal).
142+
//│ ║ l.137: 1
143+
//│ ╙── ^
104144
//│ = [function id]
105145

106146
:e
@@ -111,10 +151,10 @@ id(0
111151
//│ |id|(|0|→|id|←|)|(|1|)|
112152
//│ Parsed:
113153
//│ App(App(Ident(id),Tup(List(Jux(IntLit(0),Block(List(Ident(id))))))),Tup(List(IntLit(1))))
114-
//│ ╔══[ERROR] Illegal juxtaposition right-hand side.
115-
//│ ║ l.110: id)(1)
154+
//│ ╔══[ERROR] Illegal juxtaposition right-hand side (identifier).
155+
//│ ║ l.150: id)(1)
116156
//│ ╙── ^^
117-
//│ ═══[RUNTIME ERROR] TypeError: tmp18 is not a function
157+
//│ ═══[RUNTIME ERROR] TypeError: tmp25 is not a function
118158

119159

120160
fun test2() =
@@ -158,16 +198,10 @@ module P with
158198
)
159199
module TraceLogger
160200

161-
:pe
162201
module P with
163202
(
164203
)
165204
module TraceLogger
166-
//│ ╔══[PARSE ERROR] Expected an expression; found new line instead
167-
//│ ║ l.163: (
168-
//│ ║ ^
169-
//│ ║ l.164: )
170-
//│ ╙── ^^
171205

172206

173207
module P with ...

hkmc2/shared/src/test/mlscript/basics/Modules.mls

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ module Foo with val x = 1
1717
//│ ╔══[PARSE ERROR] Expected end of input; found '=' keyword instead
1818
//│ ║ l.13: module Foo with val x = 1
1919
//│ ╙── ^
20-
//│ ╔══[ERROR] Illegal juxtaposition right-hand side.
20+
//│ ╔══[ERROR] Illegal juxtaposition right-hand side (identifier).
2121
//│ ║ l.13: module Foo with val x = 1
2222
//│ ╙── ^
2323

hkmc2/shared/src/test/mlscript/basics/New.mls

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,31 @@ new
2828
Foo()
2929
//│ ═══[RUNTIME ERROR] TypeError: Class constructor Foo cannot be invoked without 'new'
3030

31-
:todo
31+
:e
3232
new
3333
Foo
3434
()
35-
//│ ╔══[ERROR] Illegal juxtaposition right-hand side.
35+
//│ ╔══[ERROR] Illegal juxtaposition right-hand side (unit).
3636
//│ ║ l.34: ()
3737
//│ ╙── ^^
3838
//│ = Foo
3939

40+
:w
41+
:re
42+
new
43+
Foo
44+
()
45+
//│ ╔══[WARNING] Pure expression in statement position
46+
//│ ║ l.43: Foo
47+
//│ ╙── ^^^
48+
//│ ═══[RUNTIME ERROR] TypeError: runtime.Unit is not a constructor
49+
50+
:e
51+
new Foo
52+
()
53+
//│ ╔══[ERROR] Illegal juxtaposition right-hand side (unit).
54+
//│ ║ l.52: ()
55+
//│ ╙── ^^
56+
//│ = Foo
57+
4058

0 commit comments

Comments
 (0)