AeThex-OS/packages/aethex-cli/lib/compiler/Parser.js

492 lines
No EOL
17 KiB
JavaScript

"use strict";
/**
* AeThex Compiler - Parser (AST Builder)
* Converts tokens into Abstract Syntax Tree
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Parser = void 0;
const Lexer_1 = require("./Lexer");
class Parser {
constructor(tokens) {
this.current = 0;
this.tokens = tokens;
}
parse() {
const body = [];
while (!this.isAtEnd()) {
const node = this.parseTopLevel();
if (node) {
body.push(node);
}
}
return {
type: 'Program',
body,
line: 1
};
}
parseTopLevel() {
if (this.check(Lexer_1.TokenType.REALITY)) {
return this.parseReality();
}
if (this.check(Lexer_1.TokenType.JOURNEY)) {
return this.parseJourney();
}
if (this.check(Lexer_1.TokenType.IMPORT)) {
return this.parseImport();
}
this.advance();
return null;
}
parseReality() {
const token = this.consume(Lexer_1.TokenType.REALITY, 'Expected "reality"');
const name = this.consume(Lexer_1.TokenType.IDENTIFIER, 'Expected reality name').value;
this.consume(Lexer_1.TokenType.LEFT_BRACE, 'Expected "{"');
const properties = {};
while (!this.check(Lexer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
const key = this.consume(Lexer_1.TokenType.IDENTIFIER, 'Expected property name').value;
this.consume(Lexer_1.TokenType.COLON, 'Expected ":"');
if (this.check(Lexer_1.TokenType.LEFT_BRACKET)) {
properties[key] = this.parseArray();
}
else if (this.check(Lexer_1.TokenType.STRING)) {
properties[key] = this.advance().value;
}
else if (this.check(Lexer_1.TokenType.IDENTIFIER)) {
const value = this.advance().value;
if (value === 'all') {
properties[key] = ['all'];
}
else {
properties[key] = value;
}
}
}
this.consume(Lexer_1.TokenType.RIGHT_BRACE, 'Expected "}"');
return {
type: 'Reality',
name,
properties,
line: token.line
};
}
parseJourney() {
const token = this.consume(Lexer_1.TokenType.JOURNEY, 'Expected "journey"');
const name = this.consume(Lexer_1.TokenType.IDENTIFIER, 'Expected journey name').value;
this.consume(Lexer_1.TokenType.LEFT_PAREN, 'Expected "("');
const params = [];
while (!this.check(Lexer_1.TokenType.RIGHT_PAREN) && !this.isAtEnd()) {
params.push(this.consume(Lexer_1.TokenType.IDENTIFIER, 'Expected parameter name').value);
if (!this.check(Lexer_1.TokenType.RIGHT_PAREN)) {
this.consume(Lexer_1.TokenType.COMMA, 'Expected ","');
}
}
this.consume(Lexer_1.TokenType.RIGHT_PAREN, 'Expected ")"');
this.consume(Lexer_1.TokenType.LEFT_BRACE, 'Expected "{"');
const body = [];
while (!this.check(Lexer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
const stmt = this.parseStatement();
if (stmt) {
body.push(stmt);
}
}
this.consume(Lexer_1.TokenType.RIGHT_BRACE, 'Expected "}"');
return {
type: 'Journey',
name,
params,
body,
line: token.line
};
}
parseImport() {
const token = this.consume(Lexer_1.TokenType.IMPORT, 'Expected "import"');
this.consume(Lexer_1.TokenType.LEFT_BRACE, 'Expected "{"');
const specifiers = [];
while (!this.check(Lexer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
specifiers.push(this.consume(Lexer_1.TokenType.IDENTIFIER, 'Expected identifier').value);
if (!this.check(Lexer_1.TokenType.RIGHT_BRACE)) {
this.consume(Lexer_1.TokenType.COMMA, 'Expected ","');
}
}
this.consume(Lexer_1.TokenType.RIGHT_BRACE, 'Expected "}"');
this.consume(Lexer_1.TokenType.FROM, 'Expected "from"');
const source = this.consume(Lexer_1.TokenType.STRING, 'Expected string').value;
return {
type: 'Import',
specifiers,
source,
line: token.line
};
}
parseStatement() {
// Skip platform declarations
if (this.check(Lexer_1.TokenType.PLATFORM)) {
this.advance();
this.consume(Lexer_1.TokenType.COLON, 'Expected ":"');
this.advance(); // skip platform name or block
return null;
}
if (this.check(Lexer_1.TokenType.LET)) {
return this.parseLetStatement();
}
if (this.check(Lexer_1.TokenType.WHEN)) {
return this.parseWhenStatement();
}
if (this.check(Lexer_1.TokenType.NOTIFY)) {
return this.parseNotifyStatement();
}
if (this.check(Lexer_1.TokenType.REVEAL)) {
return this.parseRevealStatement();
}
if (this.check(Lexer_1.TokenType.SYNC)) {
return this.parseSyncStatement();
}
if (this.check(Lexer_1.TokenType.RETURN)) {
return this.parseReturnStatement();
}
// Expression statement
const expr = this.parseExpression();
return {
type: 'ExpressionStatement',
expression: expr,
line: this.peek().line
};
}
parseLetStatement() {
const token = this.consume(Lexer_1.TokenType.LET, 'Expected "let"');
const identifier = this.consume(Lexer_1.TokenType.IDENTIFIER, 'Expected identifier').value;
this.consume(Lexer_1.TokenType.EQUALS, 'Expected "="');
const value = this.parseExpression();
return {
type: 'LetStatement',
identifier,
value,
line: token.line
};
}
parseWhenStatement() {
const token = this.consume(Lexer_1.TokenType.WHEN, 'Expected "when"');
const condition = this.parseExpression();
this.consume(Lexer_1.TokenType.LEFT_BRACE, 'Expected "{"');
const consequent = [];
while (!this.check(Lexer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
const stmt = this.parseStatement();
if (stmt) {
consequent.push(stmt);
}
}
this.consume(Lexer_1.TokenType.RIGHT_BRACE, 'Expected "}"');
let alternate;
if (this.check(Lexer_1.TokenType.OTHERWISE)) {
this.advance();
this.consume(Lexer_1.TokenType.LEFT_BRACE, 'Expected "{"');
alternate = [];
while (!this.check(Lexer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
const stmt = this.parseStatement();
if (stmt) {
alternate.push(stmt);
}
}
this.consume(Lexer_1.TokenType.RIGHT_BRACE, 'Expected "}"');
}
return {
type: 'WhenStatement',
condition,
consequent,
alternate,
line: token.line
};
}
parseNotifyStatement() {
const token = this.consume(Lexer_1.TokenType.NOTIFY, 'Expected "notify"');
const message = this.parseExpression();
return {
type: 'NotifyStatement',
message,
line: token.line
};
}
parseRevealStatement() {
const token = this.consume(Lexer_1.TokenType.REVEAL, 'Expected "reveal"');
const value = this.parseExpression();
return {
type: 'RevealStatement',
value,
line: token.line
};
}
parseSyncStatement() {
const token = this.consume(Lexer_1.TokenType.SYNC, 'Expected "sync"');
const target = this.parseExpression();
this.consume(Lexer_1.TokenType.ACROSS, 'Expected "across"');
const platforms = this.parseArray();
return {
type: 'SyncStatement',
target,
platforms: platforms.map(p => p.toString()),
line: token.line
};
}
parseReturnStatement() {
const token = this.consume(Lexer_1.TokenType.RETURN, 'Expected "return"');
return {
type: 'ReturnStatement',
line: token.line
};
}
parseExpression() {
return this.parseComparison();
}
parseComparison() {
let expr = this.parseAdditive();
while (this.check(Lexer_1.TokenType.LESS_THAN) ||
this.check(Lexer_1.TokenType.GREATER_THAN) ||
this.check(Lexer_1.TokenType.LESS_EQUALS) ||
this.check(Lexer_1.TokenType.GREATER_EQUALS) ||
this.check(Lexer_1.TokenType.EQUALS_EQUALS) ||
this.check(Lexer_1.TokenType.NOT_EQUALS)) {
const operator = this.advance().value;
const right = this.parseAdditive();
expr = {
type: 'BinaryExpression',
operator,
left: expr,
right,
line: this.peek().line
};
}
return expr;
}
parseAdditive() {
let expr = this.parseMultiplicative();
while (this.check(Lexer_1.TokenType.PLUS) || this.check(Lexer_1.TokenType.MINUS)) {
const operator = this.advance().value;
const right = this.parseMultiplicative();
expr = {
type: 'BinaryExpression',
operator,
left: expr,
right,
line: this.peek().line
};
}
return expr;
}
parseMultiplicative() {
let expr = this.parseUnary();
while (this.check(Lexer_1.TokenType.STAR) || this.check(Lexer_1.TokenType.SLASH)) {
const operator = this.advance().value;
const right = this.parseUnary();
expr = {
type: 'BinaryExpression',
operator,
left: expr,
right,
line: this.peek().line
};
}
return expr;
}
parseUnary() {
// Handle unary operators like !, -, +
if (this.check(Lexer_1.TokenType.BANG) || this.check(Lexer_1.TokenType.MINUS) || this.check(Lexer_1.TokenType.PLUS)) {
const operator = this.advance().value;
const operand = this.parseUnary(); // Recursively parse for chained unary operators
return {
type: 'UnaryExpression',
operator,
operand,
line: this.peek().line
};
}
return this.parsePostfix();
}
parsePostfix() {
let expr = this.parsePrimary();
while (true) {
if (this.check(Lexer_1.TokenType.DOT)) {
this.advance();
const property = {
type: 'Identifier',
name: this.consume(Lexer_1.TokenType.IDENTIFIER, 'Expected property name').value,
line: this.peek().line
};
expr = {
type: 'MemberExpression',
object: expr,
property,
line: this.peek().line
};
}
else if (this.check(Lexer_1.TokenType.LEFT_PAREN)) {
this.advance();
const args = [];
while (!this.check(Lexer_1.TokenType.RIGHT_PAREN) && !this.isAtEnd()) {
args.push(this.parseExpression());
if (!this.check(Lexer_1.TokenType.RIGHT_PAREN)) {
this.consume(Lexer_1.TokenType.COMMA, 'Expected ","');
}
}
this.consume(Lexer_1.TokenType.RIGHT_PAREN, 'Expected ")"');
expr = {
type: 'CallExpression',
callee: expr,
arguments: args,
line: this.peek().line
};
}
else {
break;
}
}
return expr;
}
parsePrimary() {
if (this.check(Lexer_1.TokenType.NUMBER)) {
const token = this.advance();
return {
type: 'Literal',
value: parseFloat(token.value),
raw: token.value,
line: token.line
};
}
if (this.check(Lexer_1.TokenType.STRING)) {
const token = this.advance();
return {
type: 'Literal',
value: token.value,
raw: `"${token.value}"`,
line: token.line
};
}
if (this.check(Lexer_1.TokenType.LEFT_BRACKET)) {
return this.parseArrayExpression();
}
if (this.check(Lexer_1.TokenType.LEFT_BRACE)) {
return this.parseObjectExpression();
}
if (this.check(Lexer_1.TokenType.NEW)) {
return this.parseNewExpression();
}
if (this.check(Lexer_1.TokenType.IDENTIFIER)) {
const token = this.advance();
return {
type: 'Identifier',
name: token.value,
line: token.line
};
}
if (this.check(Lexer_1.TokenType.LEFT_PAREN)) {
this.advance();
const expr = this.parseExpression();
this.consume(Lexer_1.TokenType.RIGHT_PAREN, 'Expected ")"');
return expr;
}
throw new Error(`Unexpected token: ${this.peek().value} at line ${this.peek().line}`);
}
parseArrayExpression() {
const token = this.consume(Lexer_1.TokenType.LEFT_BRACKET, 'Expected "["');
const elements = [];
while (!this.check(Lexer_1.TokenType.RIGHT_BRACKET) && !this.isAtEnd()) {
elements.push(this.parseExpression());
if (!this.check(Lexer_1.TokenType.RIGHT_BRACKET)) {
this.consume(Lexer_1.TokenType.COMMA, 'Expected ","');
}
}
this.consume(Lexer_1.TokenType.RIGHT_BRACKET, 'Expected "]"');
return {
type: 'ArrayExpression',
elements,
line: token.line
};
}
parseObjectExpression() {
const token = this.consume(Lexer_1.TokenType.LEFT_BRACE, 'Expected "{"');
const properties = [];
while (!this.check(Lexer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
const key = this.consume(Lexer_1.TokenType.IDENTIFIER, 'Expected property key').value;
this.consume(Lexer_1.TokenType.COLON, 'Expected ":"');
const value = this.parseExpression();
properties.push({ key, value });
if (!this.check(Lexer_1.TokenType.RIGHT_BRACE)) {
this.consume(Lexer_1.TokenType.COMMA, 'Expected ","');
}
}
this.consume(Lexer_1.TokenType.RIGHT_BRACE, 'Expected "}"');
return {
type: 'ObjectExpression',
properties,
line: token.line
};
}
parseNewExpression() {
const token = this.consume(Lexer_1.TokenType.NEW, 'Expected "new"');
const callee = {
type: 'Identifier',
name: this.consume(Lexer_1.TokenType.IDENTIFIER, 'Expected identifier').value,
line: token.line
};
this.consume(Lexer_1.TokenType.LEFT_PAREN, 'Expected "("');
const args = [];
while (!this.check(Lexer_1.TokenType.RIGHT_PAREN) && !this.isAtEnd()) {
args.push(this.parseExpression());
if (!this.check(Lexer_1.TokenType.RIGHT_PAREN)) {
this.consume(Lexer_1.TokenType.COMMA, 'Expected ","');
}
}
this.consume(Lexer_1.TokenType.RIGHT_PAREN, 'Expected ")"');
return {
type: 'NewExpression',
callee,
arguments: args,
line: token.line
};
}
parseArray() {
this.consume(Lexer_1.TokenType.LEFT_BRACKET, 'Expected "["');
const elements = [];
while (!this.check(Lexer_1.TokenType.RIGHT_BRACKET) && !this.isAtEnd()) {
if (this.check(Lexer_1.TokenType.IDENTIFIER)) {
elements.push(this.advance().value);
}
else if (this.check(Lexer_1.TokenType.STRING)) {
elements.push(this.advance().value);
}
if (!this.check(Lexer_1.TokenType.RIGHT_BRACKET)) {
this.consume(Lexer_1.TokenType.COMMA, 'Expected ","');
}
}
this.consume(Lexer_1.TokenType.RIGHT_BRACKET, 'Expected "]"');
return elements;
}
// Helper methods
check(type) {
if (this.isAtEnd())
return false;
return this.peek().type === type;
}
advance() {
if (!this.isAtEnd())
this.current++;
return this.previous();
}
isAtEnd() {
return this.peek().type === Lexer_1.TokenType.EOF;
}
peek() {
return this.tokens[this.current];
}
previous() {
return this.tokens[this.current - 1];
}
consume(type, message) {
if (this.check(type))
return this.advance();
const token = this.peek();
throw new Error(`${message} at line ${token.line}, column ${token.column}. Got: ${token.value}`);
}
}
exports.Parser = Parser;
//# sourceMappingURL=Parser.js.map