"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