@elwood-lang/core 0.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/dist/ast.d.ts +237 -0
- package/dist/ast.d.ts.map +1 -0
- package/dist/ast.js +2 -0
- package/dist/ast.js.map +1 -0
- package/dist/evaluator.d.ts +4 -0
- package/dist/evaluator.d.ts.map +1 -0
- package/dist/evaluator.js +879 -0
- package/dist/evaluator.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58 -0
- package/dist/index.js.map +1 -0
- package/dist/lexer.d.ts +14 -0
- package/dist/lexer.d.ts.map +1 -0
- package/dist/lexer.js +279 -0
- package/dist/lexer.js.map +1 -0
- package/dist/parser.d.ts +15 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +610 -0
- package/dist/parser.js.map +1 -0
- package/dist/scope.d.ts +13 -0
- package/dist/scope.d.ts.map +1 -0
- package/dist/scope.js +27 -0
- package/dist/scope.js.map +1 -0
- package/dist/token.d.ts +65 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +66 -0
- package/dist/token.js.map +1 -0
- package/package.json +36 -0
- package/src/ast.ts +235 -0
- package/src/evaluator.ts +832 -0
- package/src/index.ts +78 -0
- package/src/lexer.ts +300 -0
- package/src/parser.ts +626 -0
- package/src/scope.ts +26 -0
- package/src/token.ts +87 -0
package/dist/scope.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Variable scope for Elwood evaluation. Supports nested scopes (let bindings, lambdas).
|
|
3
|
+
*/
|
|
4
|
+
export declare class Scope {
|
|
5
|
+
private parent?;
|
|
6
|
+
private vars;
|
|
7
|
+
constructor(parent?: Scope | undefined);
|
|
8
|
+
set(name: string, value: unknown): void;
|
|
9
|
+
get(name: string): unknown | undefined;
|
|
10
|
+
has(name: string): boolean;
|
|
11
|
+
child(): Scope;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.d.ts","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,qBAAa,KAAK;IAGJ,OAAO,CAAC,MAAM,CAAC;IAF3B,OAAO,CAAC,IAAI,CAA8B;gBAEtB,MAAM,CAAC,EAAE,KAAK,YAAA;IAElC,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI;IAIvC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAKtC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAK1B,KAAK,IAAI,KAAK;CAGf"}
|
package/dist/scope.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Variable scope for Elwood evaluation. Supports nested scopes (let bindings, lambdas).
|
|
3
|
+
*/
|
|
4
|
+
export class Scope {
|
|
5
|
+
parent;
|
|
6
|
+
vars = new Map();
|
|
7
|
+
constructor(parent) {
|
|
8
|
+
this.parent = parent;
|
|
9
|
+
}
|
|
10
|
+
set(name, value) {
|
|
11
|
+
this.vars.set(name, value);
|
|
12
|
+
}
|
|
13
|
+
get(name) {
|
|
14
|
+
if (this.vars.has(name))
|
|
15
|
+
return this.vars.get(name);
|
|
16
|
+
return this.parent?.get(name);
|
|
17
|
+
}
|
|
18
|
+
has(name) {
|
|
19
|
+
if (this.vars.has(name))
|
|
20
|
+
return true;
|
|
21
|
+
return this.parent?.has(name) ?? false;
|
|
22
|
+
}
|
|
23
|
+
child() {
|
|
24
|
+
return new Scope(this);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scope.js","sourceRoot":"","sources":["../src/scope.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,OAAO,KAAK;IAGI;IAFZ,IAAI,GAAG,IAAI,GAAG,EAAmB,CAAC;IAE1C,YAAoB,MAAc;QAAd,WAAM,GAAN,MAAM,CAAQ;IAAG,CAAC;IAEtC,GAAG,CAAC,IAAY,EAAE,KAAc;QAC9B,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,GAAG,CAAC,IAAY;QACd,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,GAAG,CAAC,IAAY;QACd,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACrC,OAAO,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC;IACzC,CAAC;IAED,KAAK;QACH,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;CACF"}
|
package/dist/token.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export declare enum TokenKind {
|
|
2
|
+
StringLiteral = "StringLiteral",
|
|
3
|
+
NumberLiteral = "NumberLiteral",
|
|
4
|
+
TrueLiteral = "TrueLiteral",
|
|
5
|
+
FalseLiteral = "FalseLiteral",
|
|
6
|
+
NullLiteral = "NullLiteral",
|
|
7
|
+
Identifier = "Identifier",
|
|
8
|
+
Dollar = "Dollar",
|
|
9
|
+
DollarDot = "DollarDot",
|
|
10
|
+
Dot = "Dot",
|
|
11
|
+
DotDot = "DotDot",
|
|
12
|
+
LeftBracket = "LeftBracket",
|
|
13
|
+
RightBracket = "RightBracket",
|
|
14
|
+
LeftParen = "LeftParen",
|
|
15
|
+
RightParen = "RightParen",
|
|
16
|
+
LeftBrace = "LeftBrace",
|
|
17
|
+
RightBrace = "RightBrace",
|
|
18
|
+
Pipe = "Pipe",
|
|
19
|
+
FatArrow = "FatArrow",
|
|
20
|
+
Comma = "Comma",
|
|
21
|
+
Colon = "Colon",
|
|
22
|
+
Star = "Star",
|
|
23
|
+
Spread = "Spread",
|
|
24
|
+
Plus = "Plus",
|
|
25
|
+
Minus = "Minus",
|
|
26
|
+
Slash = "Slash",
|
|
27
|
+
Assign = "Assign",
|
|
28
|
+
EqualEqual = "EqualEqual",
|
|
29
|
+
BangEqual = "BangEqual",
|
|
30
|
+
LessThan = "LessThan",
|
|
31
|
+
LessThanOrEqual = "LessThanOrEqual",
|
|
32
|
+
GreaterThan = "GreaterThan",
|
|
33
|
+
GreaterThanOrEqual = "GreaterThanOrEqual",
|
|
34
|
+
AmpersandAmpersand = "AmpersandAmpersand",
|
|
35
|
+
PipePipe = "PipePipe",
|
|
36
|
+
Bang = "Bang",
|
|
37
|
+
Let = "Let",
|
|
38
|
+
If = "If",
|
|
39
|
+
Then = "Then",
|
|
40
|
+
Else = "Else",
|
|
41
|
+
Match = "Match",
|
|
42
|
+
Return = "Return",
|
|
43
|
+
From = "From",
|
|
44
|
+
Asc = "Asc",
|
|
45
|
+
Desc = "Desc",
|
|
46
|
+
On = "On",
|
|
47
|
+
Equals = "Equals",
|
|
48
|
+
Into = "Into",
|
|
49
|
+
Underscore = "Underscore",
|
|
50
|
+
Memo = "Memo",
|
|
51
|
+
Backtick = "Backtick",
|
|
52
|
+
Eof = "Eof"
|
|
53
|
+
}
|
|
54
|
+
export interface SourceSpan {
|
|
55
|
+
start: number;
|
|
56
|
+
end: number;
|
|
57
|
+
line: number;
|
|
58
|
+
column: number;
|
|
59
|
+
}
|
|
60
|
+
export interface Token {
|
|
61
|
+
kind: TokenKind;
|
|
62
|
+
text: string;
|
|
63
|
+
span: SourceSpan;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=token.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA,oBAAY,SAAS;IAEnB,aAAa,kBAAkB;IAC/B,aAAa,kBAAkB;IAC/B,WAAW,gBAAgB;IAC3B,YAAY,iBAAiB;IAC7B,WAAW,gBAAgB;IAG3B,UAAU,eAAe;IACzB,MAAM,WAAW;IACjB,SAAS,cAAc;IACvB,GAAG,QAAQ;IACX,MAAM,WAAW;IAGjB,WAAW,gBAAgB;IAC3B,YAAY,iBAAiB;IAC7B,SAAS,cAAc;IACvB,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,UAAU,eAAe;IAGzB,IAAI,SAAS;IACb,QAAQ,aAAa;IACrB,KAAK,UAAU;IACf,KAAK,UAAU;IACf,IAAI,SAAS;IACb,MAAM,WAAW;IAGjB,IAAI,SAAS;IACb,KAAK,UAAU;IACf,KAAK,UAAU;IAGf,MAAM,WAAW;IAGjB,UAAU,eAAe;IACzB,SAAS,cAAc;IACvB,QAAQ,aAAa;IACrB,eAAe,oBAAoB;IACnC,WAAW,gBAAgB;IAC3B,kBAAkB,uBAAuB;IAGzC,kBAAkB,uBAAuB;IACzC,QAAQ,aAAa;IACrB,IAAI,SAAS;IAGb,GAAG,QAAQ;IACX,EAAE,OAAO;IACT,IAAI,SAAS;IACb,IAAI,SAAS;IACb,KAAK,UAAU;IACf,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,GAAG,QAAQ;IACX,IAAI,SAAS;IACb,EAAE,OAAO;IACT,MAAM,WAAW;IACjB,IAAI,SAAS;IACb,UAAU,eAAe;IACzB,IAAI,SAAS;IAGb,QAAQ,aAAa;IAGrB,GAAG,QAAQ;CACZ;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,KAAK;IACpB,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;CAClB"}
|
package/dist/token.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export var TokenKind;
|
|
2
|
+
(function (TokenKind) {
|
|
3
|
+
// Literals
|
|
4
|
+
TokenKind["StringLiteral"] = "StringLiteral";
|
|
5
|
+
TokenKind["NumberLiteral"] = "NumberLiteral";
|
|
6
|
+
TokenKind["TrueLiteral"] = "TrueLiteral";
|
|
7
|
+
TokenKind["FalseLiteral"] = "FalseLiteral";
|
|
8
|
+
TokenKind["NullLiteral"] = "NullLiteral";
|
|
9
|
+
// Identifiers & paths
|
|
10
|
+
TokenKind["Identifier"] = "Identifier";
|
|
11
|
+
TokenKind["Dollar"] = "Dollar";
|
|
12
|
+
TokenKind["DollarDot"] = "DollarDot";
|
|
13
|
+
TokenKind["Dot"] = "Dot";
|
|
14
|
+
TokenKind["DotDot"] = "DotDot";
|
|
15
|
+
// Brackets
|
|
16
|
+
TokenKind["LeftBracket"] = "LeftBracket";
|
|
17
|
+
TokenKind["RightBracket"] = "RightBracket";
|
|
18
|
+
TokenKind["LeftParen"] = "LeftParen";
|
|
19
|
+
TokenKind["RightParen"] = "RightParen";
|
|
20
|
+
TokenKind["LeftBrace"] = "LeftBrace";
|
|
21
|
+
TokenKind["RightBrace"] = "RightBrace";
|
|
22
|
+
// Operators
|
|
23
|
+
TokenKind["Pipe"] = "Pipe";
|
|
24
|
+
TokenKind["FatArrow"] = "FatArrow";
|
|
25
|
+
TokenKind["Comma"] = "Comma";
|
|
26
|
+
TokenKind["Colon"] = "Colon";
|
|
27
|
+
TokenKind["Star"] = "Star";
|
|
28
|
+
TokenKind["Spread"] = "Spread";
|
|
29
|
+
// Arithmetic
|
|
30
|
+
TokenKind["Plus"] = "Plus";
|
|
31
|
+
TokenKind["Minus"] = "Minus";
|
|
32
|
+
TokenKind["Slash"] = "Slash";
|
|
33
|
+
// Assignment
|
|
34
|
+
TokenKind["Assign"] = "Assign";
|
|
35
|
+
// Comparison
|
|
36
|
+
TokenKind["EqualEqual"] = "EqualEqual";
|
|
37
|
+
TokenKind["BangEqual"] = "BangEqual";
|
|
38
|
+
TokenKind["LessThan"] = "LessThan";
|
|
39
|
+
TokenKind["LessThanOrEqual"] = "LessThanOrEqual";
|
|
40
|
+
TokenKind["GreaterThan"] = "GreaterThan";
|
|
41
|
+
TokenKind["GreaterThanOrEqual"] = "GreaterThanOrEqual";
|
|
42
|
+
// Logical
|
|
43
|
+
TokenKind["AmpersandAmpersand"] = "AmpersandAmpersand";
|
|
44
|
+
TokenKind["PipePipe"] = "PipePipe";
|
|
45
|
+
TokenKind["Bang"] = "Bang";
|
|
46
|
+
// Keywords
|
|
47
|
+
TokenKind["Let"] = "Let";
|
|
48
|
+
TokenKind["If"] = "If";
|
|
49
|
+
TokenKind["Then"] = "Then";
|
|
50
|
+
TokenKind["Else"] = "Else";
|
|
51
|
+
TokenKind["Match"] = "Match";
|
|
52
|
+
TokenKind["Return"] = "Return";
|
|
53
|
+
TokenKind["From"] = "From";
|
|
54
|
+
TokenKind["Asc"] = "Asc";
|
|
55
|
+
TokenKind["Desc"] = "Desc";
|
|
56
|
+
TokenKind["On"] = "On";
|
|
57
|
+
TokenKind["Equals"] = "Equals";
|
|
58
|
+
TokenKind["Into"] = "Into";
|
|
59
|
+
TokenKind["Underscore"] = "Underscore";
|
|
60
|
+
TokenKind["Memo"] = "Memo";
|
|
61
|
+
// Interpolation
|
|
62
|
+
TokenKind["Backtick"] = "Backtick";
|
|
63
|
+
// Special
|
|
64
|
+
TokenKind["Eof"] = "Eof";
|
|
65
|
+
})(TokenKind || (TokenKind = {}));
|
|
66
|
+
//# sourceMappingURL=token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token.js","sourceRoot":"","sources":["../src/token.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,SAyEX;AAzED,WAAY,SAAS;IACnB,WAAW;IACX,4CAA+B,CAAA;IAC/B,4CAA+B,CAAA;IAC/B,wCAA2B,CAAA;IAC3B,0CAA6B,CAAA;IAC7B,wCAA2B,CAAA;IAE3B,sBAAsB;IACtB,sCAAyB,CAAA;IACzB,8BAAiB,CAAA;IACjB,oCAAuB,CAAA;IACvB,wBAAW,CAAA;IACX,8BAAiB,CAAA;IAEjB,WAAW;IACX,wCAA2B,CAAA;IAC3B,0CAA6B,CAAA;IAC7B,oCAAuB,CAAA;IACvB,sCAAyB,CAAA;IACzB,oCAAuB,CAAA;IACvB,sCAAyB,CAAA;IAEzB,YAAY;IACZ,0BAAa,CAAA;IACb,kCAAqB,CAAA;IACrB,4BAAe,CAAA;IACf,4BAAe,CAAA;IACf,0BAAa,CAAA;IACb,8BAAiB,CAAA;IAEjB,aAAa;IACb,0BAAa,CAAA;IACb,4BAAe,CAAA;IACf,4BAAe,CAAA;IAEf,aAAa;IACb,8BAAiB,CAAA;IAEjB,aAAa;IACb,sCAAyB,CAAA;IACzB,oCAAuB,CAAA;IACvB,kCAAqB,CAAA;IACrB,gDAAmC,CAAA;IACnC,wCAA2B,CAAA;IAC3B,sDAAyC,CAAA;IAEzC,UAAU;IACV,sDAAyC,CAAA;IACzC,kCAAqB,CAAA;IACrB,0BAAa,CAAA;IAEb,WAAW;IACX,wBAAW,CAAA;IACX,sBAAS,CAAA;IACT,0BAAa,CAAA;IACb,0BAAa,CAAA;IACb,4BAAe,CAAA;IACf,8BAAiB,CAAA;IACjB,0BAAa,CAAA;IACb,wBAAW,CAAA;IACX,0BAAa,CAAA;IACb,sBAAS,CAAA;IACT,8BAAiB,CAAA;IACjB,0BAAa,CAAA;IACb,sCAAyB,CAAA;IACzB,0BAAa,CAAA;IAEb,gBAAgB;IAChB,kCAAqB,CAAA;IAErB,UAAU;IACV,wBAAW,CAAA;AACb,CAAC,EAzEW,SAAS,KAAT,SAAS,QAyEpB"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elwood-lang/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Elwood — a functional JSON transformation DSL",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"require": "./dist/index.cjs",
|
|
13
|
+
"types": "./dist/index.d.ts"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"test": "vitest run",
|
|
19
|
+
"test:watch": "vitest"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"json",
|
|
23
|
+
"jsonpath",
|
|
24
|
+
"dsl",
|
|
25
|
+
"transformation",
|
|
26
|
+
"query",
|
|
27
|
+
"functional"
|
|
28
|
+
],
|
|
29
|
+
"author": "Massimiliano Favilli",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^25.5.0",
|
|
33
|
+
"typescript": "^5.9.3",
|
|
34
|
+
"vitest": "^2.1.9"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/ast.ts
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import type { SourceSpan } from './token.js';
|
|
2
|
+
|
|
3
|
+
// ── Expressions ──
|
|
4
|
+
|
|
5
|
+
export type ElwoodExpression =
|
|
6
|
+
| PipelineExpression
|
|
7
|
+
| PathExpression
|
|
8
|
+
| IdentifierExpression
|
|
9
|
+
| LambdaExpression
|
|
10
|
+
| ObjectExpression
|
|
11
|
+
| ArrayExpression
|
|
12
|
+
| LiteralExpression
|
|
13
|
+
| InterpolatedStringExpression
|
|
14
|
+
| BinaryExpression
|
|
15
|
+
| UnaryExpression
|
|
16
|
+
| IfExpression
|
|
17
|
+
| MatchExpression
|
|
18
|
+
| MemoExpression
|
|
19
|
+
| MethodCallExpression
|
|
20
|
+
| FunctionCallExpression
|
|
21
|
+
| MemberAccessExpression
|
|
22
|
+
| IndexExpression;
|
|
23
|
+
|
|
24
|
+
// ── Top-level ──
|
|
25
|
+
|
|
26
|
+
export interface ScriptNode {
|
|
27
|
+
type: 'Script';
|
|
28
|
+
bindings: LetBindingNode[];
|
|
29
|
+
returnExpression: ElwoodExpression | null;
|
|
30
|
+
span: SourceSpan;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface LetBindingNode {
|
|
34
|
+
type: 'LetBinding';
|
|
35
|
+
name: string;
|
|
36
|
+
value: ElwoodExpression;
|
|
37
|
+
span: SourceSpan;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ── Expression nodes ──
|
|
41
|
+
|
|
42
|
+
export interface PipelineExpression {
|
|
43
|
+
type: 'Pipeline';
|
|
44
|
+
source: ElwoodExpression;
|
|
45
|
+
operations: PipeOperation[];
|
|
46
|
+
span: SourceSpan;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface PathExpression {
|
|
50
|
+
type: 'Path';
|
|
51
|
+
segments: PathSegment[];
|
|
52
|
+
isRooted: boolean;
|
|
53
|
+
span: SourceSpan;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface IdentifierExpression {
|
|
57
|
+
type: 'Identifier';
|
|
58
|
+
name: string;
|
|
59
|
+
span: SourceSpan;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface LambdaExpression {
|
|
63
|
+
type: 'Lambda';
|
|
64
|
+
parameters: string[];
|
|
65
|
+
body: ElwoodExpression;
|
|
66
|
+
span: SourceSpan;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export interface ObjectExpression {
|
|
70
|
+
type: 'Object';
|
|
71
|
+
properties: ObjectProperty[];
|
|
72
|
+
span: SourceSpan;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface ObjectProperty {
|
|
76
|
+
key: string;
|
|
77
|
+
value: ElwoodExpression;
|
|
78
|
+
span: SourceSpan;
|
|
79
|
+
isSpread?: boolean;
|
|
80
|
+
computedKey?: ElwoodExpression;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface ArrayExpression {
|
|
84
|
+
type: 'Array';
|
|
85
|
+
items: ElwoodExpression[];
|
|
86
|
+
span: SourceSpan;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface LiteralExpression {
|
|
90
|
+
type: 'Literal';
|
|
91
|
+
value: string | number | boolean | null;
|
|
92
|
+
span: SourceSpan;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface InterpolatedStringExpression {
|
|
96
|
+
type: 'InterpolatedString';
|
|
97
|
+
parts: InterpolationPart[];
|
|
98
|
+
span: SourceSpan;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export type InterpolationPart =
|
|
102
|
+
| { type: 'Text'; text: string; span: SourceSpan }
|
|
103
|
+
| { type: 'Expression'; expression: ElwoodExpression; span: SourceSpan };
|
|
104
|
+
|
|
105
|
+
export interface BinaryExpression {
|
|
106
|
+
type: 'Binary';
|
|
107
|
+
left: ElwoodExpression;
|
|
108
|
+
operator: BinaryOperator;
|
|
109
|
+
right: ElwoodExpression;
|
|
110
|
+
span: SourceSpan;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface UnaryExpression {
|
|
114
|
+
type: 'Unary';
|
|
115
|
+
operator: UnaryOperator;
|
|
116
|
+
operand: ElwoodExpression;
|
|
117
|
+
span: SourceSpan;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export interface IfExpression {
|
|
121
|
+
type: 'If';
|
|
122
|
+
condition: ElwoodExpression;
|
|
123
|
+
thenBranch: ElwoodExpression;
|
|
124
|
+
elseBranch: ElwoodExpression;
|
|
125
|
+
span: SourceSpan;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export interface MatchExpression {
|
|
129
|
+
type: 'Match';
|
|
130
|
+
input: ElwoodExpression;
|
|
131
|
+
arms: MatchArm[];
|
|
132
|
+
span: SourceSpan;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface MatchArm {
|
|
136
|
+
pattern: ElwoodExpression | null; // null = wildcard
|
|
137
|
+
result: ElwoodExpression;
|
|
138
|
+
span: SourceSpan;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export interface MemoExpression {
|
|
142
|
+
type: 'Memo';
|
|
143
|
+
lambda: LambdaExpression;
|
|
144
|
+
span: SourceSpan;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface MethodCallExpression {
|
|
148
|
+
type: 'MethodCall';
|
|
149
|
+
target: ElwoodExpression;
|
|
150
|
+
methodName: string;
|
|
151
|
+
arguments: ElwoodExpression[];
|
|
152
|
+
span: SourceSpan;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface FunctionCallExpression {
|
|
156
|
+
type: 'FunctionCall';
|
|
157
|
+
functionName: string;
|
|
158
|
+
arguments: ElwoodExpression[];
|
|
159
|
+
span: SourceSpan;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface MemberAccessExpression {
|
|
163
|
+
type: 'MemberAccess';
|
|
164
|
+
target: ElwoodExpression;
|
|
165
|
+
memberName: string;
|
|
166
|
+
span: SourceSpan;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export interface IndexExpression {
|
|
170
|
+
type: 'Index';
|
|
171
|
+
target: ElwoodExpression;
|
|
172
|
+
index: ElwoodExpression | null; // null = [*]
|
|
173
|
+
span: SourceSpan;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// ── Pipe Operations ──
|
|
177
|
+
|
|
178
|
+
export type PipeOperation =
|
|
179
|
+
| WhereOperation
|
|
180
|
+
| SelectOperation
|
|
181
|
+
| SelectManyOperation
|
|
182
|
+
| OrderByOperation
|
|
183
|
+
| GroupByOperation
|
|
184
|
+
| DistinctOperation
|
|
185
|
+
| AggregateOperation
|
|
186
|
+
| SliceOperation
|
|
187
|
+
| BatchOperation
|
|
188
|
+
| JoinOperation
|
|
189
|
+
| ConcatOperation
|
|
190
|
+
| ReduceOperation
|
|
191
|
+
| QuantifierOperation
|
|
192
|
+
| MatchOperation;
|
|
193
|
+
|
|
194
|
+
export interface WhereOperation { type: 'Where'; predicate: ElwoodExpression; span: SourceSpan }
|
|
195
|
+
export interface SelectOperation { type: 'Select'; projection: ElwoodExpression; span: SourceSpan }
|
|
196
|
+
export interface SelectManyOperation { type: 'SelectMany'; projection: ElwoodExpression; span: SourceSpan }
|
|
197
|
+
export interface OrderByOperation { type: 'OrderBy'; keys: { key: ElwoodExpression; ascending: boolean }[]; span: SourceSpan }
|
|
198
|
+
export interface GroupByOperation { type: 'GroupBy'; keySelector: ElwoodExpression; span: SourceSpan }
|
|
199
|
+
export interface DistinctOperation { type: 'Distinct'; span: SourceSpan }
|
|
200
|
+
export interface AggregateOperation { type: 'Aggregate'; name: string; predicate?: ElwoodExpression; span: SourceSpan }
|
|
201
|
+
export interface SliceOperation { type: 'Slice'; kind: 'take' | 'skip'; count: ElwoodExpression; span: SourceSpan }
|
|
202
|
+
export interface BatchOperation { type: 'Batch'; size: ElwoodExpression; span: SourceSpan }
|
|
203
|
+
export interface JoinOperation {
|
|
204
|
+
type: 'Join';
|
|
205
|
+
source: ElwoodExpression;
|
|
206
|
+
leftKey: ElwoodExpression;
|
|
207
|
+
rightKey: ElwoodExpression;
|
|
208
|
+
intoAlias?: string;
|
|
209
|
+
mode: JoinMode;
|
|
210
|
+
span: SourceSpan;
|
|
211
|
+
}
|
|
212
|
+
export interface ConcatOperation { type: 'Concat'; separator?: ElwoodExpression; span: SourceSpan }
|
|
213
|
+
export interface ReduceOperation { type: 'Reduce'; accumulator: ElwoodExpression; initialValue?: ElwoodExpression; span: SourceSpan }
|
|
214
|
+
export interface QuantifierOperation { type: 'Quantifier'; kind: 'any' | 'all'; predicate: ElwoodExpression; span: SourceSpan }
|
|
215
|
+
export interface MatchOperation { type: 'MatchOp'; arms: MatchArm[]; span: SourceSpan }
|
|
216
|
+
|
|
217
|
+
export type JoinMode = 'inner' | 'left' | 'right' | 'full';
|
|
218
|
+
|
|
219
|
+
// ── Path Segments ──
|
|
220
|
+
|
|
221
|
+
export type PathSegment =
|
|
222
|
+
| { type: 'Property'; name: string; span: SourceSpan }
|
|
223
|
+
| { type: 'Index'; index: number | null; span: SourceSpan } // null = wildcard [*]
|
|
224
|
+
| { type: 'Slice'; start: number | null; end: number | null; span: SourceSpan }
|
|
225
|
+
| { type: 'RecursiveDescent'; name: string; span: SourceSpan };
|
|
226
|
+
|
|
227
|
+
// ── Operators ──
|
|
228
|
+
|
|
229
|
+
export type BinaryOperator =
|
|
230
|
+
| 'Add' | 'Subtract' | 'Multiply' | 'Divide'
|
|
231
|
+
| 'Equal' | 'NotEqual'
|
|
232
|
+
| 'LessThan' | 'LessThanOrEqual' | 'GreaterThan' | 'GreaterThanOrEqual'
|
|
233
|
+
| 'And' | 'Or';
|
|
234
|
+
|
|
235
|
+
export type UnaryOperator = 'Negate' | 'Not';
|