Skip to content

Commit

Permalink
codegen/model done
Browse files Browse the repository at this point in the history
- Fixed ActionSplitter grammar.
- Finished codegen/model.
  • Loading branch information
mike-lischke committed Oct 9, 2024
1 parent e9b0efb commit 8f2be16
Show file tree
Hide file tree
Showing 84 changed files with 1,285 additions and 1,750 deletions.
3 changes: 3 additions & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
"Approximator",
"CMDLINE",
"COLONCOLON",
"Daccess",
"Dexport",
"Dlanguage",
"Dsuper",
"Evals",
Expand Down Expand Up @@ -72,6 +74,7 @@
"arraycopy",
"attrname",
"bitness",
"bitsets",
"clazz",
"codegen",
"decapitalize",
Expand Down
18 changes: 17 additions & 1 deletion eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ export default tslint.config(
"./tsconfig.json",
"./tests/tsconfig.json"
],
"allowDefaultProject": [
allowDefaultProject: [
"./tests"
]
},
},
ignores: ["src/generated/*"],
rules: {
"no-fallthrough": [
"warn",
Expand Down Expand Up @@ -77,7 +78,17 @@ export default tslint.config(
"always"
],
"@stylistic/no-multiple-empty-lines": ["error", { "max": 1 }],
"@stylistic/no-multi-spaces": "error",
"@stylistic/lines-around-comment": [
"error",
{
"afterBlockComment": false,
"afterLineComment": false,
}
],
"lines-between-class-members": "off", // Should be on, but handles overload signatures incorrectly.

"@typescript-eslint/adjacent-overload-signatures": "error",
"@typescript-eslint/no-explicit-any": "error",
"@typescript-eslint/no-namespace": "off",
"@typescript-eslint/no-non-null-assertion": "off",
Expand All @@ -89,10 +100,13 @@ export default tslint.config(
{
// No ordering for getters and setters here, as that conflicts currently with the rule
// adjacent-overload-signatures.

"default": [
// Index signature

"signature",
// Fields

"public-static-field",
"protected-static-field",
"private-static-field",
Expand All @@ -110,11 +124,13 @@ export default tslint.config(
"decorated-field",
"field",
// Constructors

"public-constructor",
"protected-constructor",
"private-constructor",
"constructor",
// Methods

"public-static-method",
"protected-static-method",
"private-static-method",
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"@typescript-eslint/eslint-plugin": "8.7.0",
"@typescript-eslint/parser": "8.7.0",
"@unicode/unicode-15.1.0": "1.6.0",
"antlr4ng-cli": "2.0.0",
"eslint": "9.11.1",
"eslint-plugin-jsdoc": "50.3.0",
"eslint-plugin-prefer-arrow": "1.2.3",
Expand Down
190 changes: 115 additions & 75 deletions src/grammars/ActionSplitter.g4
Original file line number Diff line number Diff line change
Expand Up @@ -4,105 +4,145 @@
* can be found in the LICENSE.txt file in the project root.
*/

grammar ActionSplitter;
lexer grammar ActionSplitter;

// $antlr-format alignTrailingComments on, columnLimit 150, maxEmptyLinesToKeep 1, reflowComments off, useTab off
// $antlr-format allowShortRulesOnASingleLine off, minEmptyLines 0, alignSemicolons ownLine

@lexer::header {
import type { ActionSplitterListener } from "../../tool/src/org/antlr/v4/parse/ActionSplitterListener.js";
}
// $antlr-format allowShortRulesOnASingleLine on, alignSemicolons none, minEmptyLines 0

@parser::header {
import type { ActionSplitterListener } from "../../tool/src/org/antlr/v4/parse/ActionSplitterListener.js";
@header {
import { Character } from "../../tool/src/org/antlr/v4/support/Character.js";
import type { ActionSplitterListener } from "../../tool/src/org/antlr/v4/parse/ActionSplitterListener.js";
}

@parser::members {
public delegate: ActionSplitterListener;
private isIDStartChar(c: number): boolean {
return c == 0x5F /* "_" */ || Character.isLetter(c);
}
}

@lexer::members {
public delegate: ActionSplitterListener;
@members {
/** Force filtering (and return tokens). Triggers all above actions. */
public getActionTokens(): Token[] {
/** Force filtering (and return tokens).Sends token values to the delegate. */
public getActionTokens(delegate: ActionSplitterListener): Token[] {
const chunks = new Array<Token>();
let t = this.nextToken();
while (t.type !== Token.EOF) {
switch (t.type) {
case ActionSplitter.COMMENT:
case ActionSplitter.LINE_COMMENT:
case ActionSplitter.TEXT: {
delegate.text(t.text!);
break;
}

case ActionSplitter.SET_NONLOCAL_ATTR: {
const regex = /\$(?<x>[a-zA-Z_][a-zA-Z0-9_]*)::\s*(?<y>[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(?<expr>[^=][^;]*);/;
const text = t.text!;
// Parse the text and extract the named groups from the match result.
const match = text.match(regex);
if (match === null) {
throw new Error(`Mismatched input '${text}'`);
}

const { x, y, expr } = match.groups!;
delegate.setNonLocalAttr(text, x, y, expr);

break;
}

case ActionSplitter.NONLOCAL_ATTR: {
const regex = /\$(?<x>[a-zA-Z_][a-zA-Z0-9_]*)::\s*(?<y>[a-zA-Z_][a-zA-Z0-9_]*)/;
const text = t.text!;
const match = text.match(regex);
if (match === null) {
throw new Error(`Mismatched input '${text}'`);
}

const { x, y } = match.groups!;
delegate.nonLocalAttr(text, x, y);

break;
}

case ActionSplitter.QUALIFIED_ATTR: {
const regex = /\$(?<x>[a-zA-Z_][a-zA-Z0-9_]*)::\s*(?<y>[a-zA-Z_][a-zA-Z0-9_]*)/;
const text = t.text!;
const match = text.match(regex);
if (match === null) {
throw new Error(`Mismatched input '${text}'`);
}

const { x, y } = match.groups!;
delegate.qualifiedAttr(text, x, y);

break;
}

case ActionSplitter.SET_ATTR: {
const regex = /\$(?<x>[a-zA-Z_][a-zA-Z0-9_]*)\s*=\s*(?<expr>[^=][^;]*);/;
const text = t.text!;
const match = text.match(regex);
if (match === null) {
throw new Error(`Mismatched input '${text}'`);
}

const { x, expr } = match.groups!;
delegate.setAttr(text, x, expr);

break;
}

case ActionSplitter.ATTR: {
const regex = /\$(?<x>[a-zA-Z_][a-zA-Z0-9_]*)/;
const text = t.text!;
const match = text.match(regex);
if (match === null) {
throw new Error(`Mismatched input '${text}'`);
}

const { x } = match.groups!;
delegate.attr(text, x);

break;
}

default:
}

chunks.push(t);
t = this.nextToken();
}

return chunks;
}

private isIDStartChar(c: number): boolean {
return c == 0x5F /* "_" */ || Character.isLetter(c);
}

parse: (
setAttr
| attr
| qualifiedAttribute
| nonLocalAttribute
| setNoneLocalAttribute
| nonLocalAttribute
| randomText
)* EOF
;

setNoneLocalAttribute:
DOLLAR x = ID COLONCOLON y = ID WS? EQUAL expr = ATTR_VALUE_EXPR SEMICOLON { this.delegate.setNonLocalAttr($text, $x, $y, $expr); }
;

nonLocalAttribute:
DOLLAR x = ID COLONCOLON y = ID {this.delegate.nonLocalAttr($text, $x, $y);}
;

qualifiedAttribute:
DOLLAR x = ID DOT y = ID {this.inputStream.LA(1) !== 0x28 /* '(' */}? {this.delegate.qualifiedAttr($text, $x, $y);}
;

setAttr:
DOLLAR x = ID WS? EQUAL expr = ATTR_VALUE_EXPR SEMICOLON { this.delegate.setAttr($text, $x, $expr); }
;

attr:
DOLLAR x = ID {this.delegate.attr($text, $x);}
;
}

// Anything else is just random text
randomText
@init {let buf = "";}
@after {this.delegate.text(buf);}: (
c = ~(BACKSLASH | DOLLAR) {buf += $c;}
| ESCAPED_DOLLAR {buf += "$";}
| BACKSLASH c = ~(DOLLAR) {buf += "\\" + $c;}
| {!this.isIDStartChar(this.inputStream.LA(2))}? DOLLAR {buf += "$";}
)+
;
// ignore comments right away

// $antlr-format allowShortRulesOnASingleLine on, alignSemicolons none, minEmptyLines 0
COMMENT: '/*' .*? '*/';
LINE_COMMENT: '//' ~('\n' | '\r')* '\r'? '\n';

DOLLAR: '$';
ESCAPED_DOLLAR: '\\$';
EQUAL: '=';
DOT: '.';
COLONCOLON: '::';
SEMICOLON: ';';
SLASHSLASH: '//';
BACKSLASH: '\\';
SET_NONLOCAL_ATTR: '$' ID '::' ID WS? '=' ATTR_VALUE_EXPR ';';

// ignore comments right away
COMMENT: '/*' .*? '*/' {this.delegate.text(this.text);};
NONLOCAL_ATTR: '$' ID '::' ID;

QUALIFIED_ATTR: '$' ID '.' ID;

SET_ATTR: '$' ID WS? '=' ATTR_VALUE_EXPR ';';

LINE_COMMENT: SLASHSLASH .*? '\r'? '\n' {this.delegate.text(this.text);};
ATTR: '$' ID;

// Anything else is just random text
TEXT: ( ~('\\' | '$') | '\\$' | '\\' ~('$') | {!this.isIDStartChar(this.inputStream.LA(2))}? '$')+;

ID: [a-zA-Z_] [a-zA-Z_0-9]*;
fragment ID: ('a' ..'z' | 'A' ..'Z' | '_') ('a' ..'z' | 'A' ..'Z' | '0' ..'9' | '_')*;

/** Don't allow an = as first char to prevent $x == 3; kind of stuff. */
ATTR_VALUE_EXPR: ~'=' (~';')*;
fragment ATTR_VALUE_EXPR: ~'=' (~';')*;

WS: [ \t\n\r]+;
fragment WS: (' ' | '\t' | '\n' | '\r')+;
2 changes: 1 addition & 1 deletion tool/src/org/antlr/v4/Tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { IATNFactory } from "./automata/IATNFactory.js";
import { LexerATNFactory } from "./automata/LexerATNFactory.js";
import { ParserATNFactory } from "./automata/ParserATNFactory.js";
import { CodeGenPipeline } from "./codegen/CodeGenPipeline.js";
import { CodeGenerator, targetLanguages, type SupportedLanguage } from "./codegen/CodeGenerator.js";
import { CodeGenerator } from "./codegen/CodeGenerator.js";
import { grammarOptions } from "./grammar-options.js";
import { Graph } from "./misc/Graph.js";
import { GrammarASTAdaptor } from "./parse/GrammarASTAdaptor.js";
Expand Down
2 changes: 1 addition & 1 deletion tool/src/org/antlr/v4/automata/ATNOptimizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export class ATNOptimizer {
}

let newTransition: Transition;
const intervals = [...matchSet];
const intervals = Array.from(matchSet);
if (intervals.length === 1) {
const matchInterval = intervals[0];
newTransition = CodePointTransitions.createWithCodePointRange(blockEndState, matchInterval.start,
Expand Down
Loading

0 comments on commit 8f2be16

Please sign in to comment.