Lint the expressions package
This commit is contained in:
@@ -97,7 +97,7 @@ export class IndexAccess extends Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class Star extends Expr {
|
export class Star extends Expr {
|
||||||
accept<R>(v: ExprVisitor<R>): R {
|
accept<R>(): R {
|
||||||
throw new Error("Method not implemented.");
|
throw new Error("Method not implemented.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,9 @@ export function complete(
|
|||||||
extensionFunctions
|
extensionFunctions
|
||||||
);
|
);
|
||||||
const expr = p.parse();
|
const expr = p.parse();
|
||||||
|
if (!expr) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
const ev = new Evaluator(expr, context, functions);
|
const ev = new Evaluator(expr, context, functions);
|
||||||
const result = ev.evaluate();
|
const result = ev.evaluate();
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
|
import {Expr} from "./ast";
|
||||||
import * as data from "./data";
|
import * as data from "./data";
|
||||||
import {ExpressionEvaluationError} from "./errors";
|
import {ExpressionEvaluationError} from "./errors";
|
||||||
import {Evaluator} from "./evaluator";
|
import {Evaluator} from "./evaluator";
|
||||||
import {Lexer} from "./lexer";
|
import {Lexer} from "./lexer";
|
||||||
import {Parser} from "./parser";
|
import {Parser} from "./parser";
|
||||||
|
|
||||||
|
function assertDefined(x: Expr | undefined): asserts x is Expr {
|
||||||
|
expect(x).toBeDefined();
|
||||||
|
}
|
||||||
|
|
||||||
describe("evaluator", () => {
|
describe("evaluator", () => {
|
||||||
const lexAndParse = (input: string) => {
|
const lexAndParse = (input: string) => {
|
||||||
const lexer = new Lexer(input);
|
const lexer = new Lexer(input);
|
||||||
@@ -12,6 +17,7 @@ describe("evaluator", () => {
|
|||||||
// Parse
|
// Parse
|
||||||
const parser = new Parser(result.tokens, ["foo"], []);
|
const parser = new Parser(result.tokens, ["foo"], []);
|
||||||
const expr = parser.parse();
|
const expr = parser.parse();
|
||||||
|
assertDefined(expr);
|
||||||
return expr;
|
return expr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export class Evaluator implements ExprVisitor<data.ExpressionData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// result is always assigned before we return here
|
// result is always assigned before we return here
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
return result!;
|
return result!;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,6 +102,7 @@ export class Evaluator implements ExprVisitor<data.ExpressionData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
visitContextAccess(contextAccess: ContextAccess): data.ExpressionData {
|
visitContextAccess(contextAccess: ContextAccess): data.ExpressionData {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
const r = this.context.get(contextAccess.name.lexeme)!;
|
const r = this.context.get(contextAccess.name.lexeme)!;
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
@@ -114,7 +116,7 @@ export class Evaluator implements ExprVisitor<data.ExpressionData> {
|
|||||||
try {
|
try {
|
||||||
idxResult = this.eval(ia.index);
|
idxResult = this.eval(ia.index);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(`could not evaluate index for index access: ${e}`, {cause: e});
|
throw new Error(`could not evaluate index for index access: ${(e as Error).message}`, {cause: e});
|
||||||
}
|
}
|
||||||
idx = new idxHelper(false, idxResult);
|
idx = new idxHelper(false, idxResult);
|
||||||
}
|
}
|
||||||
@@ -124,9 +126,9 @@ export class Evaluator implements ExprVisitor<data.ExpressionData> {
|
|||||||
let result: data.ExpressionData;
|
let result: data.ExpressionData;
|
||||||
switch (objResult.kind) {
|
switch (objResult.kind) {
|
||||||
case data.Kind.Array: {
|
case data.Kind.Array: {
|
||||||
const tobjResult = objResult as data.Array;
|
const tobjResult = objResult;
|
||||||
if (tobjResult instanceof FilteredArray) {
|
if (tobjResult instanceof FilteredArray) {
|
||||||
result = filteredArrayAccess(tobjResult as FilteredArray, idx);
|
result = filteredArrayAccess(tobjResult, idx);
|
||||||
} else {
|
} else {
|
||||||
result = arrayAccess(tobjResult, idx);
|
result = arrayAccess(tobjResult, idx);
|
||||||
}
|
}
|
||||||
@@ -135,7 +137,7 @@ export class Evaluator implements ExprVisitor<data.ExpressionData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case data.Kind.Dictionary: {
|
case data.Kind.Dictionary: {
|
||||||
const tobjResult = objResult as data.Dictionary;
|
const tobjResult = objResult;
|
||||||
result = objectAccess(tobjResult, idx);
|
result = objectAccess(tobjResult, idx);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -170,7 +172,7 @@ function filteredArrayAccess(fa: FilteredArray, idx: idxHelper): data.Expression
|
|||||||
// Check the type of the nested item
|
// Check the type of the nested item
|
||||||
switch (item.kind) {
|
switch (item.kind) {
|
||||||
case data.Kind.Dictionary: {
|
case data.Kind.Dictionary: {
|
||||||
const ti = item as data.Dictionary;
|
const ti = item;
|
||||||
if (idx.star) {
|
if (idx.star) {
|
||||||
for (const v of ti.values()) {
|
for (const v of ti.values()) {
|
||||||
result.add(v);
|
result.add(v);
|
||||||
@@ -186,7 +188,7 @@ function filteredArrayAccess(fa: FilteredArray, idx: idxHelper): data.Expression
|
|||||||
}
|
}
|
||||||
|
|
||||||
case data.Kind.Array: {
|
case data.Kind.Array: {
|
||||||
const ti = item as data.Array;
|
const ti = item;
|
||||||
if (idx.star) {
|
if (idx.star) {
|
||||||
for (const v of ti.values()) {
|
for (const v of ti.values()) {
|
||||||
result.add(v);
|
result.add(v);
|
||||||
|
|||||||
@@ -5,12 +5,15 @@ export class idxHelper {
|
|||||||
public readonly int: number | undefined;
|
public readonly int: number | undefined;
|
||||||
|
|
||||||
constructor(public readonly star: boolean, idx: ExpressionData | undefined) {
|
constructor(public readonly star: boolean, idx: ExpressionData | undefined) {
|
||||||
|
if (!idx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!star) {
|
if (!star) {
|
||||||
if (idx!.primitive) {
|
if (idx.primitive) {
|
||||||
this.str = idx!.coerceString();
|
this.str = idx.coerceString();
|
||||||
}
|
}
|
||||||
|
|
||||||
let f = idx!.number();
|
let f = idx.number();
|
||||||
if (!isNaN(f) && isFinite(f) && f >= 0) {
|
if (!isNaN(f) && isFinite(f) && f >= 0) {
|
||||||
f = Math.floor(f);
|
f = Math.floor(f);
|
||||||
this.int = f;
|
this.int = f;
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ export function tokenString(tok: Token): string {
|
|||||||
case TokenType.NUMBER:
|
case TokenType.NUMBER:
|
||||||
return tok.lexeme;
|
return tok.lexeme;
|
||||||
case TokenType.STRING:
|
case TokenType.STRING:
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
return tok.value!.toString();
|
return tok.value!.toString();
|
||||||
default:
|
default:
|
||||||
return tok.lexeme;
|
return tok.lexeme;
|
||||||
|
|||||||
+10
-11
@@ -9,8 +9,8 @@ export class Parser {
|
|||||||
private extContexts: Map<string, boolean>;
|
private extContexts: Map<string, boolean>;
|
||||||
private extFuncs: Map<string, FunctionInfo>;
|
private extFuncs: Map<string, FunctionInfo>;
|
||||||
|
|
||||||
private offset: number = 0;
|
private offset = 0;
|
||||||
private depth: number = 0;
|
private depth = 0;
|
||||||
|
|
||||||
private context: ParseContext;
|
private context: ParseContext;
|
||||||
|
|
||||||
@@ -43,15 +43,13 @@ export class Parser {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public parse(): Expr {
|
public parse(): Expr | undefined {
|
||||||
let result!: Expr;
|
|
||||||
|
|
||||||
// No tokens
|
// No tokens
|
||||||
if (this.atEnd()) {
|
if (this.atEnd()) {
|
||||||
return result;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = this.expression();
|
const result = this.expression();
|
||||||
|
|
||||||
if (!this.atEnd()) {
|
if (!this.atEnd()) {
|
||||||
throw this.buildError(ErrorType.ErrorUnexpectedSymbol, this.peek());
|
throw this.buildError(ErrorType.ErrorUnexpectedSymbol, this.peek());
|
||||||
@@ -173,7 +171,7 @@ export class Parser {
|
|||||||
let cont = true;
|
let cont = true;
|
||||||
while (cont) {
|
while (cont) {
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case this.match(TokenType.LEFT_BRACKET):
|
case this.match(TokenType.LEFT_BRACKET): {
|
||||||
let indexExpr: Expr;
|
let indexExpr: Expr;
|
||||||
if (this.match(TokenType.STAR)) {
|
if (this.match(TokenType.STAR)) {
|
||||||
indexExpr = new Star();
|
indexExpr = new Star();
|
||||||
@@ -188,6 +186,7 @@ export class Parser {
|
|||||||
depthIncreased++;
|
depthIncreased++;
|
||||||
expr = new IndexAccess(expr, indexExpr);
|
expr = new IndexAccess(expr, indexExpr);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case this.match(TokenType.DOT):
|
case this.match(TokenType.DOT):
|
||||||
// Track depth
|
// Track depth
|
||||||
@@ -195,7 +194,7 @@ export class Parser {
|
|||||||
depthIncreased++;
|
depthIncreased++;
|
||||||
|
|
||||||
if (this.match(TokenType.IDENTIFIER)) {
|
if (this.match(TokenType.IDENTIFIER)) {
|
||||||
let property = this.previous();
|
const property = this.previous();
|
||||||
expr = new IndexAccess(expr, new Literal(new data.StringData(property.lexeme), property));
|
expr = new IndexAccess(expr, new Literal(new data.StringData(property.lexeme), property));
|
||||||
} else if (this.match(TokenType.STAR)) {
|
} else if (this.match(TokenType.STAR)) {
|
||||||
expr = new IndexAccess(expr, new Star());
|
expr = new IndexAccess(expr, new Star());
|
||||||
@@ -268,7 +267,7 @@ export class Parser {
|
|||||||
case this.match(TokenType.STRING):
|
case this.match(TokenType.STRING):
|
||||||
return new Literal(new data.StringData(this.previous().value as string), this.previous());
|
return new Literal(new data.StringData(this.previous().value as string), this.previous());
|
||||||
|
|
||||||
case this.match(TokenType.LEFT_PAREN):
|
case this.match(TokenType.LEFT_PAREN): {
|
||||||
const expr = this.expression();
|
const expr = this.expression();
|
||||||
|
|
||||||
if (this.atEnd()) {
|
if (this.atEnd()) {
|
||||||
@@ -277,7 +276,7 @@ export class Parser {
|
|||||||
|
|
||||||
this.consume(TokenType.RIGHT_PAREN, ErrorType.ErrorUnexpectedSymbol);
|
this.consume(TokenType.RIGHT_PAREN, ErrorType.ErrorUnexpectedSymbol);
|
||||||
return new Grouping(expr);
|
return new Grouping(expr);
|
||||||
|
}
|
||||||
case this.atEnd():
|
case this.atEnd():
|
||||||
throw this.buildError(ErrorType.ErrorUnexpectedEndOfExpression, this.previous()); // Back up to get the last token before the EOF
|
throw this.buildError(ErrorType.ErrorUnexpectedEndOfExpression, this.previous()); // Back up to get the last token before the EOF
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-14
@@ -8,10 +8,10 @@ export function falsy(d: data.ExpressionData): boolean {
|
|||||||
case data.Kind.Boolean:
|
case data.Kind.Boolean:
|
||||||
return !d.value;
|
return !d.value;
|
||||||
|
|
||||||
case data.Kind.Number:
|
case data.Kind.Number: {
|
||||||
const dv = d.value;
|
const dv = d.value;
|
||||||
return dv === 0 || isNaN(dv);
|
return dv === 0 || isNaN(dv);
|
||||||
|
}
|
||||||
case data.Kind.String:
|
case data.Kind.String:
|
||||||
return d.value.length === 0;
|
return d.value.length === 0;
|
||||||
}
|
}
|
||||||
@@ -77,7 +77,7 @@ export function coerceTypes(
|
|||||||
// Similar to the Javascript abstract equality comparison algorithm http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3.
|
// Similar to the Javascript abstract equality comparison algorithm http://www.ecma-international.org/ecma-262/5.1/#sec-11.9.3.
|
||||||
// Except string comparison is OrdinalIgnoreCase, and objects are not coerced to primitives.
|
// Except string comparison is OrdinalIgnoreCase, and objects are not coerced to primitives.
|
||||||
export function equals(lhs: data.ExpressionData, rhs: data.ExpressionData): boolean {
|
export function equals(lhs: data.ExpressionData, rhs: data.ExpressionData): boolean {
|
||||||
let [lv, rv] = coerceTypes(lhs, rhs);
|
const [lv, rv] = coerceTypes(lhs, rhs);
|
||||||
|
|
||||||
if (lv.kind != rv.kind) {
|
if (lv.kind != rv.kind) {
|
||||||
return false;
|
return false;
|
||||||
@@ -89,7 +89,7 @@ export function equals(lhs: data.ExpressionData, rhs: data.ExpressionData): bool
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Number, Number
|
// Number, Number
|
||||||
case data.Kind.Number:
|
case data.Kind.Number: {
|
||||||
const ld = lv.value;
|
const ld = lv.value;
|
||||||
const rd = (rv as data.NumberData).value;
|
const rd = (rv as data.NumberData).value;
|
||||||
if (isNaN(ld) || isNaN(rd)) {
|
if (isNaN(ld) || isNaN(rd)) {
|
||||||
@@ -97,18 +97,21 @@ export function equals(lhs: data.ExpressionData, rhs: data.ExpressionData): bool
|
|||||||
}
|
}
|
||||||
|
|
||||||
return ld == rd;
|
return ld == rd;
|
||||||
|
}
|
||||||
|
|
||||||
// String, String
|
// String, String
|
||||||
case data.Kind.String:
|
case data.Kind.String: {
|
||||||
const ls = lv.value;
|
const ls = lv.value;
|
||||||
const rs = (rv as data.StringData).value;
|
const rs = (rv as data.StringData).value;
|
||||||
return toUpperSpecial(ls) === toUpperSpecial(rs);
|
return toUpperSpecial(ls) === toUpperSpecial(rs);
|
||||||
|
}
|
||||||
|
|
||||||
// Boolean, Boolean
|
// Boolean, Boolean
|
||||||
case data.Kind.Boolean:
|
case data.Kind.Boolean: {
|
||||||
const lb = lv.value;
|
const lb = lv.value;
|
||||||
const rb = (rv as data.BooleanData).value;
|
const rb = (rv as data.BooleanData).value;
|
||||||
return lb == rb;
|
return lb == rb;
|
||||||
|
}
|
||||||
|
|
||||||
// Object, Object
|
// Object, Object
|
||||||
case data.Kind.Dictionary:
|
case data.Kind.Dictionary:
|
||||||
@@ -131,7 +134,7 @@ export function greaterThan(lhs: data.ExpressionData, rhs: data.ExpressionData):
|
|||||||
|
|
||||||
switch (lv.kind) {
|
switch (lv.kind) {
|
||||||
// Number, Number
|
// Number, Number
|
||||||
case data.Kind.Number:
|
case data.Kind.Number: {
|
||||||
const lf = lv.value;
|
const lf = lv.value;
|
||||||
const rf = (rv as data.NumberData).value;
|
const rf = (rv as data.NumberData).value;
|
||||||
if (isNaN(lf) || isNaN(rf)) {
|
if (isNaN(lf) || isNaN(rf)) {
|
||||||
@@ -139,20 +142,23 @@ export function greaterThan(lhs: data.ExpressionData, rhs: data.ExpressionData):
|
|||||||
}
|
}
|
||||||
|
|
||||||
return lf > rf;
|
return lf > rf;
|
||||||
|
}
|
||||||
|
|
||||||
// String, String
|
// String, String
|
||||||
case data.Kind.String:
|
case data.Kind.String: {
|
||||||
let ls = lv.value;
|
let ls = lv.value;
|
||||||
let rs = (rv as data.StringData).value;
|
let rs = (rv as data.StringData).value;
|
||||||
ls = toUpperSpecial(ls);
|
ls = toUpperSpecial(ls);
|
||||||
rs = toUpperSpecial(rs);
|
rs = toUpperSpecial(rs);
|
||||||
return ls > rs;
|
return ls > rs;
|
||||||
|
}
|
||||||
|
|
||||||
// Boolean, Boolean
|
// Boolean, Boolean
|
||||||
case data.Kind.Boolean:
|
case data.Kind.Boolean: {
|
||||||
const lb = (lv as data.BooleanData).value;
|
const lb = lv.value;
|
||||||
const rb = (rv as data.BooleanData).value;
|
const rb = (rv as data.BooleanData).value;
|
||||||
return lb && !rb;
|
return lb && !rb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -169,7 +175,7 @@ export function lessThan(lhs: data.ExpressionData, rhs: data.ExpressionData): bo
|
|||||||
|
|
||||||
switch (lv.kind) {
|
switch (lv.kind) {
|
||||||
// Number, Number
|
// Number, Number
|
||||||
case data.Kind.Number:
|
case data.Kind.Number: {
|
||||||
const lf = lv.value;
|
const lf = lv.value;
|
||||||
const rf = (rv as data.NumberData).value;
|
const rf = (rv as data.NumberData).value;
|
||||||
if (isNaN(lf) || isNaN(rf)) {
|
if (isNaN(lf) || isNaN(rf)) {
|
||||||
@@ -177,20 +183,23 @@ export function lessThan(lhs: data.ExpressionData, rhs: data.ExpressionData): bo
|
|||||||
}
|
}
|
||||||
|
|
||||||
return lf < rf;
|
return lf < rf;
|
||||||
|
}
|
||||||
|
|
||||||
// String, String
|
// String, String
|
||||||
case data.Kind.String:
|
case data.Kind.String: {
|
||||||
let ls = lv.value;
|
let ls = lv.value;
|
||||||
let rs = (rv as data.StringData).value;
|
let rs = (rv as data.StringData).value;
|
||||||
ls = toUpperSpecial(ls);
|
ls = toUpperSpecial(ls);
|
||||||
rs = toUpperSpecial(rs);
|
rs = toUpperSpecial(rs);
|
||||||
return ls < rs;
|
return ls < rs;
|
||||||
|
}
|
||||||
|
|
||||||
// Boolean, Boolean
|
// Boolean, Boolean
|
||||||
case data.Kind.Boolean:
|
case data.Kind.Boolean: {
|
||||||
const lb = lv.value;
|
const lb = lv.value;
|
||||||
const rb = (rv as data.BooleanData).value;
|
const rb = (rv as data.BooleanData).value;
|
||||||
return !lb && rb;
|
return !lb && rb;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@@ -200,7 +209,7 @@ export function lessThan(lhs: data.ExpressionData, rhs: data.ExpressionData): bo
|
|||||||
export function toUpperSpecial(s: string): string {
|
export function toUpperSpecial(s: string): string {
|
||||||
const sb: string[] = [];
|
const sb: string[] = [];
|
||||||
let i = 0;
|
let i = 0;
|
||||||
let len = s.length;
|
const len = s.length;
|
||||||
let found = s.indexOf("ı");
|
let found = s.indexOf("ı");
|
||||||
while (i < len) {
|
while (i < len) {
|
||||||
if (i < found) {
|
if (i < found) {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ interface TestCase {
|
|||||||
options: TestOptions;
|
options: TestOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
function testCaseReviver(key: string, val: any): any {
|
function testCaseReviver(key: string, val: unknown): unknown {
|
||||||
if (key === "contexts") {
|
if (key === "contexts") {
|
||||||
const tmp = JSON.stringify(val);
|
const tmp = JSON.stringify(val);
|
||||||
return JSON.parse(tmp, reviver);
|
return JSON.parse(tmp, reviver);
|
||||||
@@ -105,27 +105,28 @@ describe("x-lang tests", () => {
|
|||||||
if (testCase.err && testCase.err.kind === TestErrorKind.Lexing) {
|
if (testCase.err && testCase.err.kind === TestErrorKind.Lexing) {
|
||||||
throw new Error("expected error lexing expression, but got none");
|
throw new Error("expected error lexing expression, but got none");
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e) {
|
||||||
|
const err = e as Error;
|
||||||
// Did test expect lexing error? If so, compare error message.
|
// Did test expect lexing error? If so, compare error message.
|
||||||
if (testCase.err && testCase.err.kind === TestErrorKind.Lexing) {
|
if (testCase.err && testCase.err.kind === TestErrorKind.Lexing) {
|
||||||
expect(e.message).toContain(testCase.err.value);
|
expect(err.message).toContain(testCase.err.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`unexpected error lexing expression: ${e.message} ${e.stack}`);
|
throw new Error(`unexpected error lexing expression: ${err.message} ${err.stack || ""}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse
|
// Parse
|
||||||
const contextNames = testCase.contexts.pairs().map(x => x.key);
|
const contextNames = testCase.contexts.pairs().map(x => x.key);
|
||||||
const parser = new Parser(result.tokens, contextNames, []);
|
const parser = new Parser(result.tokens, contextNames, []);
|
||||||
let expr: Expr;
|
let expr: Expr | undefined;
|
||||||
try {
|
try {
|
||||||
expr = parser.parse();
|
expr = parser.parse();
|
||||||
|
|
||||||
if (testCase.err?.kind === TestErrorKind.Parsing) {
|
if (testCase.err?.kind === TestErrorKind.Parsing) {
|
||||||
throw new Error("expected error parsing expression, but got none");
|
throw new Error("expected error parsing expression, but got none");
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e) {
|
||||||
// Did test expect parsing error?
|
// Did test expect parsing error?
|
||||||
if (testCase.err?.kind === TestErrorKind.Parsing) {
|
if (testCase.err?.kind === TestErrorKind.Parsing) {
|
||||||
// Test expects parsing error
|
// Test expects parsing error
|
||||||
@@ -133,8 +134,8 @@ describe("x-lang tests", () => {
|
|||||||
expect(errorWithExpression(pe, testCase.expr)).toContain(testCase.err.value);
|
expect(errorWithExpression(pe, testCase.expr)).toContain(testCase.err.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const err = e as Error;
|
||||||
throw new Error(`unexpected error parsing expression: ${e.message} ${e.stack}`);
|
throw new Error(`unexpected error parsing expression: ${err.message} ${err.stack || ""}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate expression
|
// Evaluate expression
|
||||||
@@ -154,14 +155,15 @@ describe("x-lang tests", () => {
|
|||||||
expect(kindStr(result.kind)).toBe(testCase.result.kind);
|
expect(kindStr(result.kind)).toBe(testCase.result.kind);
|
||||||
|
|
||||||
expect(JSON.stringify(result, replacer)).toEqual(JSON.stringify(testCase.result.value, replacer));
|
expect(JSON.stringify(result, replacer)).toEqual(JSON.stringify(testCase.result.value, replacer));
|
||||||
} catch (e: any) {
|
} catch (e) {
|
||||||
if (testCase.err?.kind === TestErrorKind.Evaluation) {
|
if (testCase.err?.kind === TestErrorKind.Evaluation) {
|
||||||
const pe = e as ExpressionError;
|
const pe = e as ExpressionError;
|
||||||
expect(errorWithExpression(pe, testCase.expr)).toContain(testCase.err.value);
|
expect(errorWithExpression(pe, testCase.expr)).toContain(testCase.err.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Error(`unexpected error evaluating expression: ${e.message} ${e.stack}`);
|
const err = e as Error;
|
||||||
|
throw new Error(`unexpected error evaluating expression: ${err.message} ${err.stack || ""}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user