littlewing 0.5.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  declare namespace exports_ast {
2
- export { unaryOp, subtract, number, nullishAssign, notEquals, negate, multiply, modulo, logicalOr, logicalAnd, lessThan, lessEqual, identifier, greaterThan, greaterEqual, functionCall, exponentiate, equals, divide, conditional, binaryOp, assign, add };
2
+ export { unaryOp, subtract, program, number, notEquals, negate, multiply, modulo, logicalOr, logicalAnd, lessThan, lessEqual, identifier, greaterThan, greaterEqual, functionCall, exponentiate, equals, divide, conditional, binaryOp, assign, add };
3
3
  }
4
4
  /**
5
5
  * Runtime value type - only numbers
@@ -44,7 +44,6 @@ declare enum TokenType {
44
44
  COMMA = "COMMA",
45
45
  QUESTION = "QUESTION",
46
46
  COLON = "COLON",
47
- NULLISH_ASSIGN = "NULLISH_ASSIGN",
48
47
  EOF = "EOF"
49
48
  }
50
49
  /**
@@ -58,7 +57,7 @@ interface Token {
58
57
  /**
59
58
  * AST Node - base type
60
59
  */
61
- type ASTNode = Program | NumberLiteral | Identifier | BinaryOp | UnaryOp | FunctionCall | Assignment | ConditionalExpression | NullishAssignment;
60
+ type ASTNode = Program | NumberLiteral | Identifier | BinaryOp | UnaryOp | FunctionCall | Assignment | ConditionalExpression;
62
61
  /**
63
62
  * Program node (multiple statements)
64
63
  */
@@ -124,16 +123,6 @@ interface ConditionalExpression {
124
123
  alternate: ASTNode;
125
124
  }
126
125
  /**
127
- * Nullish assignment (x ??= 5)
128
- * Assigns value only if variable is undefined (not provided in context)
129
- * Used for providing defaults for external variables
130
- */
131
- interface NullishAssignment {
132
- type: "NullishAssignment";
133
- name: string;
134
- value: ASTNode;
135
- }
136
- /**
137
126
  * Type guard functions for discriminated union narrowing
138
127
  */
139
128
  declare function isNumberLiteral(node: ASTNode): node is NumberLiteral;
@@ -144,11 +133,14 @@ declare function isFunctionCall(node: ASTNode): node is FunctionCall;
144
133
  declare function isAssignment(node: ASTNode): node is Assignment;
145
134
  declare function isProgram(node: ASTNode): node is Program;
146
135
  declare function isConditionalExpression(node: ASTNode): node is ConditionalExpression;
147
- declare function isNullishAssignment(node: ASTNode): node is NullishAssignment;
148
136
  /**
149
137
  * Builder functions for creating AST nodes manually
150
138
  */
151
139
  /**
140
+ * Create a program node
141
+ */
142
+ declare function program(statements: ASTNode[]): Program;
143
+ /**
152
144
  * Create a number literal node
153
145
  */
154
146
  declare function number(value: number): NumberLiteral;
@@ -173,11 +165,6 @@ declare function functionCall(name: string, args?: ASTNode[]): FunctionCall;
173
165
  */
174
166
  declare function assign(name: string, value: ASTNode): Assignment;
175
167
  /**
176
- * Create a nullish assignment node (x ??= 5)
177
- * Assigns only if variable is undefined
178
- */
179
- declare function nullishAssign(name: string, value: ASTNode): NullishAssignment;
180
- /**
181
168
  * Create a conditional expression node (ternary operator)
182
169
  */
183
170
  declare function conditional(condition: ASTNode, consequent: ASTNode, alternate: ASTNode): ConditionalExpression;
