mirror of
https://github.com/hi-language/transpiler.git
synced 2026-01-13 16:18:04 +00:00
Fix: Disambiguate grammar; add objects/rel ops/assignable
This commit is contained in:
123
src/parser.js
123
src/parser.js
@@ -19,19 +19,30 @@ class HiParser extends CstParser {
|
||||
{ ALT: () => $.SUBRULE($.expressionStatement) },
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
$.RULE('declaration', () => {
|
||||
$.CONSUME(T.Identifier);
|
||||
$.CONSUME(T.Colon);
|
||||
$.SUBRULE($.expression);
|
||||
});
|
||||
|
||||
$.RULE('assignment', () => {
|
||||
// assignable supports: Identifier(.Identifier | [expression])*
|
||||
$.RULE('assignable', () => {
|
||||
$.CONSUME(T.Identifier);
|
||||
$.MANY(() => {
|
||||
$.OR([
|
||||
{ ALT: () => { $.CONSUME(T.Dot); $.CONSUME2(T.Identifier); } },
|
||||
{ ALT: () => { $.CONSUME(T.LBracket); $.SUBRULE($.expression); $.CONSUME(T.RBracket); } }
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
$.RULE('assignment', () => {
|
||||
$.SUBRULE($.assignable, { LABEL: 'left' });
|
||||
$.CONSUME(T.Eq);
|
||||
$.SUBRULE($.expression);
|
||||
});
|
||||
|
||||
|
||||
$.RULE('returnStatement', () => {
|
||||
$.CONSUME(T.Caret);
|
||||
$.OPTION(() => $.SUBRULE($.expression));
|
||||
@@ -39,32 +50,14 @@ class HiParser extends CstParser {
|
||||
|
||||
$.RULE('expressionStatement', () => $.SUBRULE($.expression));
|
||||
|
||||
// --- Expressions (ordered by precedence, highest to lowest) ---
|
||||
// --- Primary and building blocks ---
|
||||
|
||||
// Primary is the highest precedence expression.
|
||||
$.RULE('primary', () => {
|
||||
$.OR([
|
||||
{ ALT: () => $.SUBRULE($.literal) },
|
||||
{ ALT: () => $.CONSUME(T.Identifier) },
|
||||
{ ALT: () => $.CONSUME(T.At) },
|
||||
{ ALT: () => $.SUBRULE($.arrowExpression) },
|
||||
{ ALT: () => $.SUBRULE($.block) },
|
||||
{ ALT: () => $.SUBRULE($.arrayLiteral) },
|
||||
{ ALT: () => {
|
||||
$.CONSUME(T.LParen);
|
||||
$.SUBRULE($.expression);
|
||||
$.CONSUME(T.RParen);
|
||||
}}
|
||||
]);
|
||||
});
|
||||
|
||||
// Components used by Primary
|
||||
$.RULE('literal', () => $.OR([
|
||||
{ ALT: () => $.CONSUME(T.Number) },
|
||||
{ ALT: () => $.CONSUME(T.String) },
|
||||
{ ALT: () => $.CONSUME(T.Null) }
|
||||
]));
|
||||
|
||||
|
||||
$.RULE('arrayLiteral', () => {
|
||||
$.CONSUME(T.LBracket);
|
||||
$.OPTION(() => {
|
||||
@@ -88,21 +81,36 @@ class HiParser extends CstParser {
|
||||
});
|
||||
$.CONSUME(T.RParen);
|
||||
});
|
||||
|
||||
$.RULE('block', () => {
|
||||
$.OPTION(() => $.SUBRULE($.parameterList));
|
||||
|
||||
// A code block with statements (used in arrow bodies or as expression blocks)
|
||||
$.RULE('codeBlock', () => {
|
||||
$.CONSUME(T.LBrace);
|
||||
$.SUBRULE($.statements);
|
||||
$.CONSUME(T.RBrace);
|
||||
});
|
||||
|
||||
$.RULE('arrowExpression', () => {
|
||||
|
||||
// Object literal: { key: expr, key2: expr, ... } (commas optional via newlines)
|
||||
$.RULE('objectLiteral', () => {
|
||||
$.CONSUME(T.LBrace);
|
||||
$.MANY(() => {
|
||||
$.CONSUME(T.Identifier);
|
||||
$.CONSUME(T.Colon);
|
||||
$.SUBRULE($.expression);
|
||||
});
|
||||
$.CONSUME(T.RBrace);
|
||||
});
|
||||
|
||||
// (a, b) { ... } function sugar
|
||||
$.RULE('functionExpression', () => {
|
||||
$.SUBRULE($.parameterList);
|
||||
$.CONSUME(T.Arrow);
|
||||
$.OR([
|
||||
{ ALT: () => $.SUBRULE($.block) },
|
||||
{ ALT: () => $.SUBRULE($.expression) }
|
||||
]);
|
||||
$.SUBRULE($.codeBlock);
|
||||
});
|
||||
|
||||
// ( ... ) parenthesized expression
|
||||
$.RULE('parenthesizedExpression', () => {
|
||||
$.CONSUME(T.LParen);
|
||||
$.SUBRULE($.expression);
|
||||
$.CONSUME(T.RParen);
|
||||
});
|
||||
|
||||
// MemberExpression consumes a Primary.
|
||||
@@ -125,7 +133,7 @@ class HiParser extends CstParser {
|
||||
$.CONSUME(T.RParen);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$.RULE('argumentList', () => {
|
||||
$.SUBRULE($.expression);
|
||||
$.MANY(() => {
|
||||
@@ -134,7 +142,36 @@ class HiParser extends CstParser {
|
||||
});
|
||||
});
|
||||
|
||||
// Binary Expressions are defined with a helper.
|
||||
// --- Arrow and Primary disambiguation ---
|
||||
|
||||
$.RULE('arrowExpression', () => {
|
||||
$.SUBRULE($.parameterList);
|
||||
$.CONSUME(T.Arrow);
|
||||
$.OR([
|
||||
{ GATE: () => this.LA(1).tokenType === T.LBrace, ALT: () => $.SUBRULE($.codeBlock) },
|
||||
{ ALT: () => $.SUBRULE($.expression) }
|
||||
]);
|
||||
});
|
||||
|
||||
$.RULE('primary', () => {
|
||||
$.OR([
|
||||
{ ALT: () => $.SUBRULE($.literal) },
|
||||
{ ALT: () => $.CONSUME(T.Identifier) },
|
||||
{ ALT: () => $.CONSUME(T.At) },
|
||||
// Try arrow first: ( ... ) =>
|
||||
{ GATE: this.BACKTRACK($.arrowExpression), ALT: () => $.SUBRULE($.arrowExpression) },
|
||||
// Then function sugar: ( ... ) { ... }
|
||||
{ GATE: this.BACKTRACK($.functionExpression), ALT: () => $.SUBRULE($.functionExpression) },
|
||||
// Prefer object literal over code block when both start with { ... }
|
||||
{ GATE: this.BACKTRACK($.objectLiteral), ALT: () => $.SUBRULE($.objectLiteral) },
|
||||
{ ALT: () => $.SUBRULE($.codeBlock) },
|
||||
{ ALT: () => $.SUBRULE($.arrayLiteral) },
|
||||
{ ALT: () => $.SUBRULE($.parenthesizedExpression) }
|
||||
]);
|
||||
});
|
||||
|
||||
// --- Binary Expressions with correct precedence ---
|
||||
|
||||
const buildBinaryExpressionRule = (name, higherPrecRule, operators) => {
|
||||
$.RULE(name, () => {
|
||||
$.SUBRULE(higherPrecRule, { LABEL: 'left' });
|
||||
@@ -145,16 +182,23 @@ class HiParser extends CstParser {
|
||||
});
|
||||
};
|
||||
|
||||
// Define binary expressions from highest to lowest precedence.
|
||||
// multiplicative -> call
|
||||
buildBinaryExpressionRule('multiplicativeExpression', $.callExpression, [
|
||||
{ ALT: () => $.CONSUME(T.Star) }, { ALT: () => $.CONSUME(T.Slash) }
|
||||
]);
|
||||
|
||||
// additive -> multiplicative
|
||||
buildBinaryExpressionRule('additiveExpression', $.multiplicativeExpression, [
|
||||
{ ALT: () => $.CONSUME(T.Plus) }, { ALT: () => $.CONSUME(T.Minus) }
|
||||
]);
|
||||
|
||||
buildBinaryExpressionRule('equalityExpression', $.additiveExpression, [
|
||||
// relational -> additive
|
||||
buildBinaryExpressionRule('relationalExpression', $.additiveExpression, [
|
||||
{ ALT: () => $.CONSUME(T.Gt) }, { ALT: () => $.CONSUME(T.Lt) }
|
||||
]);
|
||||
|
||||
// equality -> relational
|
||||
buildBinaryExpressionRule('equalityExpression', $.relationalExpression, [
|
||||
{ ALT: () => $.CONSUME(T.EqEq) }
|
||||
]);
|
||||
|
||||
@@ -170,12 +214,13 @@ class HiParser extends CstParser {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// Expression is the lowest precedence rule, forming the entry point for the chain.
|
||||
$.RULE('expression', () => $.SUBRULE($.conditionalExpression));
|
||||
|
||||
|
||||
this.performSelfAnalysis();
|
||||
}
|
||||
}
|
||||
|
||||
export const parser = new HiParser();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user