Skip to content

Commit c2db2d8

Browse files
Merge pull request #72 from Strumenta/bugfix/localized-issues
Differentiating between several parser and lexer issues
2 parents db2c28a + cae9105 commit c2db2d8

File tree

2 files changed

+245
-15
lines changed

2 files changed

+245
-15
lines changed

src/parsing/tylasu-parser.ts

+55-14
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ export class ANTLRTokenFactory extends TokenFactory<TylasuANTLRToken> {
6868
}
6969

7070
export const SYNTAX_ERROR = "parser.syntaxError";
71+
export const MISMATCHED_INPUT = "parser.mismatchedinput";
72+
export const TOKEN_RECOGNITION_ERROR = "lexer.tokenrecognitionerror"
7173
export const INPUT_NOT_FULLY_CONSUMED = "parser.inputNotFullyConsumed";
7274
export const ERROR_NODE_FOUND = "parser.errorNodeFound";
7375

@@ -118,13 +120,31 @@ export abstract class TylasuANTLRLexer<T extends TylasuToken> implements TylasuL
118120
reportAttemptingFullContext() {},
119121
reportContextSensitivity() {},
120122
syntaxError<S extends Token, T extends ATNSimulator>(recognizer: Recognizer<T>, offendingSymbol: S | null, line: number, charPositionInLine: number, msg: string) {
121-
issues.push(
122-
Issue.lexical(
123-
msg || "unspecified",
124-
IssueSeverity.ERROR,
125-
Position.ofPoint(new Point(line, charPositionInLine)),
126-
undefined,
127-
SYNTAX_ERROR));
123+
const regex = /token recognition error at: '(.+)'/
124+
if (regex.test(msg)){
125+
const match = msg.match(regex) as string[];
126+
issues.push(
127+
Issue.lexical(
128+
msg || "unspecified",
129+
IssueSeverity.ERROR,
130+
Position.ofPoint(new Point(line, charPositionInLine)),
131+
undefined,
132+
TOKEN_RECOGNITION_ERROR,
133+
[
134+
{
135+
name: "token",
136+
value: match[1]
137+
}
138+
]));
139+
} else {
140+
issues.push(
141+
Issue.lexical(
142+
msg || "unspecified",
143+
IssueSeverity.ERROR,
144+
Position.ofPoint(new Point(line, charPositionInLine)),
145+
undefined,
146+
SYNTAX_ERROR));
147+
}
128148
}
129149
});
130150
}
@@ -281,13 +301,34 @@ export abstract class TylasuParser<
281301
reportAttemptingFullContext() {},
282302
reportContextSensitivity() {},
283303
syntaxError<S extends Token, T extends ATNSimulator>(recognizer: Recognizer<T>, offendingSymbol: S | null, line: number, charPositionInLine: number, msg: string) {
284-
issues.push(
285-
Issue.syntactic(
286-
msg || "unspecified",
287-
IssueSeverity.ERROR,
288-
Position.ofPoint(new Point(line, charPositionInLine)),
289-
undefined,
290-
SYNTAX_ERROR));
304+
const mismatchedRegex = /^mismatched input '(<EOF>|.+)' expecting {([a-zA-Z_]+(, [a-zA-Z_]+)*)}$/
305+
if (mismatchedRegex.test(msg)) {
306+
const match = msg.match(mismatchedRegex) as string[];
307+
const args = [{
308+
name: "mismatched",
309+
value: match[1]
310+
}];
311+
match[2].split(", ").forEach((expected)=>args.push({
312+
name: "expected",
313+
value: expected
314+
}))
315+
issues.push(
316+
Issue.syntactic(
317+
msg,
318+
IssueSeverity.ERROR,
319+
Position.ofPoint(new Point(line, charPositionInLine)),
320+
undefined,
321+
MISMATCHED_INPUT,
322+
args));
323+
} else {
324+
issues.push(
325+
Issue.syntactic(
326+
msg || "unspecified",
327+
IssueSeverity.ERROR,
328+
Position.ofPoint(new Point(line, charPositionInLine)),
329+
undefined,
330+
SYNTAX_ERROR));
331+
}
291332
}
292333
});
293334
}

tests/parsing.test.ts

+190-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import {expect} from "chai";
22

