@akala/core
Version:
216 lines (172 loc) • 6.31 kB
text/typescript
import ErrorWithStatus from "../../../errorWithStatus.js";
import { FormatExpression } from "../../parser.js";
import { ApplySymbolExpression } from "../apply-symbol-expression.js";
import { BinaryExpression } from "../binary-expression.js";
import { CallExpression } from "../call-expression.js";
import { ConstantExpression } from "../constant-expression.js";
import type { Expressions, StrictExpressions } from "../expression.js";
import { TypedLambdaExpression } from "../lambda-expression.js";
import { MemberExpression } from "../member-expression.js";
import { NewExpression } from "../new-expression.js";
import { ParameterExpression } from "../parameter-expression.js";
import { TernaryExpression } from "../ternary-expression.js";
import { UnaryExpression } from "../unary-expression.js";
import { ExpressionVisitor } from "./expression-visitor.js";
/**
* Compares two expressions.
* @param {any} expr1 - The first expression.
* @param {any} expr2 - The second expression.
* @returns {boolean} True if the expressions are equal, false otherwise.
*/
export class ExpressionComparer extends ExpressionVisitor
{
constructor(private source: Expressions)
{
super();
}
public static equals(exp1: Expressions, exp2: Expressions): boolean
{
if (exp1.type != exp2.type)
{
debugger;
return false;
}
try
{
new ExpressionComparer(exp1).visit(exp2);
}
catch (e)
{
if (e.statusCode == 400)
return false;
throw e;
}
return true;
}
visitMember<T, TMember extends keyof T>(arg0: MemberExpression<T, TMember, T[TMember]>): StrictExpressions
{
if (this.source.type != arg0.type)
throw new ErrorWithStatus(400);
const exp1 = this.source;
if (arg0.source)
{
this.source = arg0.source;
this.visit(arg0.source);
}
else if (this.source.source)
throw new ErrorWithStatus(400);
this.source = exp1.member;
this.visit(arg0.member);
return arg0;
}
visitApplySymbol<T, U>(arg0: ApplySymbolExpression<T, U>): StrictExpressions
{
const exp = this.source;
if (exp.type != arg0.type)
throw new ErrorWithStatus(400);
this.source = exp.source;
this.visit(arg0.source);
this.source = exp.argument;
this.visit(arg0.argument);
return arg0;
}
visitBinary<T extends Expressions = StrictExpressions>(expression: BinaryExpression<T>): BinaryExpression<Expressions>
{
const exp = this.source;
if (exp.type != expression.type)
throw new ErrorWithStatus(400);
this.source = exp.left;
this.visit(expression.left);
this.source = exp.right;
this.visit(expression.right);
return expression;
}
visitCall<T, TMethod extends keyof T>(arg0: CallExpression<T, TMethod>): StrictExpressions
{
const exp = this.source;
if (exp.type != arg0.type)
throw new ErrorWithStatus(400);
this.source = exp.source;
this.visit(arg0.source);
if (arg0.arguments.length != exp.arguments.length)
throw new ErrorWithStatus(400);
this.visitArray(arg0.arguments as StrictExpressions[], (_, i) => this.source = exp.arguments[i]);
return arg0;
}
visitConstant(arg0: ConstantExpression<unknown>): StrictExpressions
{
if (this.source.type != arg0.type)
throw new ErrorWithStatus(400);
if (arg0.value != this.source.value)
throw new ErrorWithStatus(400);
return arg0;
}
visitFormat<TOutput>(expression: FormatExpression<TOutput>): FormatExpression<TOutput>
{
const exp = this.source;
if (exp.type != expression.type)
throw new ErrorWithStatus(400);
if (exp.formatter != expression.formatter)
throw new ErrorWithStatus(400);
this.source = exp.lhs;
this.visit(expression.lhs);
this.source = exp.settings;
if (expression.settings)
this.visit(expression.settings);
else if (this.source)
throw new ErrorWithStatus(400);
return expression;
}
visitLambda<T extends (...args: unknown[]) => unknown>(arg0: TypedLambdaExpression<T>): StrictExpressions
{
const exp = this.source;
if (exp.type != arg0.type)
throw new ErrorWithStatus(400);
if (arg0.parameters.length != exp.parameters.length)
throw new ErrorWithStatus(400);
this.visitArray(arg0.parameters as Expressions[], (e, i) => this.source = exp.parameters[i]);
this.source = exp.body;
this.visit(arg0.body);
return arg0;
}
visitNew<T>(arg0: NewExpression<T>): StrictExpressions
{
const exp = this.source;
if (exp.type != arg0.type)
throw new ErrorWithStatus(400);
this.visitArray(arg0.init as Expressions[], (e, i) => this.source = exp.init[i]);
return arg0;
}
visitParameter(arg0: ParameterExpression<unknown>): StrictExpressions
{
if (this.source.type != arg0.type)
throw new ErrorWithStatus(400);
if (arg0.name != this.source.name)
throw new ErrorWithStatus(400);
return arg0;
}
visitTernary<T extends Expressions = StrictExpressions>(arg0: TernaryExpression<T>): TernaryExpression<Expressions>
{
const exp = this.source;
if (exp.type != arg0.type)
throw new ErrorWithStatus(400);
this.source = exp.first;
this.visit(arg0.first);
this.source = exp.second;
this.visit(arg0.second);
this.source = exp.third;
this.visit(arg0.third);
return super.visitTernary(arg0);
}
visitUnary(arg0: UnaryExpression): Expressions
{
const exp = this.source;
if (exp.type != arg0.type)
throw new ErrorWithStatus(400);
if (exp.operator != arg0.operator)
throw new ErrorWithStatus(400);
this.source = exp.operand;
this.visit(arg0.operand);
return arg0;
}
}