littlewing 1.0.0 → 1.1.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/README.md CHANGED
@@ -260,17 +260,27 @@ const ast = parse("x = 5; x + 10");
260
260
 
261
261
  // Count all identifiers in an AST
262
262
  const count = visit(ast, {
263
- Program: (n, recurse) =>
264
- n.statements.reduce((sum, stmt) => sum + recurse(stmt), 0),
263
+ // Tuple: [kind, statements]
264
+ Program: (n, recurse) => {
265
+ const statements = n[1];
266
+ return statements.reduce((sum, stmt) => sum + recurse(stmt), 0);
267
+ },
265
268
  NumberLiteral: () => 0,
266
269
  Identifier: () => 1,
267
- BinaryOp: (n, recurse) => recurse(n.left) + recurse(n.right),
268
- UnaryOp: (n, recurse) => recurse(n.argument),
269
- Assignment: (n, recurse) => 1 + recurse(n.value),
270
- FunctionCall: (n, recurse) =>
271
- 1 + n.arguments.reduce((sum, arg) => sum + recurse(arg), 0),
270
+ // Tuple: [kind, left, operator, right]
271
+ BinaryOp: (n, recurse) => recurse(n[1]) + recurse(n[3]),
272
+ // Tuple: [kind, operator, argument]
273
+ UnaryOp: (n, recurse) => recurse(n[2]),
274
+ // Tuple: [kind, name, value]
275
+ Assignment: (n, recurse) => 1 + recurse(n[2]),
276
+ // Tuple: [kind, name, arguments]
277
+ FunctionCall: (n, recurse) => {
278
+ const args = n[2];
279
+ return 1 + args.reduce((sum, arg) => sum + recurse(arg), 0);
280
+ },
281
+ // Tuple: [kind, condition, consequent, alternate]
272
282
  ConditionalExpression: (n, recurse) =>
273
- recurse(n.condition) + recurse(n.consequent) + recurse(n.alternate),
283
+ recurse(n[1]) + recurse(n[2]) + recurse(n[3]),
274
284
  }); // → 3 (x appears 3 times)