3-
import {Issue, Node} from "../src";
3+
import {Issue, IssueSeverity, IssueType, Node, Point, Position} from "../src";
44
import {SimpleLangLexer} from "./parser/SimpleLangLexer";
55
import {CharStream, Lexer, TokenStream} from "antlr4ng";
66
import {CompilationUnitContext, SimpleLangParser} from "./parser/SimpleLangParser";
@@ -36,4 +36,193 @@ describe('Parsing', function() {
3636
expect(result.root!.parseTree).to.equal(result.firstStage!.root);
3737
expect(result.code).to.equal(code);
3838
});
39+
it("produce correct issues for: display 1 +",
40+
function () {
41+
const code = "display 1 +";
42+
const parser = new SLParser(new ANTLRTokenFactory());
43+
const result = parser.parse(code);
44+
expect(result.issues).to.eql([new Issue(
45+
IssueType.SYNTACTIC,
46+
"mismatched input '<EOF>' expecting {INT_LIT, DEC_LIT, STRING_LIT, BOOLEAN_LIT}",
47+
IssueSeverity.ERROR,
48+
new Position(new Point(1, 11), new Point(1, 11)),
49+
undefined,
50+
"parser.mismatchedinput",
51+
[
52+
{
53+
name: "mismatched",
54+
value: "<EOF>"
55+
},
56+
{
57+
name: "expected",
58+
value: "INT_LIT"
59+
},
60+
{
61+
name: "expected",
62+
value: "DEC_LIT"
63+
},
64+
{
65+
name: "expected",
66+
value: "STRING_LIT"
67+
},
68+
{
69+
name: "expected",
70+
value: "BOOLEAN_LIT"
71+
}
72+
]
73+
)])
74+
});
75+
it("produce correct issues for: display 1 ++",
76+
function () {
77+
const code = "display 1 ++";
78+
const parser = new SLParser(new ANTLRTokenFactory());
79+
const result = parser.parse(code);
80+
expect(result.issues).to.eql([
81+
new Issue(
82+
IssueType.SYNTACTIC,
83+
"mismatched input '+' expecting {INT_LIT, DEC_LIT, STRING_LIT, BOOLEAN_LIT}",
84+
IssueSeverity.ERROR,
85+
new Position(new Point(1, 11), new Point(1, 11)),
86+
undefined,
87+
"parser.mismatchedinput",
88+
[
89+
{
90+
name: "mismatched",
91+
value: "+"
92+
},
93+
{
94+
name: "expected",
95+
value: "INT_LIT"
96+
},
97+
{
98+
name: "expected",
99+
value: "DEC_LIT"
100+
},
101+
{
102+
name: "expected",
103+
value: "STRING_LIT"
104+
},
105+
{
106+
name: "expected",
107+
value: "BOOLEAN_LIT"
108+
}
109+
]
110+
),
111+
new Issue(
112+
IssueType.SYNTACTIC,
113+
"mismatched input '<EOF>' expecting {INT_LIT, DEC_LIT, STRING_LIT, BOOLEAN_LIT}",
114+
IssueSeverity.ERROR,
115+
new Position(new Point(1, 12), new Point(1, 12)),
116+
undefined,
117+
"parser.mismatchedinput",
118+
[
119+
{
120+
name: "mismatched",
121+
value: "<EOF>"
122+
},
123+
{
124+
name: "expected",
125+
value: "INT_LIT"
126+
},
127+
{
128+
name: "expected",
129+
value: "DEC_LIT"
130+
},
131+
{
132+
name: "expected",
133+
value: "STRING_LIT"
134+
},
135+
{
136+
name: "expected",
137+
value: "BOOLEAN_LIT"
138+
}
139+
]
140+
)])
141+
});
142+
it("produce correct issues for: display",
143+
function () {
144+
const code = "display";
145+
const parser = new SLParser(new ANTLRTokenFactory());
146+
const result = parser.parse(code);
147+
expect(result.issues).to.eql([
148+
new Issue(
149+
IssueType.SYNTACTIC,
150+
"mismatched input '<EOF>' expecting {INT_LIT, DEC_LIT, STRING_LIT, BOOLEAN_LIT}",
151+
IssueSeverity.ERROR,
152+
new Position(new Point(1, 7), new Point(1, 7)),
153+
undefined,
154+
"parser.mismatchedinput",
155+
[
156+
{
157+
name: "mismatched",
158+
value: "<EOF>"
159+
},
160+
{
161+
name: "expected",
162+
value: "INT_LIT"
163+
},
164+
{
165+
name: "expected",
166+
value: "DEC_LIT"
167+
},
168+
{
169+
name: "expected",
170+
value: "STRING_LIT"
171+
},
172+
{
173+
name: "expected",
174+
value: "BOOLEAN_LIT"
175+
}
176+
]
177+
)])
178+
});
179+
it("produce correct issues for: ###",
180+
function () {
181+
const code = "###";
182+
const parser = new SLParser(new ANTLRTokenFactory());
183+
const result = parser.parse(code);
184+
expect(result.issues).to.eql([
185+
new Issue(
186+
IssueType.LEXICAL,
187+
"token recognition error at: '#'",
188+
IssueSeverity.ERROR,
189+
new Position(new Point(1, 0), new Point(1, 0)),
190+
undefined,
191+
"lexer.tokenrecognitionerror",
192+
[
193+
{
194+
name: "token",
195+
value: "#"
196+
}
197+
]
198+
),
199+
new Issue(
200+
IssueType.LEXICAL,
201+
"token recognition error at: '#'",
202+
IssueSeverity.ERROR,
203+
new Position(new Point(1, 1), new Point(1, 1)),
204+
undefined,
205+
"lexer.tokenrecognitionerror",
206+
[
207+
{
208+
name: "token",
209+
value: "#"
210+
}
211+
]
212+
),
213+
new Issue(
214+
IssueType.LEXICAL,
215+
"token recognition error at: '#'",
216+
IssueSeverity.ERROR,
217+
new Position(new Point(1, 2), new Point(1, 2)),
218+
undefined,
219+
"lexer.tokenrecognitionerror",
220+
[
221+
{
222+
name: "token",
223+
value: "#"
224+
}
225+
]
226+
)])
227+
})
39228
});

0 commit comments

Comments
 (0)