Skip to content

Commit 813e006

Browse files
authored
Merge pull request #129 from airportyh/improve-error-output
Improved error reporting
2 parents 1aac4c2 + 4d94b61 commit 813e006

File tree

2 files changed

+72
-16
lines changed

2 files changed

+72
-16
lines changed

moo.js

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,38 @@
5353
}
5454
}
5555

56+
function pad(s, length) {
57+
if (s.length > length) {
58+
return s
59+
}
60+
return Array(length - s.length + 1).join(" ") + s
61+
}
62+
63+
function lastNLines(string, numLines) {
64+
var position = string.length
65+
var lineBreaks = 0;
66+
while (true) {
67+
var idx = string.lastIndexOf("\n", position - 1)
68+
if (idx === -1) {
69+
break;
70+
} else {
71+
lineBreaks++
72+
}
73+
position = idx
74+
if (lineBreaks === numLines) {
75+
break;
76+
}
77+
if (position === 0) {
78+
break;
79+
}
80+
}
81+
var startPosition =
82+
lineBreaks < numLines ?
83+
0 :
84+
position + 1
85+
return string.substring(startPosition).split("\n")
86+
}
87+
5688
function objectToRules(object) {
5789
var keys = Object.getOwnPropertyNames(object)
5890
var result = []
@@ -524,7 +556,8 @@
524556

525557
// throw, if no rule with {error: true}
526558
if (group.shouldThrow) {
527-
throw new Error(this.formatError(token, "invalid syntax"))
559+
var err = new Error(this.formatError(token, "invalid syntax"))
560+
throw err;
528561
}
529562

530563
if (group.pop) this.popState()
@@ -565,13 +598,28 @@
565598
col: this.col,
566599
}
567600
}
568-
var start = Math.max(0, token.offset - token.col + 1)
569-
var eol = token.lineBreaks ? token.text.indexOf('\n') : token.text.length
570-
var firstLine = this.buffer.substring(start, token.offset + eol)
571-
message += " at line " + token.line + " col " + token.col + ":\n\n"
572-
message += " " + firstLine + "\n"
573-
message += " " + Array(token.col).join(" ") + "^"
574-
return message
601+
602+
var numLinesAround = 2
603+
var firstDisplayedLine = Math.max(token.line - numLinesAround, 1)
604+
var lastDisplayedLine = token.line + numLinesAround
605+
var lastLineDigits = String(lastDisplayedLine).length
606+
var displayedLines = lastNLines(
607+
this.buffer,
608+
(this.line - token.line) + numLinesAround + 1
609+
)
610+
.slice(0, 5)
611+
var errorLines = []
612+
errorLines.push(message + " at line " + token.line + " col " + token.col + ":")
613+
errorLines.push("")
614+
for (var i = 0; i < displayedLines.length; i++) {
615+
var line = displayedLines[i]
616+
var lineNo = firstDisplayedLine + i
617+
errorLines.push(pad(String(lineNo), lastLineDigits) + " " + line);
618+
if (lineNo === token.line) {
619+
errorLines.push(pad("", lastLineDigits + token.col + 1) + "^")
620+
}
621+
}
622+
return errorLines.join("\n")
575623
}
576624

577625
Lexer.prototype.clone = function() {

test/test.js

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -905,8 +905,9 @@ describe('errors', () => {
905905
expect(lexer.next()).toMatchObject({value: '456'})
906906
expect(() => lexer.next()).toThrow(
907907
"invalid syntax at line 2 col 4:\n\n" +
908-
" 456baa\n" +
909-
" ^"
908+
"1 123\n" +
909+
"2 456baa\n" +
910+
" ^"
910911
)
911912
})
912913

@@ -921,8 +922,12 @@ describe('errors', () => {
921922
expect(tok).toMatchObject({type: 'error', value: ' 12\n345\n6', lineBreaks: 2})
922923
expect(lexer.formatError(tok, "numbers!")).toBe(
923924
"numbers! at line 3 col 2:\n\n" +
924-
" g 12\n" +
925-
" ^"
925+
"1 abc\n" +
926+
"2 def\n" +
927+
"3 g 12\n" +
928+
" ^\n" +
929+
"4 345\n" +
930+
"5 6"
926931
)
927932
})
928933

@@ -937,8 +942,9 @@ describe('errors', () => {
937942
expect(lexer.col).toBe(9)
938943
expect(lexer.formatError(undefined, "EOF!")).toBe(
939944
"EOF! at line 2 col 9:\n\n" +
940-
" def quxx\n" +
941-
" ^"
945+
"1 abc\n" +
946+
"2 def quxx\n" +
947+
" ^"
942948
)
943949
})
944950

@@ -954,8 +960,10 @@ describe('errors', () => {
954960
expect(lexer.col).toBe(1)
955961
expect(lexer.formatError(undefined, "oh no!")).toBe(
956962
"oh no! at line 2 col 1:\n\n" +
957-
" def quxx\n" +
958-
" ^"
963+
"1 abc\n" +
964+
"2 def quxx\n" +
965+
" ^\n" +
966+
"3 bar"
959967
)
960968
})
961969

0 commit comments

Comments
 (0)