UNPKG

@prism-lang/core

Version:

A programming language for uncertainty

993 lines 96.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Parser = exports.ParseError = void 0; exports.parse = parse; const tokenizer_1 = require("./tokenizer"); const ast_1 = require("./ast"); class ParseError extends Error { token; sourceCode; constructor(message, token, sourceCode) { const errorMessage = ParseError.formatError(message, token, sourceCode); super(errorMessage); this.token = token; this.sourceCode = sourceCode; this.name = 'ParseError'; } static formatError(message, token, sourceCode) { let errorMsg = `ParseError at line ${token.line}, column ${token.column}: ${message}`; if (sourceCode) { const lines = sourceCode.split('\n'); const errorLine = lines[token.line - 1]; if (errorLine) { errorMsg += '\n\n'; errorMsg += ` ${token.line} | ${errorLine}\n`; errorMsg += ` ${' '.repeat(token.column)}^`; // Add some context - show the token that caused the error if (token.type !== tokenizer_1.TokenType.EOF) { errorMsg += `\n\nFound: '${token.value}' (${tokenizer_1.TokenType[token.type]})`; } } } return errorMsg; } } exports.ParseError = ParseError; class Parser { tokens; current = 0; sourceCode; constructor(tokens, sourceCode) { this.tokens = tokens; this.sourceCode = sourceCode; } parse() { const statements = []; while (!this.isAtEnd()) { const stmt = this.statement(); if (stmt) { statements.push(stmt); } } return new ast_1.Program(statements); } statement() { try { if (this.match(tokenizer_1.TokenType.ASYNC)) { // async can only be followed by function for now this.consume(tokenizer_1.TokenType.FUNCTION, "Expected 'function' after 'async'"); return this.functionDeclaration(true); } if (this.match(tokenizer_1.TokenType.FUNCTION)) { return this.functionDeclaration(false); } if (this.match(tokenizer_1.TokenType.RETURN)) { return this.returnStatement(); } if (this.match(tokenizer_1.TokenType.CONST, tokenizer_1.TokenType.LET)) { return this.variableDeclaration(); } if (this.match(tokenizer_1.TokenType.AGENTS)) { return this.agentsStatement(); } if (this.match(tokenizer_1.TokenType.UNCERTAIN)) { // Check what follows 'uncertain' if (this.check(tokenizer_1.TokenType.IF)) { return this.uncertainIfStatement(); } else if (this.check(tokenizer_1.TokenType.FOR)) { return this.uncertainForStatement(); } else if (this.check(tokenizer_1.TokenType.WHILE)) { return this.uncertainWhileStatement(); } else { throw new ParseError("Expected 'if', 'for', or 'while' after 'uncertain'", this.peek(), this.sourceCode); } } if (this.match(tokenizer_1.TokenType.IF)) { return this.ifStatement(); } if (this.match(tokenizer_1.TokenType.FOR)) { return this.forStatement(); } if (this.match(tokenizer_1.TokenType.WHILE)) { return this.whileStatement(); } if (this.match(tokenizer_1.TokenType.DO)) { return this.doWhileStatement(); } if (this.match(tokenizer_1.TokenType.BREAK)) { return this.breakStatement(); } if (this.match(tokenizer_1.TokenType.CONTINUE)) { return this.continueStatement(); } if (this.match(tokenizer_1.TokenType.IN)) { return this.contextStatement(); } if (this.match(tokenizer_1.TokenType.IMPORT)) { return this.importStatement(); } if (this.match(tokenizer_1.TokenType.EXPORT)) { return this.exportStatement(); } // Check for potential destructuring patterns if (this.check(tokenizer_1.TokenType.LEFT_BRACKET)) { // Array destructuring pattern - parse as expression statement return this.expressionStatement(); } if (this.check(tokenizer_1.TokenType.LEFT_BRACE)) { // Look ahead to determine if this is a block or object literal const checkpoint = this.current; this.advance(); // consume { let isObjectOrDestructuring = false; // Check various patterns that indicate object literal or destructuring if (this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { // Empty object {} isObjectOrDestructuring = true; } else if (this.check(tokenizer_1.TokenType.SPREAD)) { // Spread in object {...x} isObjectOrDestructuring = true; } else if (this.check(tokenizer_1.TokenType.IDENTIFIER)) { // Look ahead one more token after identifier this.advance(); if (this.check(tokenizer_1.TokenType.COMMA) || this.check(tokenizer_1.TokenType.COLON) || this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { // Object property syntax isObjectOrDestructuring = true; } else if (this.check(tokenizer_1.TokenType.CONFIDENCE_ARROW)) { // Confidence arrow after identifier in {} context // This is likely a destructuring pattern isObjectOrDestructuring = true; } else if (this.check(tokenizer_1.TokenType.EQUAL)) { // Could be destructuring with default value {x = default} or assignment {x = y} // Look further ahead to distinguish const checkPoint2 = this.current; this.advance(); // skip = // Skip the default value expression let depth = 0; while (!this.isAtEnd() && (depth > 0 || (!this.check(tokenizer_1.TokenType.COMMA) && !this.check(tokenizer_1.TokenType.RIGHT_BRACE)))) { if (this.check(tokenizer_1.TokenType.LEFT_PAREN) || this.check(tokenizer_1.TokenType.LEFT_BRACKET) || this.check(tokenizer_1.TokenType.LEFT_BRACE)) { depth++; } else if (this.check(tokenizer_1.TokenType.RIGHT_PAREN) || this.check(tokenizer_1.TokenType.RIGHT_BRACKET) || this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { depth--; } this.advance(); } // If followed by comma or }, it's likely object destructuring with default if (this.check(tokenizer_1.TokenType.COMMA) || this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { // Check if the closing } is followed by = if (this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { const checkPoint3 = this.current; this.advance(); // skip } if (this.check(tokenizer_1.TokenType.EQUAL)) { isObjectOrDestructuring = true; } this.current = checkPoint3; } else { // Has comma, likely part of destructuring pattern isObjectOrDestructuring = true; } } this.current = checkPoint2; } } // Restore position this.current = checkpoint; if (isObjectOrDestructuring) { // Parse as expression statement (which will handle both object literals and destructuring) return this.expressionStatement(); } else { // Parse as block statement this.advance(); // consume { return this.blockStatement(); } } return this.expressionStatement(); } catch (error) { this.synchronize(); throw error; } } agentsStatement() { this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after 'agents'"); const statements = []; while (!this.check(tokenizer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) { const agentDecl = this.agentDeclaration(); statements.push(agentDecl); } this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after agents block"); return new ast_1.BlockStatement(statements); } agentDeclaration() { const name = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected agent name").value; this.consume(tokenizer_1.TokenType.COLON, "Expected ':' after agent name"); this.consume(tokenizer_1.TokenType.AGENT, "Expected 'Agent' keyword"); const config = {}; if (this.match(tokenizer_1.TokenType.LEFT_BRACE)) { while (!this.check(tokenizer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) { const key = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected config key").value; this.consume(tokenizer_1.TokenType.COLON, "Expected ':' after config key"); if (key === 'confidence') { const value = this.consume(tokenizer_1.TokenType.NUMBER, "Expected number for confidence").value; config.confidence = parseFloat(value); } else if (key === 'role') { const value = this.consume(tokenizer_1.TokenType.STRING, "Expected string for role").value; config.role = value; } if (this.check(tokenizer_1.TokenType.COMMA)) { this.advance(); } } this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after agent config"); } return new ast_1.AgentDeclaration(name, config); } uncertainIfStatement() { this.consume(tokenizer_1.TokenType.IF, "Expected 'if' after 'uncertain'"); this.consume(tokenizer_1.TokenType.LEFT_PAREN, "Expected '(' after 'uncertain if'"); const condition = this.expression(); const threshold = 0.5; // default threshold, actual evaluation happens at runtime this.consume(tokenizer_1.TokenType.RIGHT_PAREN, "Expected ')' after condition"); this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after condition"); const branches = {}; while (!this.check(tokenizer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) { if (this.match(tokenizer_1.TokenType.HIGH)) { this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after 'high'"); const statements = this.blockContents(); branches.high = new ast_1.BlockStatement(statements); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after high branch"); } else if (this.match(tokenizer_1.TokenType.MEDIUM)) { this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after 'medium'"); const statements = this.blockContents(); branches.medium = new ast_1.BlockStatement(statements); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after medium branch"); } else if (this.match(tokenizer_1.TokenType.LOW)) { this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after 'low'"); const statements = this.blockContents(); branches.low = new ast_1.BlockStatement(statements); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after low branch"); } else if (this.match(tokenizer_1.TokenType.DEFAULT)) { this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after 'default'"); const statements = this.blockContents(); branches.default = new ast_1.BlockStatement(statements); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after default branch"); } else { throw new ParseError("Expected 'high', 'medium', 'low', or 'default' branch", this.peek(), this.sourceCode); } } this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after uncertain if branches"); return new ast_1.UncertainIfStatement(condition, threshold, branches); } ifStatement() { this.consume(tokenizer_1.TokenType.LEFT_PAREN, "Expected '(' after 'if'"); const condition = this.expression(); this.consume(tokenizer_1.TokenType.RIGHT_PAREN, "Expected ')' after if condition"); // For if statements, always treat { as a block statement let thenStatement; if (this.check(tokenizer_1.TokenType.LEFT_BRACE)) { this.advance(); // consume { thenStatement = this.blockStatement(); } else { const stmt = this.statement(); if (!stmt) throw new ParseError("Expected statement", this.peek(), this.sourceCode); thenStatement = stmt; } let elseStatement = undefined; if (this.match(tokenizer_1.TokenType.ELSE)) { // For else, also handle blocks directly if (this.check(tokenizer_1.TokenType.LEFT_BRACE)) { this.advance(); // consume { elseStatement = this.blockStatement(); } else { elseStatement = this.statement() || undefined; } } return new ast_1.IfStatement(condition, thenStatement, elseStatement); } contextStatement() { this.consume(tokenizer_1.TokenType.CONTEXT, "Expected 'context' after 'in'"); const contextName = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected context name").value; // For context statements, handle blocks directly let body; if (this.check(tokenizer_1.TokenType.LEFT_BRACE)) { this.advance(); // consume { body = this.blockStatement(); } else { const stmt = this.statement(); if (!stmt) throw new ParseError("Expected statement", this.peek(), this.sourceCode); body = stmt; } let shiftTo = undefined; if (this.match(tokenizer_1.TokenType.SHIFTING)) { this.consume(tokenizer_1.TokenType.TO, "Expected 'to' after 'shifting'"); shiftTo = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected context name after 'to'").value; // Parse the shifting target block if (this.check(tokenizer_1.TokenType.LEFT_BRACE)) { this.advance(); // consume { this.blockStatement(); // consume the shifting target block } else { this.statement(); // consume the shifting target statement } } return new ast_1.ContextStatement(contextName, body, shiftTo); } blockStatement() { const statements = this.blockContents(); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after block"); return new ast_1.BlockStatement(statements); } blockContents() { const statements = []; while (!this.check(tokenizer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) { const stmt = this.statement(); if (stmt) { statements.push(stmt); } } return statements; } expressionStatement() { // Look for destructuring pattern at the start if (this.check(tokenizer_1.TokenType.LEFT_BRACKET) || this.check(tokenizer_1.TokenType.LEFT_BRACE)) { // Use lookahead to check if this is likely a destructuring assignment const isLikelyDestructuring = this.isLikelyDestructuringPattern(); // console.log('At start of expressionStatement, token:', this.peek(), 'isLikelyDestructuring:', isLikelyDestructuring); if (isLikelyDestructuring) { const pattern = this.tryParseDestructuringPattern(); // console.log('Parsed pattern:', pattern); if (pattern) { // Check for confidence threshold (Option 1: [a, b] ~> 0.8 = array) let confidenceThreshold; if (this.match(tokenizer_1.TokenType.CONFIDENCE_ARROW)) { const threshold = this.expression(); if (threshold) { confidenceThreshold = threshold; } } if (this.match(tokenizer_1.TokenType.EQUAL)) { const value = this.expression(); this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.DestructuringAssignment(pattern, value, confidenceThreshold); } else { throw new ParseError("Expected '=' after destructuring pattern", this.peek(), this.sourceCode); } } } } const expr = this.expression(); // Check if this is an assignment or compound assignment if (expr instanceof ast_1.IdentifierExpression) { if (this.match(tokenizer_1.TokenType.EQUAL)) { const value = this.expression(); // Consume optional semicolon this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.AssignmentStatement(expr.name, value); } else if (this.match(tokenizer_1.TokenType.PLUS_EQUAL)) { // x += y becomes x = x + y const right = this.expression(); const value = new ast_1.BinaryExpression('+', expr, right); this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.AssignmentStatement(expr.name, value); } else if (this.match(tokenizer_1.TokenType.MINUS_EQUAL)) { // x -= y becomes x = x - y const right = this.expression(); const value = new ast_1.BinaryExpression('-', expr, right); this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.AssignmentStatement(expr.name, value); } else if (this.match(tokenizer_1.TokenType.STAR_EQUAL)) { // x *= y becomes x = x * y const right = this.expression(); const value = new ast_1.BinaryExpression('*', expr, right); this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.AssignmentStatement(expr.name, value); } else if (this.match(tokenizer_1.TokenType.SLASH_EQUAL)) { // x /= y becomes x = x / y const right = this.expression(); const value = new ast_1.BinaryExpression('/', expr, right); this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.AssignmentStatement(expr.name, value); } else if (this.match(tokenizer_1.TokenType.PERCENT_EQUAL)) { // x %= y becomes x = x % y const right = this.expression(); const value = new ast_1.BinaryExpression('%', expr, right); this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.AssignmentStatement(expr.name, value); } else if (this.match(tokenizer_1.TokenType.CONFIDENCE_PLUS_EQUAL)) { // x ~+= y becomes x = x ~+ y const right = this.expression(); const value = new ast_1.BinaryExpression('~+', expr, right); this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.AssignmentStatement(expr.name, value); } else if (this.match(tokenizer_1.TokenType.CONFIDENCE_MINUS_EQUAL)) { // x ~-= y becomes x = x ~- y const right = this.expression(); const value = new ast_1.BinaryExpression('~-', expr, right); this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.AssignmentStatement(expr.name, value); } else if (this.match(tokenizer_1.TokenType.CONFIDENCE_STAR_EQUAL)) { // x ~*= y becomes x = x ~* y const right = this.expression(); const value = new ast_1.BinaryExpression('~*', expr, right); this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.AssignmentStatement(expr.name, value); } else if (this.match(tokenizer_1.TokenType.CONFIDENCE_SLASH_EQUAL)) { // x ~/= y becomes x = x ~/ y const right = this.expression(); const value = new ast_1.BinaryExpression('~/', expr, right); this.match(tokenizer_1.TokenType.SEMICOLON); return new ast_1.AssignmentStatement(expr.name, value); } } // Consume optional semicolon this.match(tokenizer_1.TokenType.SEMICOLON); // Wrap expression in an ExpressionStatement return new ast_1.ExpressionStatement(expr); } forStatement() { // for statement can be either: // 1. C-style: for i = 0; i < 10; i++ { ... } // 2. For-in: for item in array { ... } // 3. For-in with index: for item, index in array { ... } // Check if this is a for-in loop by looking ahead const checkPoint = this.current; // Try to parse as for-in first if (this.check(tokenizer_1.TokenType.IDENTIFIER)) { this.advance(); if (this.check(tokenizer_1.TokenType.COMMA)) { // for item, index in array this.advance(); // consume comma if (this.check(tokenizer_1.TokenType.IDENTIFIER)) { this.advance(); if (this.check(tokenizer_1.TokenType.IN)) { // Reset and parse as for-in with index this.current = checkPoint; return this.forInStatement(); } } } else if (this.check(tokenizer_1.TokenType.IN)) { // for item in array this.current = checkPoint; return this.forInStatement(); } } // Reset position and parse as C-style for loop this.current = checkPoint; // C-style for loop: for init; condition; update { body } let init = null; let condition = null; let update = null; // Parse init if (!this.check(tokenizer_1.TokenType.SEMICOLON)) { if (this.check(tokenizer_1.TokenType.IDENTIFIER) && this.peekNext().type === tokenizer_1.TokenType.EQUAL) { // Variable assignment const identifier = this.advance().value; this.consume(tokenizer_1.TokenType.EQUAL, "Expected '=' in assignment"); const value = this.expression(); if (!value) { throw new ParseError("Expected expression after '='", this.previous(), this.sourceCode); } init = new ast_1.AssignmentStatement(identifier, value); } else { // Expression const expr = this.expression(); if (expr) { init = new ast_1.ExpressionStatement(expr); } } } if (!this.match(tokenizer_1.TokenType.SEMICOLON)) { throw new ParseError("Expected ';' after for loop initializer", this.peek(), this.sourceCode); } // Parse condition if (!this.check(tokenizer_1.TokenType.SEMICOLON)) { condition = this.expression(); } if (!this.match(tokenizer_1.TokenType.SEMICOLON)) { throw new ParseError("Expected ';' after for loop condition", this.peek(), this.sourceCode); } // Parse update if (!this.check(tokenizer_1.TokenType.LEFT_BRACE)) { // Check if this is an assignment if (this.check(tokenizer_1.TokenType.IDENTIFIER)) { const checkPoint = this.current; const identifier = this.advance(); if (this.match(tokenizer_1.TokenType.EQUAL)) { // It's an assignment expression const value = this.expression(); if (!value) { throw new ParseError("Expected expression after '='", this.previous(), this.sourceCode); } update = new ast_1.AssignmentExpression(identifier.value, value); } else { // Not an assignment, reset and parse as regular expression this.current = checkPoint; update = this.expression(); } } else { update = this.expression(); } } // Parse body const body = this.statement(); if (!body) { throw new ParseError("Expected body for for loop", this.peek(), this.sourceCode); } return new ast_1.ForLoop(init, condition, update, body); } forInStatement() { // Parse variable name if (!this.check(tokenizer_1.TokenType.IDENTIFIER)) { throw new ParseError("Expected identifier in for-in loop", this.peek(), this.sourceCode); } const variable = this.advance().value; // Check for optional index variable let index = null; if (this.match(tokenizer_1.TokenType.COMMA)) { if (!this.check(tokenizer_1.TokenType.IDENTIFIER)) { throw new ParseError("Expected identifier after comma in for-in loop", this.peek(), this.sourceCode); } index = this.advance().value; } // Expect 'in' if (!this.match(tokenizer_1.TokenType.IN)) { throw new ParseError("Expected 'in' in for-in loop", this.peek(), this.sourceCode); } // Parse iterable expression const iterable = this.expression(); if (!iterable) { throw new ParseError("Expected expression after 'in'", this.peek(), this.sourceCode); } // Parse body const body = this.statement(); if (!body) { throw new ParseError("Expected body for for-in loop", this.peek(), this.sourceCode); } return new ast_1.ForInLoop(variable, index, iterable, body); } whileStatement() { // Parse condition const condition = this.expression(); if (!condition) { throw new ParseError("Expected condition in while loop", this.peek(), this.sourceCode); } // Parse body const body = this.statement(); if (!body) { throw new ParseError("Expected body for while loop", this.peek(), this.sourceCode); } return new ast_1.WhileLoop(condition, body); } doWhileStatement() { // Parse body const body = this.statement(); if (!body) { throw new ParseError("Expected body for do-while loop", this.peek(), this.sourceCode); } // Expect 'while' if (!this.match(tokenizer_1.TokenType.WHILE)) { throw new ParseError("Expected 'while' after do-while body", this.peek(), this.sourceCode); } // Parse condition const condition = this.expression(); if (!condition) { throw new ParseError("Expected condition in do-while loop", this.peek(), this.sourceCode); } return new ast_1.DoWhileLoop(body, condition); } breakStatement() { return new ast_1.BreakStatement(); } continueStatement() { return new ast_1.ContinueStatement(); } uncertainForStatement() { this.consume(tokenizer_1.TokenType.FOR, "Expected 'for' after 'uncertain'"); // Parse init, condition, update like regular for loop let init = null; let condition = null; let update = null; // Parse init if (!this.check(tokenizer_1.TokenType.SEMICOLON)) { if (this.check(tokenizer_1.TokenType.IDENTIFIER) && this.peekNext().type === tokenizer_1.TokenType.EQUAL) { const identifier = this.advance().value; this.consume(tokenizer_1.TokenType.EQUAL, "Expected '=' in assignment"); const value = this.expression(); if (!value) { throw new ParseError("Expected expression after '='", this.previous(), this.sourceCode); } init = new ast_1.AssignmentStatement(identifier, value); } else { const expr = this.expression(); if (expr) { init = new ast_1.ExpressionStatement(expr); } } } if (!this.match(tokenizer_1.TokenType.SEMICOLON)) { throw new ParseError("Expected ';' after for loop initializer", this.peek(), this.sourceCode); } // Parse condition if (!this.check(tokenizer_1.TokenType.SEMICOLON)) { condition = this.expression(); } if (!this.match(tokenizer_1.TokenType.SEMICOLON)) { throw new ParseError("Expected ';' after for loop condition", this.peek(), this.sourceCode); } // Parse update if (!this.check(tokenizer_1.TokenType.LEFT_BRACE)) { if (this.check(tokenizer_1.TokenType.IDENTIFIER)) { const checkPoint = this.current; const identifier = this.advance(); if (this.match(tokenizer_1.TokenType.EQUAL)) { const value = this.expression(); if (!value) { throw new ParseError("Expected expression after '='", this.previous(), this.sourceCode); } update = new ast_1.AssignmentExpression(identifier.value, value); } else { this.current = checkPoint; update = this.expression(); } } else { update = this.expression(); } } // Parse uncertain branches this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after uncertain for loop header"); const branches = this.parseUncertainBranches(); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after uncertain for branches"); return new ast_1.UncertainForLoop(init, condition, update, branches); } uncertainWhileStatement() { this.consume(tokenizer_1.TokenType.WHILE, "Expected 'while' after 'uncertain'"); // Parse condition - must be a confident expression const condition = this.expression(); if (!condition) { throw new ParseError("Expected condition in uncertain while loop", this.peek(), this.sourceCode); } // Parse uncertain branches this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after uncertain while condition"); const branches = this.parseUncertainBranches(); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after uncertain while branches"); return new ast_1.UncertainWhileLoop(condition, branches); } parseUncertainBranches() { const branches = {}; while (!this.check(tokenizer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) { if (this.match(tokenizer_1.TokenType.HIGH)) { if (branches.high) { throw new ParseError("Duplicate 'high' branch in uncertain statement", this.previous(), this.sourceCode); } this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after 'high'"); const statements = this.blockContents(); branches.high = new ast_1.BlockStatement(statements); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after high branch"); } else if (this.match(tokenizer_1.TokenType.MEDIUM)) { if (branches.medium) { throw new ParseError("Duplicate 'medium' branch in uncertain statement", this.previous(), this.sourceCode); } this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after 'medium'"); const statements = this.blockContents(); branches.medium = new ast_1.BlockStatement(statements); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after medium branch"); } else if (this.match(tokenizer_1.TokenType.LOW)) { if (branches.low) { throw new ParseError("Duplicate 'low' branch in uncertain statement", this.previous(), this.sourceCode); } this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after 'low'"); const statements = this.blockContents(); branches.low = new ast_1.BlockStatement(statements); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after low branch"); } else if (this.match(tokenizer_1.TokenType.DEFAULT)) { if (branches.default) { throw new ParseError("Duplicate 'default' branch in uncertain statement", this.previous(), this.sourceCode); } this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' after 'default'"); const statements = this.blockContents(); branches.default = new ast_1.BlockStatement(statements); this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after default branch"); } else { throw new ParseError("Expected 'high', 'medium', 'low', or 'default' branch in uncertain statement", this.peek(), this.sourceCode); } } return branches; } importStatement() { const specifiers = []; let defaultImport; let namespaceImport; let source; // Check for namespace import: import * as name from "module" if (this.match(tokenizer_1.TokenType.STAR)) { this.consume(tokenizer_1.TokenType.AS, "Expected 'as' after '*'"); namespaceImport = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected namespace name after 'as'").value; } // Check for named imports: import {name1, name2} from "module" else if (this.check(tokenizer_1.TokenType.LEFT_BRACE)) { this.advance(); // consume { while (!this.check(tokenizer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) { const imported = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected import name").value; let local = imported; // Default to same name // Check for renaming: import {original as renamed} if (this.match(tokenizer_1.TokenType.AS)) { local = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected local name after 'as'").value; } specifiers.push(new ast_1.ImportSpecifier(imported, local !== imported ? local : undefined)); if (this.match(tokenizer_1.TokenType.COMMA)) { // Allow trailing comma if (this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { break; } } else if (!this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { throw new ParseError("Expected ',' or '}' after import specifier", this.peek(), this.sourceCode); } } this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after import specifiers"); } // Check for default import: import defaultName from "module" else if (this.check(tokenizer_1.TokenType.IDENTIFIER)) { defaultImport = this.advance().value; // Check for mixed import: import defaultName, {named} from "module" if (this.match(tokenizer_1.TokenType.COMMA)) { if (this.match(tokenizer_1.TokenType.LEFT_BRACE)) { while (!this.check(tokenizer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) { const imported = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected import name").value; let local = imported; if (this.match(tokenizer_1.TokenType.AS)) { local = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected local name after 'as'").value; } specifiers.push(new ast_1.ImportSpecifier(imported, local !== imported ? local : undefined)); if (this.match(tokenizer_1.TokenType.COMMA)) { if (this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { break; } } else if (!this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { throw new ParseError("Expected ',' or '}' after import specifier", this.peek(), this.sourceCode); } } this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after import specifiers"); } } } else { // No valid import pattern found - this is an error throw new ParseError("Expected import specifier", this.peek(), this.sourceCode); } // Expect 'from' keyword this.consume(tokenizer_1.TokenType.FROM, "Expected 'from' after import specifiers"); // Parse module source source = this.consume(tokenizer_1.TokenType.STRING, "Expected module path after 'from'").value; this.match(tokenizer_1.TokenType.SEMICOLON); // Optional semicolon return new ast_1.ImportStatement(specifiers, source, defaultImport, namespaceImport); } exportStatement() { // Check for different export patterns // export default expression if (this.match(tokenizer_1.TokenType.DEFAULT)) { const declaration = this.expressionStatement(); return new ast_1.ExportStatement(undefined, undefined, declaration, true); } // export * from "module" if (this.match(tokenizer_1.TokenType.STAR)) { this.consume(tokenizer_1.TokenType.FROM, "Expected 'from' after 'export *'"); const source = this.consume(tokenizer_1.TokenType.STRING, "Expected module path after 'from'").value; this.match(tokenizer_1.TokenType.SEMICOLON); // Optional semicolon return new ast_1.ExportStatement(undefined, source, undefined, false, true); } // export {name1, name2} or export {name1, name2} from "module" if (this.match(tokenizer_1.TokenType.LEFT_BRACE)) { const specifiers = []; while (!this.check(tokenizer_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) { const local = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected export name").value; let exported = local; // Default to same name // Check for renaming: export {original as renamed} if (this.match(tokenizer_1.TokenType.AS)) { exported = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected exported name after 'as'").value; } specifiers.push(new ast_1.ExportSpecifier(local, exported !== local ? exported : undefined)); if (this.match(tokenizer_1.TokenType.COMMA)) { // Allow trailing comma if (this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { break; } } else if (!this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { throw new ParseError("Expected ',' or '}' after export specifier", this.peek(), this.sourceCode); } } this.consume(tokenizer_1.TokenType.RIGHT_BRACE, "Expected '}' after export specifiers"); // Check for re-export: export {names} from "module" let source; if (this.match(tokenizer_1.TokenType.FROM)) { source = this.consume(tokenizer_1.TokenType.STRING, "Expected module path after 'from'").value; } this.match(tokenizer_1.TokenType.SEMICOLON); // Optional semicolon return new ast_1.ExportStatement(specifiers, source); } // export statement (direct export) const declaration = this.statement(); if (!declaration) { throw new ParseError("Expected declaration after 'export'", this.peek(), this.sourceCode); } return new ast_1.ExportStatement(undefined, undefined, declaration); } functionDeclaration(isAsync = false) { // Parse function name const name = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected function name").value; // Parse parameters this.consume(tokenizer_1.TokenType.LEFT_PAREN, "Expected '(' after function name"); const parameters = []; let restParameter = undefined; if (!this.check(tokenizer_1.TokenType.RIGHT_PAREN)) { do { if (this.match(tokenizer_1.TokenType.SPREAD)) { // Rest parameter if (this.check(tokenizer_1.TokenType.IDENTIFIER)) { restParameter = this.advance().value; } else if (this.check(tokenizer_1.TokenType.LEFT_BRACKET) || this.check(tokenizer_1.TokenType.LEFT_BRACE)) { // Rest with destructuring pattern const pattern = this.tryParseDestructuringPattern(); if (!pattern) { throw new ParseError("Expected parameter pattern after '...'", this.peek(), this.sourceCode); } restParameter = pattern; } else { throw new ParseError("Expected parameter name or pattern after '...'", this.peek(), this.sourceCode); } // Rest parameter must be last if (this.match(tokenizer_1.TokenType.COMMA)) { throw new ParseError("Rest parameter must be last formal parameter", this.previous(), this.sourceCode); } } else if (this.match(tokenizer_1.TokenType.IDENTIFIER)) { if (restParameter) { throw new ParseError("Rest parameter must be last formal parameter", this.previous(), this.sourceCode); } parameters.push(this.previous().value); } else if (this.check(tokenizer_1.TokenType.LEFT_BRACKET) || this.check(tokenizer_1.TokenType.LEFT_BRACE)) { // Destructuring pattern parameter if (restParameter) { throw new ParseError("Rest parameter must be last formal parameter", this.previous(), this.sourceCode); } const pattern = this.tryParseDestructuringPattern(); if (!pattern) { throw new ParseError("Expected parameter pattern", this.peek(), this.sourceCode); } parameters.push(pattern); } else { throw new ParseError("Expected parameter name or pattern", this.peek(), this.sourceCode); } } while (this.match(tokenizer_1.TokenType.COMMA)); } this.consume(tokenizer_1.TokenType.RIGHT_PAREN, "Expected ')' after parameters"); // Parse optional confidence annotation let confidenceAnnotation; if (this.match(tokenizer_1.TokenType.CONFIDENCE_ARROW)) { const confExpr = this.expression(); if (!confExpr) { throw new ParseError("Expected confidence expression after '~>'", this.previous(), this.sourceCode); } confidenceAnnotation = confExpr; } // Parse function body (must be a block) this.consume(tokenizer_1.TokenType.LEFT_BRACE, "Expected '{' before function body"); const body = this.blockStatement(); return new ast_1.FunctionDeclaration(name, parameters, body, restParameter, confidenceAnnotation, isAsync); } returnStatement() { let value; // Check if there's a return value (not followed by semicolon or EOF) if (!this.check(tokenizer_1.TokenType.SEMICOLON) && !this.isAtEnd() && !this.check(tokenizer_1.TokenType.RIGHT_BRACE)) { value = this.expression() || undefined; } this.match(tokenizer_1.TokenType.SEMICOLON); // Optional semicolon return new ast_1.ReturnStatement(value); } variableDeclaration() { // Get the declaration kind (const or let) const kind = this.previous().value; // Check for destructuring pattern if (this.check(tokenizer_1.TokenType.LEFT_BRACKET) || this.check(tokenizer_1.TokenType.LEFT_BRACE)) { const pattern = this.tryParseDestructuringPattern(); if (pattern) { // Pattern destructuring: const [a, b] = array or const {x, y} = obj this.consume(tokenizer_1.TokenType.EQUAL, "Expected '=' after destructuring pattern"); const initializer = this.expression(); if (!initializer) { throw new ParseError("Expected expression after '='", this.peek(), this.sourceCode); } this.match(tokenizer_1.TokenType.SEMICOLON); // Optional semicolon return new ast_1.VariableDeclaration(kind, '', initializer, pattern); } } // Regular variable declaration: const/let name = value const identifier = this.consume(tokenizer_1.TokenType.IDENTIFIER, "Expected variable name").value; // const requires an initializer, let allows optional initializer let initializer; if (this.match(tokenizer_1.TokenType.EQUAL)) { const expr = this.expression(); if (!expr) { throw new ParseError("Expected expression after '='", this.previous(), this.sourceCode); } initializer = expr; } else if (kind === 'const') { throw new ParseError("const declarations must have an initializer", this.peek(), this.sourceCode); } this.match(tokenizer_1.TokenType.SEMICOLON); // Optional semicolon return new ast_1.VariableDeclaration(kind, identifier, initializer); } expression() { return this.pipeline(); } pipeline() { let expr = this.ternary(); while (this.match(tokenizer_1.TokenType.PIPELINE, tokenizer_1.TokenType.CONFIDENCE_PIPELINE, tokenizer_1.TokenType.CONFIDENCE_THRESHOLD_GATE)) { const operator = this.previous(); if (operator.type === tokenizer_1.TokenType.CONFIDENCE_THRESHOLD_GATE) { // Handle threshold gate operator ~?> const threshold = this.ternary(); if (!threshold) { throw new ParseError("Expected threshold expression after '~?>'", this.previous(), this.sourceCode); } // Create threshold gate expression expr = new ast_1.BinaryExpression('~?>', expr, threshold); } else { // Handle regular and confidence pipeline operators const isConfidencePipeline = operator.type === tokenizer_1.TokenType.CONFIDENCE_PIPELINE; const right = this.ternary(); if (!right) { throw new ParseError("Expected expression after pipeline op