Parser API
The Parser API provides a comprehensive parser for the Prism language, transforming source code into an Abstract Syntax Tree (AST) that can be executed by the runtime.
Overview
The parser handles:
- Tokenization of source code
- Parsing of all Prism language constructs
- Error handling with detailed error messages
- Support for confidence expressions and uncertain control flow
- Pipeline operators and placeholders
- Destructuring patterns with confidence thresholds
Parser Class
Constructor
class Parser {
constructor(tokens: Token[], sourceCode?: string)
}
Parameters:
tokens: Array of tokens from the tokenizersourceCode: Optional source code for enhanced error messages
Methods
parse()
parse(): Program
Parses the tokens into a complete program AST.
Returns: A Program node containing all parsed statements
Example:
import { tokenize, Parser } from '@prism-lang/core';
const source = `
x = 42;
if (x > 40) {
console.log("Large number");
}
`;
const tokens = tokenize(source);
const parser = new Parser(tokens, source);
const ast = parser.parse();
parse() Function
export function parse(source: string): Program
Convenience function that handles tokenization and parsing in one step.
Parameters:
source: The source code string to parse
Returns: A Program AST node
Example:
import { parse } from '@prism-lang/core';
const ast = parse('x = 10 ~> 0.9;');
Error Handling
ParseError
class ParseError extends Error {
constructor(message: string, token: Token, sourceCode?: string)
token: Token
sourceCode?: string
}
Thrown when the parser encounters invalid syntax.
Properties:
message: Detailed error message with locationtoken: The token where the error occurredsourceCode: The original source code (if provided)
Error Format:
ParseError at line 2, column 5: Expected ')' after expression
2 | if (x > 10
^
Found: '{' (LEFT_BRACE)
Supported Language Features
Expressions
Literals
- Numbers:
42,3.14 - Strings:
"hello",'world' - Interpolated strings:
`Hello ${name}` - Booleans:
true,false - Null:
null - Undefined:
undefined
Operators
- Arithmetic:
+,-,*,/,%,** - Comparison:
>,<,>=,<=,==,!= - Logical:
&&,||,! - Confidence operators:
~>,~~,~&&,~|| - Pipeline:
|>,~|>,~?> - Nullish coalescing:
?? - Confidence coalescing:
~??
Complex Expressions
- Arrays:
[1, 2, 3],[...arr, 4] - Objects:
{x: 10, y: 20},{...obj, z: 30} - Property access:
obj.prop,obj?.prop,obj~.prop - Index access:
arr[0] - Function calls:
fn(arg1, arg2) - Lambda expressions:
x => x * 2,(x, y) => x + y - Ternary:
condition ? true : false - Placeholders:
_(for use in pipelines)
Statements
Variable Assignment
x = 42;
y = "hello" ~> 0.9; // with confidence
Compound Assignment
x += 5; // x = x + 5
y *= 2; // y = y * 2
Control Flow
// Regular if
if (condition) {
// statements
} else {
// statements
}
// Uncertain if
uncertain if (condition ~> 0.8) {
high {
// high confidence branch
}
medium {
// medium confidence branch
}
low {
// low confidence branch
}
}
Loops
// C-style for loop
for i = 0; i < 10; i++ {
// statements
}
// For-in loop
for item in array {
// statements
}
// For-in with index
for item, index in array {
// statements
}
// While loop
while condition {
// statements
}
// Do-while loop
do {
// statements
} while condition;
// Uncertain loops
uncertain for i = 0; i < 10; i++ {
high { /* high confidence */ }
low { /* low confidence */ }
}
uncertain while condition {
high { /* high confidence */ }
low { /* low confidence */ }
}
Loop Control
break; // Exit loop
continue; // Skip to next iteration
Context Management
in context "user_input" {
// statements
}
in context "analysis" {
// statements
} shifting to "report" {
// statements
}
Agent Declarations
agents {
assistant: Agent {
confidence: 0.9,
role: "helpful assistant"
}
}
Destructuring
Array Destructuring
[a, b, c] = array;
[first, ...rest] = array;
[a, , c] = array; // Skip element
// With confidence thresholds
[a, b] ~> 0.8 = array;
[a ~> 0.9, b ~> 0.7] = array;
Object Destructuring
{x, y} = point;
{name: userName, age} = user;
{a, ...rest} = obj;
// With confidence thresholds
{x, y} ~> 0.8 = point;
{x ~> 0.9, y ~> 0.7} = point;
// With default values
{x = 0, y = 0} = point;
Nested Destructuring
[{x, y}, [a, b]] = data;
{user: {name, age}} = response;
Pipeline Operations
// Regular pipeline
value |> transform(_) |> format(_);
// Confidence pipeline (preserves confidence)
value ~|> transform(_) ~|> format(_);
// Threshold gate
value ~?> 0.8; // Pass through only if confidence >= 0.8
AST Node Types
The parser generates various AST node types. Each node extends the base ASTNode class:
abstract class ASTNode {
abstract type: NodeType;
location?: { line: number; column: number };
setLocation(line: number, column: number): this;
}
Common Properties
type: The node type identifierlocation: Optional source location information
Expression Nodes
IdentifierExpression: Variable referencesNumberLiteral,StringLiteral,BooleanLiteral: Literal valuesInterpolatedString: Template strings with expressionsArrayLiteral,ObjectLiteral: Collection literalsBinaryExpression: Binary operationsUnaryExpression: Unary operationsCallExpression: Function callsConfidenceExpression: Expression with confidence valueLambdaExpression: Arrow functions
Statement Nodes
Program: Root node containing all statementsAssignmentStatement: Variable assignmentsIfStatement,UncertainIfStatement: Conditional executionForLoop,ForInLoop,WhileLoop: Loop constructsContextStatement: Context managementBlockStatement: Statement blocksExpressionStatement: Expression as statement
Best Practices
-
Error Recovery: The parser includes synchronization points to recover from errors and continue parsing
-
Source Code Tracking: Always provide source code to the parser for better error messages
-
Location Information: AST nodes include location information for debugging and error reporting
-
Validation: The parser performs syntactic validation but not semantic validation (that's done by the runtime)
Example: Custom AST Traversal
import { parse, ASTNode, IdentifierExpression } from '@prism-lang/core';
function findIdentifiers(node: ASTNode): string[] {
const identifiers: string[] = [];
function traverse(n: ASTNode) {
if (n instanceof IdentifierExpression) {
identifiers.push(n.name);
}
// Traverse child nodes based on type
// (implementation depends on node type)
}
traverse(node);
return identifiers;
}
const ast = parse('x = y + z;');
const vars = findIdentifiers(ast);
console.log(vars); // ['x', 'y', 'z']