import { Expr } from "./ast"; export interface ParserOptions { maxDepth?: number; } export declare class Parser { private lexer; private currentToken; private depth; private maxDepth; private disableRangeMembershipIn; constructor(input: string, options?: ParserOptions); private checkDepth; private saveState; private restoreState; private formatLocation; private eat; private primary; private postfix; private unary; private power; private factor; private term; private addition; private comparison; private equality; private logical_and; /** * Parse alternative expressions: a | b | c * Returns first non-null value, left-to-right evaluation. */ private alternative; private logical_or; /** * Parse pipe expressions: a |> f(b) |> g(c) or a |> f |> g * Desugars to: g(f(a, b), c) or g(f(a)) * Left-associative, lowest precedence (below logical_or) * Parentheses are optional: a |> f is equivalent to a |> f() */ private pipe; /** * Try to parse range membership: expr in expr..expr or expr in expr...expr * Also handles: expr not in expr..expr (when negated is true) * Returns null if this is not a range expression (e.g., it's 'in' from 'let...in') */ private tryParseRangeMembership; /** * Desugar range membership expression. * `value in start..end` becomes `value >= start and value <= end` * `value in start...end` becomes `value >= start and value < end` * * For complex expressions, wraps in let to avoid multiple evaluation. */ private desugarRangeMembership; /** * Trailing commas are allowed: let x=2, y=3, in x*y */ private letExpr; /** * Parse a type definition: let Person = { name: String, age: Int } in body * Called after 'let' when we see an UPPER_IDENTIFIER * Supports multiple bindings: let Person = {...}, Persons = [Person] in body * Trailing commas are allowed: let Person = {...}, in body */ private typeDefExpr; /** * Parse remaining let bindings after a comma (when mixing type and value bindings) * Returns a LetExpr with the remaining bindings * Trailing commas are allowed */ private parseLetBindingsAfterComma; /** * Parse a type expression: String, Int|String, Int(i | i > 0), [Int], { prop: TypeExpr, ... } * Handles union types: Int|String|Bool */ private typeExpr; /** * Parse a primary type expression (without union) */ private typeExprPrimary; /** * Parse a subtype constraint: Int(i | i > 0) or Int(i | positive: i > 0, even: i % 2 == 0) * Called after the base type has been parsed, when we see '(' * Supports: * - Single constraint: Int(i | i > 0) * - Labeled constraint: Int(i | positive: i > 0) * - Multiple constraints: Int(i | positive: i > 0, even: i % 2 == 0) * - String labels: Int(i | 'must be positive': i > 0) * - Trailing commas are allowed: Int(i | i > 0,) */ private subtypeConstraintExpr; /** * Parse a single constraint with optional label * Formats: * - condition (no label) * - identifier: condition * - 'string message': condition */ private parseConstraint; /** * Parse a type schema: { name: String, age: Int, nickname :? String, ... } or { name: String, ...: Int } * Trailing commas are allowed: { name: String, age: Int, } * extras: * - { x: Int } - closed, no extra attrs allowed * - { x: Int, ... } - ignored, extra attrs allowed but not included * - { x: Int, ...: String } - typed, extra attrs must match type */ private typeSchemaExpr; private ifExprParse; /** * Try to parse pipe-style guard: guard(x | condition, ...) * Returns a lambda that checks constraints and returns the input value. * Returns null if not a pipe-style guard (e.g., regular function call). * Called from lowercase identifier parsing (when guard/check used as function name). */ private tryParsePipeGuard; /** * Try to parse pipe-style guard body after LPAREN has been seen. * Called from GUARD/CHECK keyword parsing. * Returns null if not a valid pipe-style guard pattern. */ private tryParsePipeGuardBody; /** * Parse the body of a pipe-style guard after LPAREN has been consumed. * Returns null if not a valid pattern, restoring the saved state. * Trailing commas are allowed: guard(i | i>0, i<0,) */ private parsePipeGuardBody; /** * Parse guard/check expression: guard [label:] condition[, ...] in body * Supports the guard...let...check...in sugar pattern * Trailing commas are allowed: guard age > 0, length(name) > 0, in age */ private guardExprParse; /** * Parse lambda expression: fn( ~> body ) or fn( x ~> body ) or fn( x, y ~> body ) */ private lambdaParse; /** * Parse object literal: {key: value, key2: value2, ...} * Trailing commas are allowed: {a: 1, b: 2,} */ private objectParse; /** * Parse array literal: [expr, expr, ...] * Trailing commas are allowed: [1, 2, 3,] */ private arrayParse; /** * Parse datapath literal: .x.y.z or .items.0.name * Grammar: '.' pathSegment ('.' pathSegment)* * pathSegment: IDENTIFIER | NUMBER * * Note: The lexer may tokenize "0.1" as a single NUMBER token when parsing * consecutive numeric segments. We handle this by splitting such tokens. * The lexer also treats ".0" as a NUMBER token (decimal number starting with dot). */ private datapathParse; /** * Parse additional path segments after the first one */ private parseAdditionalPathSegments; /** * Check if current token is a NUMBER that starts with a dot (e.g., ".0") * This happens when the lexer treats ".0" as a decimal number */ private isDecimalNumberToken; /** * Parse path segments from a NUMBER token. * A NUMBER token like "0.1" in datapath context should become segments [0, 1]. * Returns the array of integer segments, or null if not a valid NUMBER. */ private parseNumericPathSegments; /** * Parse a single path segment: IDENTIFIER or integer NUMBER * Returns null if current token is not a valid segment. */ private parsePathSegment; private expr; /** * Parse guard/check: detect if it's pipe-style guard(x | cond) or block-style guard cond in body */ private guardOrPipeGuard; parse(): Expr; /** * Parse an expression in a context where `in` is a delimiter token (e.g. plugin-program * bindings), not a range-membership operator. */ parseExprWithInDisabled(): Expr; } /** * Parse an arithmetic expression string into an AST */ export declare function parse(input: string, options?: ParserOptions): Expr; /** * Minimal v1 plugin-program parser. * * Grammar: * program := (round)* score * round := ('plan'|'then') bindingList 'in' * bindingList := binding (',' binding)* [','] * binding := IDENTIFIER '=' expr * score := expr */ export type PluginProgram = { rounds: Array<{ kind: "plan" | "then"; bindings: Array<{ name: string; value: Expr; }>; }>; score: Expr; }; export declare function parsePluginProgram(input: string, options?: ParserOptions): PluginProgram; //# sourceMappingURL=parser.d.ts.map