Skip to content

Commit c67f84a

Browse files
committed
extended operations range
1 parent f0673fd commit c67f84a

File tree

5 files changed

+151
-37
lines changed

5 files changed

+151
-37
lines changed

src/common/ast-types.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { OperationTypes, Operators } from "./operators";
1+
import { ExpressionOperators, OperationTypes, Operators } from "./operators";
22
import { Token } from "./token-types";
33

44
export abstract class AstNode {
@@ -105,7 +105,7 @@ export class BracketObjectAccessNode extends AstNode {
105105
export class BinOpNode extends AstNode {
106106
constructor(
107107
public left: AstNode,
108-
public op: Operators,
108+
public op: ExpressionOperators,
109109
public right: AstNode) {
110110
super('binOp');
111111
}

src/common/operators.ts

Lines changed: 128 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,20 @@ export enum OperationTypes {
22
Arithmetic, Assignment, Comparison, Logical, Membership
33
};
44

5-
export type Operators =
6-
"=" | "+=" | "-=" | "*=" | "/=" | "++" | "--"
7-
| "+" | "-" | "*" | "/" | "%" | "**" | "//"
8-
| ">" | ">=" | "==" | "!=" | "<>" | "<" | "<="
9-
| "and" | "or" | "not"
10-
| "in" | "not in";
5+
export type AssignmentOperators = "=" | "+=" | "-=" | "*=" | "/=" | "++" | "--";
6+
export type ArithmeticOperators = "+" | "-" | "*" | "/" | "%" | "**" | "//";
7+
export type ComparisonOperators = ">" | ">=" | "==" | "!=" | "<>" | "<" | "<=";
8+
export type LogicalOperators = "and" | "or" | "not" | "not in";
9+
export type MembershipOperators = "in";
1110

11+
export type Operators = AssignmentOperators | ArithmeticOperators | ComparisonOperators | LogicalOperators | MembershipOperators;
1212

1313
export const OperatorsMap: Record<Operators, OperationTypes> = {
14-
"=" : OperationTypes.Assignment,
15-
"+=" : OperationTypes.Assignment,
16-
"-=" : OperationTypes.Assignment,
17-
"*=" : OperationTypes.Assignment,
18-
"/=" : OperationTypes.Assignment,
19-
"++" : OperationTypes.Assignment,
20-
"--" : OperationTypes.Assignment,
21-
22-
"+" : OperationTypes.Arithmetic,
23-
"-" : OperationTypes.Arithmetic,
24-
"*" : OperationTypes.Arithmetic,
25-
"/" : OperationTypes.Arithmetic,
26-
"%" : OperationTypes.Arithmetic,
14+
"+": OperationTypes.Arithmetic,
15+
"-": OperationTypes.Arithmetic,
16+
"*": OperationTypes.Arithmetic,
17+
"/": OperationTypes.Arithmetic,
18+
"%": OperationTypes.Arithmetic,
2719
"**": OperationTypes.Arithmetic,
2820
"//": OperationTypes.Arithmetic,
2921

@@ -32,13 +24,126 @@ export const OperatorsMap: Record<Operators, OperationTypes> = {
3224
"==": OperationTypes.Comparison,
3325
"!=": OperationTypes.Comparison,
3426
"<>": OperationTypes.Comparison,
35-
"<" : OperationTypes.Comparison,
27+
"<": OperationTypes.Comparison,
3628
"<=": OperationTypes.Comparison,
3729

3830
"and": OperationTypes.Logical,
39-
"or" : OperationTypes.Logical,
31+
"or": OperationTypes.Logical,
4032
"not": OperationTypes.Logical,
33+
"not in": OperationTypes.Logical,
4134

42-
"in" : OperationTypes.Membership,
43-
"not in": OperationTypes.Logical
35+
"in": OperationTypes.Membership,
36+
37+
"=": OperationTypes.Assignment,
38+
"+=": OperationTypes.Assignment,
39+
"-=": OperationTypes.Assignment,
40+
"*=": OperationTypes.Assignment,
41+
"/=": OperationTypes.Assignment,
42+
"++": OperationTypes.Assignment,
43+
"--": OperationTypes.Assignment,
4444
};
45+
46+
export type Primitive = string | number | boolean | null;
47+
48+
export type ExpressionOperators = ArithmeticOperators | ComparisonOperators | LogicalOperators | MembershipOperators;
49+
type ExpressionOperation = (l: Primitive, r: Primitive) => Primitive;
50+
51+
export const OperationFuncs: Record<ExpressionOperators, ExpressionOperation> = {
52+
"+": (l, r) => arithmeticOperation(l, r, "+"),
53+
"-": (l, r) => arithmeticOperation(l, r, "-"),
54+
"/": (l, r) => arithmeticOperation(l, r, "/"),
55+
"*": (l, r) => arithmeticOperation(l, r, "*"),
56+
"%": (l, r) => arithmeticOperation(l, r, "%"),
57+
"**": (l, r) => arithmeticOperation(l, r, "**"),
58+
"//": (l, r) => arithmeticOperation(l, r, "//"),
59+
60+
">": (l, r) => comparissonOperation(l, r, ">"),
61+
">=": (l, r) => comparissonOperation(l, r, ">="),
62+
"<": (l, r) => comparissonOperation(l, r, "<"),
63+
"<=": (l, r) => comparissonOperation(l, r, "<="),
64+
"==": (l, r) => comparissonOperation(l, r, "=="),
65+
"!=": (l, r) => comparissonOperation(l, r, "!="),
66+
"<>": (l, r) => comparissonOperation(l, r, "<>"),
67+
68+
"and": (l, r) => logicalOperation(l, r, "and"),
69+
"or": (l, r) => logicalOperation(l, r, "or"),
70+
"not": (l, r) => logicalOperation(l, r, "not"),
71+
"not in": (l, r) => logicalOperation(l, r, "not in"),
72+
73+
"in": (l, r) => membershipOperation(l, r, "in")
74+
}
75+
76+
function membershipOperation(l: Primitive, r: Primitive, op: MembershipOperators): Primitive {
77+
if(typeof l === 'string'){
78+
return (l as string).includes(String(r));
79+
}
80+
81+
if(Array.isArray(l)){
82+
return (l as any[]).includes(r);
83+
}
84+
85+
throw new Error(`Unknown operation '${op}'`);
86+
}
87+
88+
function logicalOperation(l: Primitive, r: Primitive, op: LogicalOperators): Primitive {
89+
switch (op) {
90+
case 'and':
91+
return l as any && r as any;
92+
93+
case 'or':
94+
return (l as any) || (r as any);
95+
}
96+
throw new Error(`Unknown operation '${op}'`);
97+
}
98+
99+
function comparissonOperation(l: Primitive, r: Primitive, op: ComparisonOperators): Primitive {
100+
switch (op) {
101+
case '==':
102+
return l as any === r as any;
103+
104+
case '!=':
105+
return (l as any) !== (r as any);
106+
107+
case '<>':
108+
return (l as any) !== (r as any);
109+
110+
case '>':
111+
return (l as number) > (r as number);
112+
113+
case '<':
114+
return (l as number) < (r as number);
115+
116+
case '>=':
117+
return (l as number) >= (r as number);
118+
119+
case '<=':
120+
return (l as number) <= (r as number);
121+
}
122+
123+
throw new Error(`Unknown operation '${op}'`);
124+
}
125+
126+
function arithmeticOperation(l: Primitive, r: Primitive, op: ArithmeticOperators): Primitive {
127+
128+
switch (op) {
129+
case '+':
130+
return l as any + r as any;
131+
132+
case '-':
133+
return (l as any) - (r as any);
134+
135+
case '*':
136+
return (l as number) * (r as number);
137+
138+
case '/':
139+
return (l as number) / (r as number);
140+
141+
case '%':
142+
return (l as number) % (r as number);
143+
144+
case '**':
145+
return Math.pow(l as number, r as number);
146+
}
147+
148+
throw new Error(`Unknown operation '${op}'`);
149+
}

src/evaluator/evaluator.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,10 @@
11
import {
22
ArrowFuncDefNode,
33
AssignNode, AstBlock, AstNode, BinOpNode, BracketObjectAccessNode, ConstNode, CreateArrayNode,
4-
CreateObjectNode, DotObjectAccessNode, FunctionCallNode, FunctionDefNode, GetSingleVarNode, SetSingleVarNode
4+
CreateObjectNode, DotObjectAccessNode, FunctionCallNode, FunctionDefNode, GetSingleVarNode, OperationFuncs, Primitive, SetSingleVarNode
55
} from '../common';
66
import { Scope } from './scope';
77

8-
type Primitive = string | number | boolean | null;
9-
const OperationFuncs: Record<string, (l: Primitive, r: Primitive) => Primitive> = {
10-
"+": (l, r) => (l as number) + (r as number) as Primitive,
11-
"-": (l, r) => (l as number) - (r as number) as Primitive,
12-
"/": (l, r) => (l as number) / (r as number) as Primitive,
13-
"*": (l, r) => (l as number) * (r as number) as Primitive
14-
}
15-
168
export class Evaluator {
179

1810

src/interpreter.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,4 +190,21 @@ describe('Interpreter', () => {
190190
expect(e.evaluate(script)).toBe("32,64,96");
191191
});
192192

193+
it('arrow functions with filter', () => {
194+
const script = `
195+
arr = [1,2,3]
196+
arr.map(n =>
197+
n = n * 2
198+
{
199+
t1: n * 2,
200+
t2: n * 3
201+
}
202+
)
203+
.filter(v => (v.t1 > 10) or (v.t2 > 10))
204+
.map(r => r.t1 * r.t2)
205+
.join(',')
206+
`;
207+
expect(e.evaluate(script)).toBe("96,216");
208+
});
209+
193210
});

src/parser/parser.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {
22
BinOpNode, ConstNode, AstBlock, Token, ParserOptions, AstNode, Operators, AssignNode, TokenTypes,
33
GetSingleVarNode, FunctionCallNode, getTokenType, getTokenValue, isTokenTypeLiteral, getStartLine,
44
getStartColumn, getEndColumn, getEndLine, findOperators, splitTokens, DotObjectAccessNode, BracketObjectAccessNode,
5-
findTokenValueIndex, FunctionDefNode, CreateObjectNode, ObjectPropertyInfo, CreateArrayNode, ArrowFuncDefNode
5+
findTokenValueIndex, FunctionDefNode, CreateObjectNode, ObjectPropertyInfo, CreateArrayNode, ArrowFuncDefNode, ExpressionOperators
66
} from '../common';
77

88
export class InstructionLine {
@@ -222,14 +222,14 @@ export class Parser {
222222
const leftSlice = slice(tokens, 0, opIndex);
223223
prevNode = this.createExpressionNode(leftSlice);
224224
}
225-
prevNode = new BinOpNode(prevNode, op, rightNode)
225+
prevNode = new BinOpNode(prevNode, op as ExpressionOperators, rightNode)
226226

227227
} else {
228228
const leftSlice = prevNode ? [] : slice(tokens, 0, opIndex);
229229
const rightSlice = slice(tokens, opIndex + 1, nextOpIndex || tokens.length);
230230
const left = prevNode || this.createExpressionNode(leftSlice, prevNode);
231231
const right = this.createExpressionNode(rightSlice);
232-
prevNode = new BinOpNode(left, op, right);
232+
prevNode = new BinOpNode(left, op as ExpressionOperators, right);
233233
}
234234
}
235235

0 commit comments

Comments
 (0)