Skip to content

Commit

Permalink
bugfix: Fix improper state generation in setShiftAction
Browse files Browse the repository at this point in the history
Previously, setShiftAction could modify
an already populated state instead of
regenerating its successor. This is
problematic because

0. the modified state was then not marked
   for regeneration, so it could be left
   in an inconsisten state
1. the modified state could also be a successor
   of another state and the modification could
   hypothetically be incorrect for that state
  • Loading branch information
mik-jozef committed Nov 22, 2023
1 parent 5dcfb47 commit 392abca
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 10 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lr-parser-typescript",
"version": "1.1.1",
"version": "1.1.2",
"scripts": {
"build": "rm -rf ./local/out \n tsc",
"prepublishOnly": "yarn run build && yarn run test",
Expand Down
2 changes: 1 addition & 1 deletion src/_tests/grammar-5.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,5 @@ matchValueProcedureCall.match = ProcedureCall;
matchValueExprRung.match = ExprRung;

export const parser = new Parser(ExprRung, {
logLevel: LogLevel.verbose,
logLevel: LogLevel.none,
});
32 changes: 32 additions & 0 deletions src/_tests/grammar-6.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { LetDeclaration, parser } from "./grammar-6.js";
import { ParseError } from "../parser/parser.js";

describe('Parser', () => {
it('does not parse ""', () => {
const result = parser.parse('');

expect(result).toBeInstanceOf(ParseError);
});

it('does not parse "l"', () => {
const result = parser.parse('l');

expect(result).toBeInstanceOf(ParseError);
});

it('parses "l{}"', () => {
const result = parser.parse('l{}');

expect(result).toBeInstanceOf(LetDeclaration);
expect(result as LetDeclaration).toHaveProperty('body', []);
});

it('parses "l{l{}}"', () => {
const result = parser.parse('l{l{}}');

expect(result).toBeInstanceOf(LetDeclaration);
expect(result as LetDeclaration).toHaveProperty('body', [
expect.any(LetDeclaration),
]);
});
});
23 changes: 23 additions & 0 deletions src/_tests/grammar-6.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Caten, Maybe, MatchArr, SyntaxTreeNode } from "#pattern";
import { LogLevel } from "../parser/table/generate-table.js";
import { Parser } from "../parser/parser.js";


export class LetDeclaration extends SyntaxTreeNode {
body!: LetDeclaration[];

static pattern: Caten = new Caten(
'l',
'{',
new Maybe(
new MatchArr('body', LetDeclaration),
),
'}',
);
}

export const parser = new Parser(LetDeclaration, {
logLevel: LogLevel.verbose,
});

parser.parse('l{l{}}');
15 changes: 7 additions & 8 deletions src/parser/table/parser-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,19 +120,18 @@ export class ParserState {
under: GrammarSymbol | null,
ruleAt: RuleAt,
): GrammarConflict | null {
if (!this.actions.has(under)) {
this.actions.set(
under,
new ParserState([], [ ...this.exampleLane, under ]),
);
}

const maybeParserState = this.actions.get(under)!;
let maybeParserState = this.actions.get(under);

if (maybeParserState instanceof GrammarRule) {
return new GrammarConflict(this, under, maybeParserState);
}

if (!maybeParserState || maybeParserState.isPopulated()) {
maybeParserState = new ParserState([], [ ...this.exampleLane, under ]);

this.actions.set(under, maybeParserState);
}

maybeParserState.insert(ruleAt);

return null;
Expand Down

0 comments on commit 392abca

Please sign in to comment.