275
285
  ```
276
286
 
@@ -287,18 +297,24 @@ const ast = parse("x = 5; y = x + 10; y * 2");
287
297
  const result = visitPartial(
288
298
  ast,
289
299
  {
300
+ // Tuple: [kind, statements]
290
301
  Program: (n, recurse) => {
291
- for (const stmt of n.statements) {
302
+ const statements = n[1];
303
+ for (const stmt of statements) {
292
304
  const found = recurse(stmt);
293
305
  if (found !== undefined) return found;
294
306
  }
295
307
  return undefined;
296
308
  },
309
+ // Tuple: [kind, name, value]
297
310
  Assignment: (n, recurse) => {
298
- if (n.name === "y") return n; // Found it!
299
- return recurse(n.value); // Keep searching
311
+ const name = n[1];
312
+ const value = n[2];
313
+ if (name === "y") return n; // Found it!
314
+ return recurse(value); // Keep searching
300
315
  },
301
- BinaryOp: (n, recurse) => recurse(n.left) ?? recurse(n.right),
316
+ // Tuple: [kind, left, operator, right]
317
+ BinaryOp: (n, recurse) => recurse(n[1]) ?? recurse(n[3]),
302
318
  },
303
319
  () => undefined,
304
320
  ); // → Assignment node for "y = x + 10"
@@ -313,22 +329,29 @@ import { visit, parse, ast } from "littlewing";
313
329
 
314
330
  // Double all numeric literals
315
331
  const transformed = visit<ASTNode>(parse("2 + 3 * 4"), {
316
- Program: (n, recurse) =>
317
- ast.program(n.statements.map((stmt) => recurse(stmt))),
318
- NumberLiteral: (n) => ast.number(n.value * 2),
332
+ // Tuple: [kind, statements]
333
+ Program: (n, recurse) => {
334
+ const statements = n[1];
335
+ return ast.program(statements.map((stmt) => recurse(stmt)));
336
+ },
337
+ // Tuple: [kind, value]
338
+ NumberLiteral: (n) => ast.number(n[1] * 2),
319
339
  Identifier: (n) => n,
320
- BinaryOp: (n, recurse) =>
321
- ast.binaryOp(recurse(n.left), n.operator, recurse(n.right)),
322
- UnaryOp: (n, recurse) => ast.unaryOp(n.operator, recurse(n.argument)),
323
- Assignment: (n, recurse) => ast.assignment(n.name, recurse(n.value)),
324
- FunctionCall: (n, recurse) =>
325
- ast.functionCall(n.name, n.arguments.map(recurse)),
340
+ // Tuple: [kind, left, operator, right]
341
+ BinaryOp: (n, recurse) => ast.binaryOp(recurse(n[1]), n[2], recurse(n[3])),
342
+ // Tuple: [kind, operator, argument]
343
+ UnaryOp: (n, recurse) => ast.unaryOp(n[1], recurse(n[2])),
344
+ // Tuple: [kind, name, value]
345
+ Assignment: (n, recurse) => ast.assign(n[1], recurse(n[2])),
346
+ // Tuple: [kind, name, arguments]
347
+ FunctionCall: (n, recurse) => {
348
+ const name = n[1];
349
+ const args = n[2];
350
+ return ast.functionCall(name, args.map(recurse));
351
+ },
352
+ // Tuple: [kind, condition, consequent, alternate]
326
353
  ConditionalExpression: (n, recurse) =>
327
- ast.conditional(
328
- recurse(n.condition),
329
- recurse(n.consequent),
330
- recurse(n.alternate),
331
- ),
354
+ ast.conditional(recurse(n[1]), recurse(n[2]), recurse(n[3])),
332
355
  });
333
356
 
334
357
  generate(transformed); // → "4 + 6 * 8"
package/dist/index.d.ts CHANGED
@@ -1,168 +1,87 @@
1
- /**
2
- * Runtime value type - only numbers
3
- */
4
- type RuntimeValue = number;
1
+ declare namespace exports_ast {
2
+ export { unaryOp, subtract, program, number, notEquals, negate, multiply, modulo, logicalOr, logicalNot, logicalAnd, lessThan, lessEqual, isUnaryOp, isProgram, isNumberLiteral, isIdentifier, isFunctionCall, isConditionalExpression, isBinaryOp, isAssignment, identifier, greaterThan, greaterEqual, getNodeName, functionCall, exponentiate, equals, divide, conditional, binaryOp, assign, add, UnaryOp, Program, Operator, NumberLiteral, NodeKind, Identifier, FunctionCall, ConditionalExpression, BinaryOp, Assignment, ASTNode };
3
+ }
5
4
  /**
6
5
  * Binary operator types
7
6
  */
8
7
  type Operator = "+" | "-" | "*" | "/" | "%" | "^" | "==" | "!=" | "<" | ">" | "<=" | ">=" | "&&" | "||";
9
8
  /**
10
- * Execution context providing global functions and variables
11
- * Functions must accept zero or more number arguments and return a number
12
- * Variables must be numbers
13
- */
14
- interface ExecutionContext {
15
- functions?: Record<string, (...args: RuntimeValue[]) => RuntimeValue>;
16
- variables?: Record<string, RuntimeValue>;
17
- }
18
- /**
19
- * Token types for lexer output
20
- */
21
- declare enum TokenType {
22
- NUMBER = "NUMBER",
23
- IDENTIFIER = "IDENTIFIER",
24
- PLUS = "PLUS",
25
- MINUS = "MINUS",
26
- STAR = "STAR",
27
- SLASH = "SLASH",
28
- PERCENT = "PERCENT",
29
- CARET = "CARET",
30
- EXCLAMATION = "EXCLAMATION",
31
- DOUBLE_EQUALS = "DOUBLE_EQUALS",
32
- NOT_EQUALS = "NOT_EQUALS",
33
- LESS_THAN = "LESS_THAN",
34
- GREATER_THAN = "GREATER_THAN",
35
- LESS_EQUAL = "LESS_EQUAL",
36
- GREATER_EQUAL = "GREATER_EQUAL",
37
- LOGICAL_AND = "LOGICAL_AND",
38
- LOGICAL_OR = "LOGICAL_OR",
39
- LPAREN = "LPAREN",
40
- RPAREN = "RPAREN",
41
- EQUALS = "EQUALS",
42
- COMMA = "COMMA",
43
- QUESTION = "QUESTION",
44
- COLON = "COLON",
45
- EOF = "EOF"
9
+ * AST Node kind discriminator (const enum for zero-cost abstraction)
10
+ */
11
+ declare const enum NodeKind {
12
+ Program = 0,
13
+ NumberLiteral = 1,
14
+ Identifier = 2,
15
+ BinaryOp = 3,
16
+ UnaryOp = 4,
17
+ FunctionCall = 5,
18
+ Assignment = 6,
19
+ ConditionalExpression = 7
46
20
  }
47
21
  /**
48
- * Token produced by lexer
49
- */
50
- interface Token {
51
- type: TokenType;
52
- value: string | number;
53
- position: number;
54
- }
55
- /**
56
- * AST Node - base type
57
- */
58
- type ASTNode = Program | NumberLiteral | Identifier | BinaryOp | UnaryOp | FunctionCall | Assignment | ConditionalExpression;
59
- /**
60
22
  * Program node (multiple statements)
23
+ * Tuple: [kind, statements]
61
24
  */
62
- interface Program {
63
- type: "Program";
64
- statements: ASTNode[];
65
- }
25
+ type Program = readonly [kind: NodeKind.Program, statements: readonly ASTNode[]];
66
26
  /**
67
27
  * Number literal (123, 45.67)
28
+ * Tuple: [kind, value]
68
29
  */
69
- interface NumberLiteral {
70
- type: "NumberLiteral";
71
- value: number;
72
- }
30
+ type NumberLiteral = readonly [kind: NodeKind.NumberLiteral, value: number];
73
31
  /**
74
32
  * Identifier (variable or function name)
33
+ * Tuple: [kind, name]
75
34
  */
76
- interface Identifier {
77
- type: "Identifier";
78
- name: string;
79
- }
35
+ type Identifier = readonly [kind: NodeKind.Identifier, name: string];
80
36
  /**
81
37
  * Binary operation (a + b, x * y, etc.)
38
+ * Tuple: [kind, left, operator, right]
39
+ * Note: left-to-right reading order
82
40
  */
83
- interface BinaryOp {
84
- type: "BinaryOp";
85
- left: ASTNode;
86
- operator: Operator;
87
- right: ASTNode;
88
- }
41
+ type BinaryOp = readonly [kind: NodeKind.BinaryOp, left: ASTNode, operator: Operator, right: ASTNode];
89
42
  /**
90
43
  * Unary operation (-x, !x, etc.)
44
+ * Tuple: [kind, operator, argument]
91
45
  */
92
- interface UnaryOp {
93
- type: "UnaryOp";
94
- operator: "-" | "!";
95
- argument: ASTNode;
96
- }
46
+ type UnaryOp = readonly [kind: NodeKind.UnaryOp, operator: "-" | "!", argument: ASTNode];
97
47
  /**
98
- * Function call (now(), abs(-5), etc.)
48
+ * Function call (NOW(), MAX(a, b), etc.)
49
+ * Tuple: [kind, name, arguments]
99
50
  */
100
- interface FunctionCall {
101
- type: "FunctionCall";
102
- name: string;
103
- arguments: ASTNode[];
104
- }
51
+ type FunctionCall = readonly [kind: NodeKind.FunctionCall, name: string, arguments: readonly ASTNode[]];
105
52
  /**
106
53
  * Variable assignment (x = 5)
54
+ * Tuple: [kind, name, value]
107
55
  */
108
- interface Assignment {
109
- type: "Assignment";
110
- name: string;
111
- value: ASTNode;
112
- }
56
+ type Assignment = readonly [kind: NodeKind.Assignment, name: string, value: ASTNode];
113
57
  /**
114
58
  * Conditional expression (ternary operator: condition ? consequent : alternate)
115
59
  * Returns consequent if condition !== 0, otherwise returns alternate
60
+ * Tuple: [kind, condition, consequent, alternate]
116
61
  */
117
- interface ConditionalExpression {
118
- type: "ConditionalExpression";
119
- condition: ASTNode;
120
- consequent: ASTNode;
121
- alternate: ASTNode;
122
- }
62
+ type ConditionalExpression = readonly [kind: NodeKind.ConditionalExpression, condition: ASTNode, consequent: ASTNode, alternate: ASTNode];
63
+ /**
64
+ * AST Node - discriminated union of all node types
65
+ */
66
+ type ASTNode = Program | NumberLiteral | Identifier | BinaryOp | UnaryOp | FunctionCall | Assignment | ConditionalExpression;
123
67
  /**
124
68
  * Type guard functions for discriminated union narrowing
125
69
  */
70
+ declare function isProgram(node: ASTNode): node is Program;
126
71
  declare function isNumberLiteral(node: ASTNode): node is NumberLiteral;
127
72
  declare function isIdentifier(node: ASTNode): node is Identifier;
128
73
  declare function isBinaryOp(node: ASTNode): node is BinaryOp;
129
74
  declare function isUnaryOp(node: ASTNode): node is UnaryOp;
130
75
  declare function isFunctionCall(node: ASTNode): node is FunctionCall;
131
76
  declare function isAssignment(node: ASTNode): node is Assignment;
132
- declare function isProgram(node: ASTNode): node is Program;
133
77
  declare function isConditionalExpression(node: ASTNode): node is ConditionalExpression;
134
78
  /**
135
- * Extracts input variables from an AST.
136
- *
137
- * Input variables are those whose values can be determined without knowing
138
- * the values of other variables in the script. This includes:
139
- * - Literals (10, -5, 3.14)
140
- * - Unary minus of literals (-10)
141
- * - Constant expressions (2 + 3, -5 * 2)
142
- * - Function calls with constant arguments (MAX(10, 20), NOW())
143
- *
144
- * Computed variables (those that reference other variables) are excluded.
145
- *
146
- * @param ast - The AST to analyze (can be a single statement or Program node)
147
- * @returns Array of input variable names
148
- *
149
- * @example
150
- * ```typescript
151
- * const ast = parse('price = 100; tax = price * 0.08')
152
- * extractInputVariables(ast) // ['price']
153
- * ```
154
- */
155
- declare function extractInputVariables(ast: ASTNode): string[];
156
- declare namespace exports_ast {
157
- export { unaryOp, subtract, program, number, notEquals, negate, multiply, modulo, logicalOr, logicalNot, logicalAnd, lessThan, lessEqual, identifier, greaterThan, greaterEqual, functionCall, exponentiate, equals, divide, conditional, binaryOp, assign, add };
158
- }
159
- /**
160
79
  * Builder functions for creating AST nodes manually
161
80
  */
162
81
  /**
163
82
  * Create a program node
164
83
  */
165
- declare function program(statements: ASTNode[]): Program;
84
+ declare function program(statements: readonly ASTNode[]): Program;
166
85
  /**
167
86
  * Create a number literal node
168
87
  */
@@ -182,7 +101,7 @@ declare function unaryOp(operator: "-" | "!", argument: ASTNode): UnaryOp;
182
101
  /**
183
102
  * Create a function call node
184
103
  */
185
- declare function functionCall(name: string, args?: ASTNode[]): FunctionCall;
104
+ declare function functionCall(name: string, args?: readonly ASTNode[]): FunctionCall;
186
105
  /**
187
106
  * Create a variable assignment node
188
107
  */
@@ -264,41 +183,33 @@ declare function logicalAnd(left: ASTNode, right: ASTNode): BinaryOp;
264
183
  * Create a logical OR operation (||)
265
184
  */
266
185
  declare function logicalOr(left: ASTNode, right: ASTNode): BinaryOp;
186
+ declare function getNodeName(node: ASTNode): string;
267
187
  /**
268
- * Generate source code from an AST node
269
- */
270
- declare function generate(node: ASTNode): string;
271
- /**
272
- * Default execution context with common Math functions and date/time utilities
273
- * Users can use this as-is or spread it into their own context
274
- *
275
- * All functions use UPPERCASE naming convention to avoid collisions with user variables.
276
- * All date-related functions work with timestamps (milliseconds since Unix epoch)
277
- * to maintain the language's numbers-only type system.
188
+ * Extracts input variables from an AST.
278
189
  *
279
- * @example
280
- * // Use as-is
281
- * execute('ABS(-5)', defaultContext)
190
+ * Input variables are those whose values can be determined without knowing
191
+ * the values of other variables in the script. This includes:
192
+ * - Literals (10, -5, 3.14)
193
+ * - Unary minus of literals (-10)
194
+ * - Constant expressions (2 + 3, -5 * 2)
195
+ * - Function calls with constant arguments (MAX(10, 20), NOW())
282
196
  *
283
- * @example
284
- * // Spread into custom context
285
- * execute('NOW() + FROM_MINUTES(5)', {
286
- * ...defaultContext,
287
- * variables: { customVar: 42 }
288
- * })
197
+ * Computed variables (those that reference other variables) are excluded.
289
198
  *
290
- * @example
291
- * // Work with timestamps
292
- * const result = execute('NOW() + FROM_DAYS(7)', defaultContext)
293
- * const futureDate = new Date(result) // Convert back to Date if needed
199
+ * @param ast - The AST to analyze (can be a single statement or Program node)
200
+ * @returns Array of input variable names
294
201
  *
295
202
  * @example
296
- * // Calculate time differences
297
- * const ts1 = Date.now()
298
- * const ts2 = ts1 + 1000 * 60 * 60 * 3 // 3 hours later
299
- * execute('DIFFERENCE_IN_HOURS(ts1, ts2)', { ...defaultContext, variables: { ts1, ts2 } })
203
+ * ```typescript
204
+ * const ast = parse('price = 100; tax = price * 0.08')
205
+ * extractInputVariables(ast) // ['price']
206
+ * ```
300
207
  */
301
- declare const defaultContext: ExecutionContext;
208
+ declare function extractInputVariables(ast: ASTNode): string[];
209
+ /**
210
+ * Generate source code from an AST node
211
+ */
212
+ declare function generate(node: ASTNode): string;
302
213
  /**
303
214
  * Options for customizing the humanization output
304
215
  */
@@ -363,9 +274,23 @@ interface HumanizeOptions {
363
274
  */
364
275
  declare function humanize(node: ASTNode, options?: HumanizeOptions): string;
365
276
  /**
277
+ * Runtime value type - only numbers
278
+ */
279
+ type RuntimeValue = number;
280
+ /**
281
+ * Execution context providing global functions and variables
282
+ * Functions must accept zero or more number arguments and return a number
283
+ * Variables must be numbers
284
+ */
285
+ interface ExecutionContext {
286
+ functions?: Record<string, (...args: RuntimeValue[]) => RuntimeValue>;
287
+ variables?: Record<string, RuntimeValue>;
288
+ }
289
+ /**
366
290
  * Evaluate source code or AST with given context
367
291
  * @param input - Either a source code string or an AST node
368
292
  * @param context - Optional execution context with variables and functions
293
+ * @returns The evaluated result
369
294
  */
370
295
  declare function evaluate(input: string | ASTNode, context?: ExecutionContext): RuntimeValue;
371
296
  /**
@@ -395,12 +320,257 @@ declare function evaluate(input: string | ASTNode, context?: ExecutionContext):
395
320
  declare function optimize(node: ASTNode): ASTNode;
396
321
  /**
397
322
  * Parse source code string into AST
398
- * Convenience function that creates lexer and parser
323
+ * Implements Pratt parsing (top-down operator precedence)
324
+ * Uses lazy lexing - calls lexer on-demand instead of receiving all tokens upfront
399
325
  *
400
326
  * @param source - The source code to parse
401
327
  * @returns Parsed AST
402
328
  */
403
329
  declare function parse(source: string): ASTNode;
330
+ declare namespace exports_datetime {
331
+ export { START_OF_YEAR, START_OF_WEEK, START_OF_QUARTER, START_OF_MONTH, START_OF_DAY, NOW, IS_WEEKEND, IS_SAME_DAY, IS_LEAP_YEAR, GET_YEAR, GET_WEEKDAY, GET_SECOND, GET_QUARTER, GET_MONTH, GET_MINUTE, GET_MILLISECOND, GET_HOUR, GET_DAY_OF_YEAR, GET_DAY, FROM_YEARS, FROM_WEEKS, FROM_MONTHS, FROM_DAYS, END_OF_YEAR, END_OF_MONTH, END_OF_DAY, DIFFERENCE_IN_YEARS, DIFFERENCE_IN_WEEKS, DIFFERENCE_IN_SECONDS, DIFFERENCE_IN_MONTHS, DIFFERENCE_IN_MINUTES, DIFFERENCE_IN_HOURS, DIFFERENCE_IN_DAYS, DATE, ADD_YEARS, ADD_MONTHS, ADD_DAYS };
332
+ }
333
+ /**
334
+ * Date utility functions for working with timestamps
335
+ * All functions work with milliseconds since Unix epoch (numbers only)
336
+ *
337
+ * IMPORTANT: All functions use local timezone to match the user's context.
338
+ * In a browser, this reflects the user's timezone. On a server, this reflects
339
+ * the server's configured timezone. This ensures date calculations align with
340
+ * the user's calendar expectations.
341
+ */
342
+ /**
343
+ * Get current timestamp (milliseconds since Unix epoch)
344
+ */
345
+ declare const NOW: () => RuntimeValue;
346
+ /**
347
+ * Create timestamp from date components (local timezone)
348
+ * Year is required, all other parameters default to minimum values
349
+ * Month is 1-based (1 = January, 12 = December)
350
+ * All parameters are interpreted in local timezone
351
+ */
352
+ declare const DATE: (year: RuntimeValue, month?: number, day?: number, hour?: number, minute?: number, second?: number) => RuntimeValue;
353
+ /**
354
+ * Convert days to milliseconds
355
+ */
356
+ declare const FROM_DAYS: (d: RuntimeValue) => RuntimeValue;
357
+ /**
358
+ * Convert weeks to milliseconds
359
+ */
360
+ declare const FROM_WEEKS: (w: RuntimeValue) => RuntimeValue;
361
+ /**
362
+ * Convert months to milliseconds (approximate: 30 days per month)
363
+ * WARNING: This is an approximation. Not all months have 30 days.
364
+ * For accurate month arithmetic, use ADD_MONTHS() instead.
365
+ */
366
+ declare const FROM_MONTHS: (months: RuntimeValue) => RuntimeValue;
367
+ /**
368
+ * Convert years to milliseconds (approximate: 365 days per year)
369
+ * WARNING: This is an approximation. Leap years have 366 days.
370
+ * For accurate year arithmetic, use ADD_YEARS() instead.
371
+ */
372
+ declare const FROM_YEARS: (years: RuntimeValue) => RuntimeValue;
373
+ /**
374
+ * Get the year from a timestamp (local timezone)
375
+ */
376
+ declare const GET_YEAR: (timestamp: RuntimeValue) => RuntimeValue;
377
+ /**
378
+ * Get the month from a timestamp (1-based: 1 = January, 12 = December, local timezone)
379
+ */
380
+ declare const GET_MONTH: (timestamp: RuntimeValue) => RuntimeValue;
381
+ /**
382
+ * Get the day of month from a timestamp (1-31, local timezone)
383
+ */
384
+ declare const GET_DAY: (timestamp: RuntimeValue) => RuntimeValue;
385
+ /**
386
+ * Get the hour from a timestamp (0-23, local timezone)
387
+ */
388
+ declare const GET_HOUR: (timestamp: RuntimeValue) => RuntimeValue;
389
+ /**
390
+ * Get the minute from a timestamp (0-59, local timezone)
391
+ */
392
+ declare const GET_MINUTE: (timestamp: RuntimeValue) => RuntimeValue;
393
+ /**
394
+ * Get the second from a timestamp (0-59, local timezone)
395
+ */
396
+ declare const GET_SECOND: (timestamp: RuntimeValue) => RuntimeValue;
397
+ /**
398
+ * Get the millisecond component from a timestamp (0-999, local timezone)
399
+ */
400
+ declare const GET_MILLISECOND: (timestamp: RuntimeValue) => RuntimeValue;
401
+ /**
402
+ * Get the day of week from a timestamp (0 = Sunday, 6 = Saturday, local timezone)
403
+ */
404
+ declare const GET_WEEKDAY: (timestamp: RuntimeValue) => RuntimeValue;
405
+ /**
406
+ * Get the day of year (1-366) from a timestamp (local timezone)
407
+ * January 1st = 1, December 31st = 365 or 366 (leap year)
408
+ */
409
+ declare const GET_DAY_OF_YEAR: (timestamp: RuntimeValue) => RuntimeValue;
410
+ /**
411
+ * Get the quarter (1-4) from a timestamp (local timezone)
412
+ */
413
+ declare const GET_QUARTER: (timestamp: RuntimeValue) => RuntimeValue;
414
+ /**
415
+ * Get the absolute difference between two timestamps in seconds (whole seconds)
416
+ */
417
+ declare const DIFFERENCE_IN_SECONDS: (ts1: RuntimeValue, ts2: RuntimeValue) => RuntimeValue;
418
+ /**
419
+ * Get the absolute difference between two timestamps in minutes (whole minutes)
420
+ */
421
+ declare const DIFFERENCE_IN_MINUTES: (ts1: RuntimeValue, ts2: RuntimeValue) => RuntimeValue;
422
+ /**
423
+ * Get the absolute difference between two timestamps in hours (whole hours)
424
+ */
425
+ declare const DIFFERENCE_IN_HOURS: (ts1: RuntimeValue, ts2: RuntimeValue) => RuntimeValue;
426
+ /**
427
+ * Get the difference in calendar days between two timestamps
428
+ * Counts the number of calendar day boundaries crossed, not 24-hour periods
429
+ * Example: Nov 7 at 11:59 PM to Nov 8 at 12:01 AM = 1 day (different calendar days)
430
+ */
431
+ declare const DIFFERENCE_IN_DAYS: (ts1: RuntimeValue, ts2: RuntimeValue) => RuntimeValue;
432
+ /**
433
+ * Get the difference in calendar weeks between two timestamps
434
+ * Counts the number of week boundaries crossed (based on calendar days)
435
+ */
436
+ declare const DIFFERENCE_IN_WEEKS: (ts1: RuntimeValue, ts2: RuntimeValue) => RuntimeValue;
437
+ /**
438
+ * Get the number of full calendar months between two timestamps (local timezone)
439
+ * Counts complete months where the same day-of-month has been reached
440
+ *
441
+ * Examples:
442
+ * Jan 15 → Feb 14 = 0 months (Feb 15 not reached yet)
443
+ * Jan 15 → Feb 15 = 1 month
444
+ * Jan 31 → Feb 28 = 0 months (Feb 31 doesn't exist)
445
+ * Jan 31 → Mar 31 = 2 months
446
+ */
447
+ declare const DIFFERENCE_IN_MONTHS: (ts1: RuntimeValue, ts2: RuntimeValue) => RuntimeValue;
448
+ /**
449
+ * Get the number of full calendar years between two timestamps (local timezone)
450
+ * Counts complete years where the same month and day have been reached
451
+ *
452
+ * Examples:
453
+ * Jan 15, 2020 → Jan 14, 2021 = 0 years (Jan 15 not reached)
454
+ * Jan 15, 2020 → Jan 15, 2021 = 1 year
455
+ * Feb 29, 2020 → Feb 28, 2021 = 0 years (Feb 29 doesn't exist)
456
+ * Feb 29, 2020 → Mar 1, 2021 = 1 year
457
+ */
458
+ declare const DIFFERENCE_IN_YEARS: (ts1: RuntimeValue, ts2: RuntimeValue) => RuntimeValue;
459
+ /**
460
+ * Get the start of day (00:00:00.000 local time) for a given timestamp
461
+ */
462
+ declare const START_OF_DAY: (timestamp: RuntimeValue) => RuntimeValue;
463
+ /**
464
+ * Get the end of day (23:59:59.999 local time) for a given timestamp
465
+ */
466
+ declare const END_OF_DAY: (timestamp: RuntimeValue) => RuntimeValue;
467
+ /**
468
+ * Get the start of week (Sunday at 00:00:00.000 local time) for a given timestamp
469
+ */
470
+ declare const START_OF_WEEK: (timestamp: RuntimeValue) => RuntimeValue;
471
+ /**
472
+ * Get the start of month (1st day at 00:00:00.000 local time) for a given timestamp
473
+ */
474
+ declare const START_OF_MONTH: (timestamp: RuntimeValue) => RuntimeValue;
475
+ /**
476
+ * Get the end of month (last day at 23:59:59.999 local time) for a given timestamp
477
+ */
478
+ declare const END_OF_MONTH: (timestamp: RuntimeValue) => RuntimeValue;
479
+ /**
480
+ * Get the start of year (Jan 1st at 00:00:00.000 local time) for a given timestamp
481
+ */
482
+ declare const START_OF_YEAR: (timestamp: RuntimeValue) => RuntimeValue;
483
+ /**
484
+ * Get the end of year (Dec 31st at 23:59:59.999 local time) for a given timestamp
485
+ */
486
+ declare const END_OF_YEAR: (timestamp: RuntimeValue) => RuntimeValue;
487
+ /**
488
+ * Add days to a timestamp (local timezone)
489
+ */
490
+ declare const ADD_DAYS: (timestamp: RuntimeValue, days: RuntimeValue) => RuntimeValue;
491
+ /**
492
+ * Add months to a timestamp (handles variable month lengths correctly, local timezone)
493
+ */
494
+ declare const ADD_MONTHS: (timestamp: RuntimeValue, months: RuntimeValue) => RuntimeValue;
495
+ /**
496
+ * Add years to a timestamp (local timezone)
497
+ */
498
+ declare const ADD_YEARS: (timestamp: RuntimeValue, years: RuntimeValue) => RuntimeValue;
499
+ /**
500
+ * Check if two timestamps are on the same calendar day (local timezone)
501
+ * Returns 1 if true, 0 if false
502
+ */
503
+ declare const IS_SAME_DAY: (ts1: RuntimeValue, ts2: RuntimeValue) => RuntimeValue;
504
+ /**
505
+ * Check if timestamp falls on a weekend (Saturday or Sunday, local timezone)
506
+ * Returns 1 if true, 0 if false
507
+ */
508
+ declare const IS_WEEKEND: (timestamp: RuntimeValue) => RuntimeValue;
509
+ /**
510
+ * Check if timestamp is in a leap year (local timezone)
511
+ * Returns 1 if true, 0 if false
512
+ */
513
+ declare const IS_LEAP_YEAR: (timestamp: RuntimeValue) => RuntimeValue;
514
+ /**
515
+ * Get the start of quarter for a given timestamp (local timezone)
516
+ */
517
+ declare const START_OF_QUARTER: (timestamp: RuntimeValue) => RuntimeValue;
518
+ declare namespace exports_math {
519
+ export { TAN, SQRT, SIN, ROUND, MIN, MAX, LOG10, LOG, FLOOR, EXP, COS, CLAMP, CEIL, ABS };
520
+ }
521
+ /**
522
+ * Math utility functions
523
+ * All functions work with numbers only
524
+ */
525
+ /**
526
+ * Constrain a value between a minimum and maximum
527
+ * @example CLAMP(value, 0, 100) - Clamps value between 0 and 100
528
+ */
529
+ declare const CLAMP: (value: RuntimeValue, min: RuntimeValue, max: RuntimeValue) => RuntimeValue;
530
+ declare const ABS: (x: RuntimeValue) => RuntimeValue;
531
+ declare const CEIL: (x: RuntimeValue) => RuntimeValue;
532
+ declare const FLOOR: (x: RuntimeValue) => RuntimeValue;
533
+ declare const ROUND: (x: RuntimeValue) => RuntimeValue;
534
+ declare const SQRT: (x: RuntimeValue) => RuntimeValue;
535
+ declare const MIN: (...values: RuntimeValue[]) => RuntimeValue;
536
+ declare const MAX: (...values: RuntimeValue[]) => RuntimeValue;
537
+ declare const SIN: (x: RuntimeValue) => RuntimeValue;
538
+ declare const COS: (x: RuntimeValue) => RuntimeValue;
539
+ declare const TAN: (x: RuntimeValue) => RuntimeValue;
540
+ declare const LOG: (x: RuntimeValue) => RuntimeValue;
541
+ declare const LOG10: (x: RuntimeValue) => RuntimeValue;
542
+ declare const EXP: (x: RuntimeValue) => RuntimeValue;
543
+ /**
544
+ * Default execution context with standard library functions
545
+ * Users can use this as-is or spread it into their own context
546
+ *
547
+ * All functions use UPPERCASE naming convention to avoid collisions with user variables.
548
+ * All date-related functions work with timestamps (milliseconds since Unix epoch)
549
+ * to maintain the language's numbers-only type system.
550
+ *
551
+ * @example
552
+ * // Use as-is
553
+ * execute('ABS(-5)', defaultContext)
554
+ *
555
+ * @example
556
+ * // Spread into custom context
557
+ * execute('NOW() + FROM_MINUTES(5)', {
558
+ * ...defaultContext,
559
+ * variables: { customVar: 42 }
560
+ * })
561
+ *
562
+ * @example
563
+ * // Work with timestamps
564
+ * const result = execute('NOW() + FROM_DAYS(7)', defaultContext)
565
+ * const futureDate = new Date(result) // Convert back to Date if needed
566
+ *
567
+ * @example
568
+ * // Calculate time differences
569
+ * const ts1 = Date.now()
570
+ * const ts2 = ts1 + 1000 * 60 * 60 * 3 // 3 hours later
571
+ * execute('DIFFERENCE_IN_HOURS(ts1, ts2)', { ...defaultContext, variables: { ts1, ts2 } })
572
+ */
573
+ declare const defaultContext: ExecutionContext;
404
574
  /**
405
575
  * Type-safe visitor pattern for AST traversal.
406
576
  *
@@ -593,4 +763,4 @@ declare function visit<T>(node: ASTNode, visitor: Visitor<T>): T;
593
763
  * )
594
764
  */
595
765
  declare function visitPartial<T>(node: ASTNode, visitor: Partial<Visitor<T>>, defaultHandler: (node: ASTNode, recurse: (n: ASTNode) => T) => T): T;
596
- export { visitPartial, visit, parse, optimize, isUnaryOp, isProgram, isNumberLiteral, isIdentifier, isFunctionCall, isConditionalExpression, isBinaryOp, isAssignment, humanize, generate, extractInputVariables, evaluate, defaultContext, exports_ast as ast, Visitor, UnaryOp, TokenType, Token, RuntimeValue, Program, Operator, NumberLiteral, Identifier, HumanizeOptions, FunctionCall, ExecutionContext, ConditionalExpression, BinaryOp, Assignment, ASTNode };
766
+ export { visitPartial, visit, parse, optimize, exports_math as math, isUnaryOp, isProgram, isNumberLiteral, isIdentifier, isFunctionCall, isConditionalExpression, isBinaryOp, isAssignment, humanize, generate, extractInputVariables, evaluate, defaultContext, exports_datetime as datetime, exports_ast as ast, Visitor, UnaryOp, RuntimeValue, Program, Operator, NumberLiteral, NodeKind, Identifier, HumanizeOptions, FunctionCall, ExecutionContext, ConditionalExpression, BinaryOp, Assignment, ASTNode };