From 976bb71c3cb6250cf8bdf46784da86d53ee4fdb1 Mon Sep 17 00:00:00 2001 From: Sam Cao Date: Sat, 30 Nov 2024 10:10:24 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=A6=84=20refactor:=20Redesign=20ast=2014?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ts2java/ast/enums/Ts2JavaAstBinaryOp.java | 192 ++++++++++++++++++ .../ts2java/ast/expr/Ts2JavaAstBinExpr.java | 102 ++++++++++ .../ast/interfaces/ITs2JavaAstExpr.java | 5 +- .../ts2java/ast/TestBasicOperations.java | 95 --------- .../ast/expr/TestTs2JavaAstBinExpr.java | 122 +++++++++++ 5 files changed, 420 insertions(+), 96 deletions(-) create mode 100644 src/main/java/com/caoccao/javet/buddy/ts2java/ast/enums/Ts2JavaAstBinaryOp.java create mode 100644 src/main/java/com/caoccao/javet/buddy/ts2java/ast/expr/Ts2JavaAstBinExpr.java create mode 100644 src/test/java/com/caoccao/javet/buddy/ts2java/ast/expr/TestTs2JavaAstBinExpr.java diff --git a/src/main/java/com/caoccao/javet/buddy/ts2java/ast/enums/Ts2JavaAstBinaryOp.java b/src/main/java/com/caoccao/javet/buddy/ts2java/ast/enums/Ts2JavaAstBinaryOp.java new file mode 100644 index 0000000..ed6c9a9 --- /dev/null +++ b/src/main/java/com/caoccao/javet/buddy/ts2java/ast/enums/Ts2JavaAstBinaryOp.java @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2024. caoccao.com Sam Cao + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.caoccao.javet.buddy.ts2java.ast.enums; + +import com.caoccao.javet.buddy.ts2java.exceptions.Ts2JavaException; +import com.caoccao.javet.swc4j.ast.enums.Swc4jAstBinaryOp; +import com.caoccao.javet.utils.SimpleFreeMarkerFormat; +import com.caoccao.javet.utils.SimpleMap; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.Implementation; +import net.bytebuddy.implementation.bytecode.*; +import net.bytebuddy.jar.asm.MethodVisitor; +import net.bytebuddy.jar.asm.Opcodes; + +public final class Ts2JavaAstBinaryOp { + public static final String JAVA_LANG_MATH = "java/lang/Math"; + + private Ts2JavaAstBinaryOp() { + } + + private static Addition getAddition(TypeDescription type) { + if (type.represents(int.class)) { + return Addition.INTEGER; + } else if (type.represents(long.class)) { + return Addition.LONG; + } else if (type.represents(float.class)) { + return Addition.FLOAT; + } else if (type.represents(double.class)) { + return Addition.DOUBLE; + } + throw new Ts2JavaException( + SimpleFreeMarkerFormat.format("Unsupported type ${type} in addition.", + SimpleMap.of("type", type.getName()))); + } + + public static StackManipulation getArithmeticStackManipulation(Swc4jAstBinaryOp binaryOp, TypeDescription type) { + switch (binaryOp) { + case Add: + return getAddition(type); + case Div: + return getDivision(type); + case LShift: + return getShiftLeft(type); + case Mod: + return getRemainder(type); + case Mul: + return getMultiplication(type); + case RShift: + return getShiftRight(type); + case Sub: + return getSubtraction(type); + case ZeroFillRShift: + return getZeroFillShiftRight(type); + case Exp: + return getExp(); + default: + throw new Ts2JavaException( + SimpleFreeMarkerFormat.format("Binary op ${op} is not supported.", + SimpleMap.of("op", binaryOp.name()))); + } + } + + private static Division getDivision(TypeDescription type) { + if (type.represents(int.class)) { + return Division.INTEGER; + } else if (type.represents(long.class)) { + return Division.LONG; + } else if (type.represents(float.class)) { + return Division.FLOAT; + } else if (type.represents(double.class)) { + return Division.DOUBLE; + } + throw new Ts2JavaException( + SimpleFreeMarkerFormat.format("Unsupported type ${type} in division.", + SimpleMap.of("type", type.getName()))); + } + + private static StackManipulation getExp() { + return new StackManipulation.Simple(( + MethodVisitor methodVisitor, + Implementation.Context implementationContext) -> { + methodVisitor.visitMethodInsn( + Opcodes.INVOKESTATIC, + JAVA_LANG_MATH, + "pow", + "(DD)D", + false); + return new StackManipulation.Size(-2, 0); + }); + } + + private static Multiplication getMultiplication(TypeDescription type) { + if (type.represents(int.class)) { + return Multiplication.INTEGER; + } else if (type.represents(long.class)) { + return Multiplication.LONG; + } else if (type.represents(float.class)) { + return Multiplication.FLOAT; + } else if (type.represents(double.class)) { + return Multiplication.DOUBLE; + } + throw new Ts2JavaException( + SimpleFreeMarkerFormat.format("Unsupported type ${type} in multiplication.", + SimpleMap.of("type", type.getName()))); + } + + private static Remainder getRemainder(TypeDescription type) { + if (type.represents(int.class)) { + return Remainder.INTEGER; + } else if (type.represents(long.class)) { + return Remainder.LONG; + } else if (type.represents(float.class)) { + return Remainder.FLOAT; + } else if (type.represents(double.class)) { + return Remainder.DOUBLE; + } + throw new Ts2JavaException( + SimpleFreeMarkerFormat.format("Unsupported type ${type} in mod.", + SimpleMap.of("type", type.getName()))); + } + + private static ShiftLeft getShiftLeft(TypeDescription type) { + if (type.represents(int.class)) { + return ShiftLeft.INTEGER; + } else if (type.represents(long.class)) { + return ShiftLeft.LONG; + } + throw new Ts2JavaException( + SimpleFreeMarkerFormat.format("Unsupported type ${type} in left shift.", + SimpleMap.of("type", type.getName()))); + } + + private static ShiftRight getShiftRight(TypeDescription type) { + if (type.represents(int.class)) { + return ShiftRight.INTEGER; + } else if (type.represents(long.class)) { + return ShiftRight.LONG; + } + throw new Ts2JavaException( + SimpleFreeMarkerFormat.format("Unsupported type ${type} in right shift.", + SimpleMap.of("type", type.getName()))); + } + + private static Subtraction getSubtraction(TypeDescription type) { + if (type.represents(int.class)) { + return Subtraction.INTEGER; + } else if (type.represents(long.class)) { + return Subtraction.LONG; + } else if (type.represents(float.class)) { + return Subtraction.FLOAT; + } else if (type.represents(double.class)) { + return Subtraction.DOUBLE; + } + throw new Ts2JavaException( + SimpleFreeMarkerFormat.format("Unsupported type ${type} in subtraction.", + SimpleMap.of("type", type.getName()))); + } + + private static StackManipulation getZeroFillShiftRight(TypeDescription type) { + if (type.represents(int.class)) { + return new StackManipulation.Simple( + (MethodVisitor methodVisitor, Implementation.Context implementationContext) -> { + methodVisitor.visitInsn(Opcodes.IUSHR); + return new StackManipulation.Size(-1, 0); + }); + } else if (type.represents(long.class)) { + return new StackManipulation.Simple( + (MethodVisitor methodVisitor, Implementation.Context implementationContext) -> { + methodVisitor.visitInsn(Opcodes.L2I); + methodVisitor.visitInsn(Opcodes.LUSHR); + return new StackManipulation.Size(-2, 0); + }); + } + throw new Ts2JavaException( + SimpleFreeMarkerFormat.format("Unsupported type ${type} in zero fill right shift.", + SimpleMap.of("type", type.getName()))); + } +} diff --git a/src/main/java/com/caoccao/javet/buddy/ts2java/ast/expr/Ts2JavaAstBinExpr.java b/src/main/java/com/caoccao/javet/buddy/ts2java/ast/expr/Ts2JavaAstBinExpr.java new file mode 100644 index 0000000..bb11b51 --- /dev/null +++ b/src/main/java/com/caoccao/javet/buddy/ts2java/ast/expr/Ts2JavaAstBinExpr.java @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2024. caoccao.com Sam Cao + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.caoccao.javet.buddy.ts2java.ast.expr; + +import com.caoccao.javet.buddy.ts2java.ast.BaseTs2JavaAst; +import com.caoccao.javet.buddy.ts2java.ast.enums.Ts2JavaAstBinaryOp; +import com.caoccao.javet.buddy.ts2java.ast.interfaces.ITs2JavaAst; +import com.caoccao.javet.buddy.ts2java.ast.interfaces.ITs2JavaAstExpr; +import com.caoccao.javet.buddy.ts2java.ast.memo.Ts2JavaMemoFunction; +import com.caoccao.javet.buddy.ts2java.compiler.JavaClassCast; +import com.caoccao.javet.buddy.ts2java.exceptions.Ts2JavaAstException; +import com.caoccao.javet.swc4j.ast.enums.Swc4jAstBinaryOp; +import com.caoccao.javet.swc4j.ast.expr.Swc4jAstBinExpr; +import com.caoccao.javet.utils.SimpleFreeMarkerFormat; +import com.caoccao.javet.utils.SimpleMap; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.implementation.Implementation; +import net.bytebuddy.implementation.bytecode.StackManipulation; +import net.bytebuddy.jar.asm.MethodVisitor; + +public class Ts2JavaAstBinExpr + extends BaseTs2JavaAst + implements ITs2JavaAstExpr { + protected final ITs2JavaAstExpr left; + protected final ITs2JavaAstExpr right; + protected Swc4jAstBinaryOp op; + + public Ts2JavaAstBinExpr( + ITs2JavaAst parent, + Swc4jAstBinExpr ast, + TypeDescription type, + Ts2JavaMemoFunction memo) { + super(parent, ast, memo); + op = ast.getOp(); + if (op.isArithmeticOperator()) { + this.type = type; + } else if (op.isLogicalCompareOperator()) { + this.type = TypeDescription.ForLoadedType.of(void.class); + } else if (op.isLogicalConditionOperator()) { + this.type = TypeDescription.ForLoadedType.of(boolean.class); + } + left = ITs2JavaAstExpr.cast(parent, ast.getLeft(), this.type, memo); + right = ITs2JavaAstExpr.cast(parent, ast.getRight(), this.type, memo); + } + + @Override + public Size apply(MethodVisitor methodVisitor, Implementation.Context context) { + visitLineNumber(methodVisitor); + Size sizeLoadLeft = left.apply(methodVisitor, context); + Size sizeCastLeft = JavaClassCast.getUpCastStackManipulation(left.getType(), type) + .map(s -> s.apply(methodVisitor, context)) + .orElse(Size.ZERO); + Size sizeLoadRight = right.apply(methodVisitor, context); + Size sizeCastRight = JavaClassCast.getUpCastStackManipulation(right.getType(), type) + .map(s -> s.apply(methodVisitor, context)) + .orElse(Size.ZERO); + Size sizeLoadAndCast = aggregateSize(sizeLoadLeft, sizeCastLeft, sizeLoadRight, sizeCastRight); + StackManipulation stackManipulation; + if (op.isArithmeticOperator()) { + stackManipulation = Ts2JavaAstBinaryOp.getArithmeticStackManipulation(op, type); + } else { + throw new Ts2JavaAstException( + ast, + SimpleFreeMarkerFormat.format("Bin expr op ${op} is not supported.", + SimpleMap.of("op", op.name()))); + } + Size sizeOp = stackManipulation.apply(methodVisitor, context); + return aggregateSize(sizeLoadAndCast, sizeOp); + } + + @Override + public void compile() { + left.compile(); + right.compile(); + } + + public ITs2JavaAstExpr getLeft() { + return left; + } + + public Swc4jAstBinaryOp getOp() { + return op; + } + + public ITs2JavaAstExpr getRight() { + return right; + } +} diff --git a/src/main/java/com/caoccao/javet/buddy/ts2java/ast/interfaces/ITs2JavaAstExpr.java b/src/main/java/com/caoccao/javet/buddy/ts2java/ast/interfaces/ITs2JavaAstExpr.java index c58c975..c76283c 100644 --- a/src/main/java/com/caoccao/javet/buddy/ts2java/ast/interfaces/ITs2JavaAstExpr.java +++ b/src/main/java/com/caoccao/javet/buddy/ts2java/ast/interfaces/ITs2JavaAstExpr.java @@ -16,6 +16,7 @@ package com.caoccao.javet.buddy.ts2java.ast.interfaces; +import com.caoccao.javet.buddy.ts2java.ast.expr.Ts2JavaAstBinExpr; import com.caoccao.javet.buddy.ts2java.ast.expr.Ts2JavaAstIdent; import com.caoccao.javet.buddy.ts2java.ast.expr.Ts2JavaAstUnaryExpr; import com.caoccao.javet.buddy.ts2java.ast.expr.lit.Ts2JavaAstBool; @@ -23,6 +24,7 @@ import com.caoccao.javet.buddy.ts2java.ast.memo.Ts2JavaMemo; import com.caoccao.javet.buddy.ts2java.ast.memo.Ts2JavaMemoFunction; import com.caoccao.javet.buddy.ts2java.exceptions.Ts2JavaAstException; +import com.caoccao.javet.swc4j.ast.expr.Swc4jAstBinExpr; import com.caoccao.javet.swc4j.ast.expr.Swc4jAstIdent; import com.caoccao.javet.swc4j.ast.expr.Swc4jAstParenExpr; import com.caoccao.javet.swc4j.ast.expr.Swc4jAstUnaryExpr; @@ -42,6 +44,8 @@ public interface ITs2JavaAstExpr