mirror of
https://github.com/AeThex-Corporation/AeThex-OS.git
synced 2026-04-18 22:37:21 +00:00
492 lines
No EOL
17 KiB
JavaScript
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
|