@@ -287,10 +274,6 @@ declare class CodeGenerator {
287
274
  */
288
275
  private generateAssignment;
289
276
  /**
290
- * Generate code for a nullish assignment
291
- */
292
- private generateNullishAssignment;
293
- /**
294
277
  * Generate code for a conditional expression (ternary operator)
295
278
  */
296
279
  private generateConditionalExpression;
@@ -337,10 +320,12 @@ declare function generate(node: ASTNode): string;
337
320
  declare const defaultContext: ExecutionContext;
338
321
  /**
339
322
  * Executor - evaluates an AST with given context
323
+ * Uses a tree-walk interpreter with O(n) execution time where n is the number of AST nodes
340
324
  */
341
325
  declare class Executor {
342
326
  private context;
343
327
  private variables;
328
+ private externalVariables;
344
329
  constructor(context?: ExecutionContext);
345
330
  /**
346
331
  * Execute an AST node and return the result
@@ -372,15 +357,11 @@ declare class Executor {
372
357
  private executeFunctionCall;
373
358
  /**
374
359
  * Execute a variable assignment
360
+ * External variables (from context) take precedence over script assignments
361
+ * This allows scripts to define defaults that can be overridden at runtime
375
362
  */
376
363
  private executeAssignment;
377
364
  /**
378
- * Execute a nullish assignment (??=)
379
- * Only assigns if the variable is undefined (not in variables map)
380
- * Returns the existing value if defined, otherwise evaluates and assigns the value
381
- */
382
- private executeNullishAssignment;
383
- /**
384
365
  * Execute a conditional expression (ternary operator)
385
366
  * Returns consequent if condition !== 0, otherwise returns alternate
386
367
  */
@@ -392,10 +373,12 @@ declare class Executor {
392
373
  declare function execute(source: string, context?: ExecutionContext): RuntimeValue;
393
374
  /**
394
375
  * Lexer - converts source code into tokens
376
+ * Implements a single-pass O(n) tokenization algorithm
395
377
  */
396
378
  declare class Lexer {
397
379
  private source;
398
380
  private position;
381
+ private length;
399
382
  constructor(source: string);
400
383
  /**
401
384
  * Tokenize the entire source and return all tokens
@@ -411,7 +394,7 @@ declare class Lexer {
411
394
  private skipWhitespaceAndComments;
412
395
  /**
413
396
  * Read a number token
414
- * Supports: integers (42), decimals (3.14), and scientific notation (1.5e6, 2e-3)
397
+ * Supports: integers (42), decimals (3.14), decimal shorthand (.2), and scientific notation (1.5e6, 2e-3, .5e2)
415
398
  */
416
399
  private readNumber;
417
400
  /**
@@ -419,23 +402,11 @@ declare class Lexer {
419
402
  */
420
403
  private readIdentifier;
421
404
  /**
422
- * Get character at position
423
- */
424
- private getCharAt;
425
- /**
426
- * Peek at the next character without consuming it
427
- */
428
- private peek;
429
- /**
430
- * Peek ahead n positions without consuming
431
- */
432
- private peekAhead;
433
- /**
434
- * Check if character is a digit
405
+ * Check if character is a digit (0-9)
435
406
  */
436
407
  private isDigit;
437
408
  /**
438
- * Check if character is a letter
409
+ * Check if character is a letter (a-z, A-Z)
439
410
  */
440
411
  private isLetter;
441
412
  /**
@@ -444,25 +415,25 @@ declare class Lexer {
444
415
  private isWhitespace;
445
416
  }
446
417
  /**
447
- * Optimize an AST using a theoretically optimal O(n) algorithm.
418
+ * Optimize an AST using constant folding and expression simplification.
448
419
  *
449
- * This optimizer implements a single-pass data-flow analysis algorithm that:
450
- * 1. Builds a dependency graph of all variables and expressions
451
- * 2. Performs constant propagation via forward data-flow analysis
452
- * 3. Eliminates dead code via backward reachability analysis
453
- * 4. Evaluates expressions in a single topological pass
420
+ * This optimizer performs LOCAL, SAFE optimizations that preserve program semantics:
421
+ * - Constant folding: Evaluates arithmetic with literal operands at compile-time
422
+ * - Function argument pre-evaluation: Simplifies expressions passed to functions
423
+ * - Conditional folding: Evaluates ternary with constant condition
424
+ *
425
+ * Optimizations that are NOT performed (because they're unsafe with context variables):
426
+ * - Variable propagation: Variables can be overridden by ExecutionContext
427
+ * - Dead code elimination: Cannot determine if variables are "dead" without knowing context
428
+ * - Cross-statement analysis: Each statement may affect external state
454
429
  *
455
430
  * Time complexity: O(n) where n is the number of AST nodes
456
- * Space complexity: O(n) for the dependency graph
431
+ * Space complexity: O(d) where d is the max depth (recursion stack)
457
432
  *
458
433
  * Algorithm properties:
459
434
  * - Sound: Preserves program semantics exactly
460
- * - Complete: Finds all optimization opportunities
461
- * - Optimal: No redundant traversals or recomputation
462
- *
463
- * Based on classical compiler optimization theory:
464
- * - Cytron et al. "Efficiently Computing Static Single Assignment Form" (1991)
465
- * - Wegman & Zadeck "Constant Propagation with Conditional Branches" (1991)
435
+ * - Safe: No assumptions about variable values or liveness
436
+ * - Local: Only optimizes within individual expressions
466
437
  *
467
438
  * @param node - The AST node to optimize
468
439
  * @returns Optimized AST node
@@ -470,6 +441,7 @@ declare class Lexer {
470
441
  declare function optimize(node: ASTNode): ASTNode;
471
442
  /**
472
443
  * Parser using Pratt parsing (top-down operator precedence)
444
+ * Implements an efficient O(n) parsing algorithm
473
445
  */
474
446
  declare class Parser {
475
447
  private tokens;
@@ -477,11 +449,12 @@ declare class Parser {
477
449
  constructor(tokens: Token[]);
478
450
  /**
479
451
  * Parse tokens into an AST
480
- * Supports multiple statements separated by semicolons
452
+ * Supports multiple statements separated by semicolons or newlines
481
453
  */
482
454
  parse(): ASTNode;
483
455
  /**
484
456
  * Parse an expression with Pratt parsing (precedence climbing)
457
+ * This is the core of the parser - handles infix operators with proper precedence
485
458
  */
486
459
  private parseExpression;
487
460
  /**
@@ -496,15 +469,15 @@ declare class Parser {
496
469
  * Get unary operator precedence
497
470
  * Returns 6 which is higher than add/sub (6) but lower than exponentiation (8)
498
471
  * This means: -2^2 parses as -(2^2) = -4, not (-2)^2 = 4
499
- * This matches the behavior of Python, Ruby, and most languages
472
+ * Matches the behavior of Python, Ruby, and most languages
500
473
  */
501
474
  private getUnaryPrecedence;
502
475
  /**
503
- * Check if token is a binary operator
476
+ * Check if token is a binary operator (O(1) Set lookup)
504
477
  */
505
478
  private isBinaryOperator;
506
479
  /**
507
- * Get current token
480
+ * Get current token without advancing
508
481
  */
509
482
  private peek;
510
483
  /**
@@ -514,9 +487,10 @@ declare class Parser {
514
487
  }
515
488
  /**
516
489
  * Parse source code string into AST
490
+ * Convenience function that creates lexer and parser
517
491
  *
518
492
  * @param source - The source code to parse
519
493
  * @returns Parsed AST
520
494
  */
521
495
  declare function parseSource(source: string): ASTNode;
522
- export { parseSource, optimize, isUnaryOp, isProgram, isNumberLiteral, isNullishAssignment, isIdentifier, isFunctionCall, isConditionalExpression, isBinaryOp, isAssignment, generate, execute, defaultContext, exports_ast as ast, TokenType, Token, RuntimeValue, Parser, Lexer, Executor, ExecutionContext, CodeGenerator, ASTNode };
496
+ export { parseSource, optimize, isUnaryOp, isProgram, isNumberLiteral, isIdentifier, isFunctionCall, isConditionalExpression, isBinaryOp, isAssignment, generate, execute, defaultContext, exports_ast as ast, TokenType, Token, RuntimeValue, Parser, Lexer, Executor, ExecutionContext, CodeGenerator, ASTNode };