猿问

在 Java 解释器中抽象数学运算

我正在用 Java 编写一个 AST 解释器,它有很多方法可以检查参数类型并在它们匹配时执行操作。到目前为止,已经有五种以上的方法,它们基本上是相互复制粘贴的版本。有没有办法抽象要检查的类型和要执行的操作?


    @Override

    public Object visitMultiplyNode(MultiplyNode multiplyNode) {

        Object lhs = multiplyNode.getLeftHandSide().accept(this);

        Object rhs = multiplyNode.getRightHandSide().accept(this);


        if (lhs instanceof Double && rhs instanceof Double) {

            return (double) lhs * (double) rhs;

        }

        if (lhs instanceof Long && rhs instanceof Long) {

            return (long) lhs * (long) rhs;

        }

        throw new TypeError("Can not multiply " + lhs.getClass() + " and " + rhs.getClass() + ".");

    }

我要检查的类型并不总是相同的,例如,模数节点只接受 Longs 而加法节点也接受 Strings 进行连接。


    @Override

    public Object visitAddNode(AddNode addNode) {

        Object lhs = addNode.getLeftHandSide().accept(this);

        Object rhs = addNode.getRightHandSide().accept(this);


        if (lhs instanceof Double && rhs instanceof Double) {

            return (double) lhs + (double) rhs;

        }

        if (lhs instanceof Long && rhs instanceof  Long) {

            return (long) lhs + (long) rhs;

        }

        if (lhs instanceof String && rhs instanceof String) {

            return "" + lhs + lhs;

        }

        throw new TypeError("Can not add " + lhs.getClass() + " and " + rhs.getClass() + ".");

    }


    @Override

    public Object visitModulusNode(ModulusNode modulusNode) {

        Object lhs = modulusNode.getLeftHandSide().accept(this);

        Object rhs = modulusNode.getRightHandSide().accept(this);


        if (lhs instanceof Long && rhs instanceof Long) {

            return (long) lhs % (long) rhs;

        }

        throw new TypeError("Can not take modulus of " + lhs.getClass() + " and " + rhs.getClass() + ".");

    }


杨__羊羊
浏览 131回答 2
2回答

慕运维8079593

你可以使用 lambda:private Object visitBinaryOperatorNode(BinaryOpNode node, BiFunction<T, T> op) {&nbsp; &nbsp; Object lhs = node.getLeftHandSide().accept(this);&nbsp; &nbsp; Object rhs = node.getRightHandSide().accept(this);&nbsp; &nbsp; if (lhs instanceof Long && rhs instanceof Long) {&nbsp; &nbsp; &nbsp; &nbsp; return op.apply((long) lhs, (long) rhs);&nbsp; &nbsp; }&nbsp; &nbsp; throw new TypeError("Can not take " + node.getOpName() + "of " + lhs.getClass() + " and " + rhs.getClass() + ".");}但是,由于您的某些运算符支持多种类型,因此您需要另一层抽象:@RequiredArgsConstructor// Lombok, otherwise write the boilerplate yourselfpublic class BinaryOperator<T, T> {&nbsp; &nbsp;@NonNull private final BiFunction<T, T> op;&nbsp; &nbsp;@NonNull private final Class<T> clazz;&nbsp; &nbsp;public boolean isApplicable(Object left, Object right) {&nbsp; &nbsp; &nbsp; &nbsp;return clazz.isInstance(left) && clazz.isInstance(right);&nbsp; &nbsp;}&nbsp; &nbsp;public T apply(Object left, Object right) {&nbsp; &nbsp; &nbsp; &nbsp;return op.apply(clazz.cast(left), clazz.cast(right));&nbsp; &nbsp;}}您现在可以传递一组有效的二元运算符并测试它们是否适用,如果适用,则应用它们。private static final List<BinaryOperator<?, ?>> VALID_ADD_OPERATORS = Arrays.asList(&nbsp; &nbsp; new BinaryOperator<>((x, y) -> x + y, Double.class),&nbsp;&nbsp; &nbsp; new BinaryOperator<>((x, y) -> x + y, Long.class),&nbsp; &nbsp; new BinaryOperator<>((x, y) -> x + y, String.class));private static final List<BinaryOperator<?, ?>> VALID_MULTIPLY_OPERATORS = Arrays.asList(&nbsp; &nbsp; new BinaryOperator<>((x, y) -> x * y, Double.class),&nbsp;&nbsp; &nbsp; new BinaryOperator<>((x, y) -> x * y, Long.class));@Overridepublic Object visitAddNode(AddNode addNode) {&nbsp; &nbsp; return visitBinaryOperatorNode(addNode, VALID_ADD_OPERATORS );}@Overridepublic Object visitMultiplyNode(MultiplyNode multiplyNode) {&nbsp;&nbsp; &nbsp; return visitBinaryOperatorNode(multiplyNode, VALID_MULTIPLY_OPERATORS );&nbsp;}private Object visitBinaryOperatorNode(BinaryOpNode node, List<BinaryOperator<?, ?>> validOperators) {&nbsp; &nbsp; Object lhs = node.getLeftHandSide().accept(this);&nbsp; &nbsp; Object rhs = node.getRightHandSide().accept(this);&nbsp; &nbsp; for (BinaryOperator<?, ?> op : validOperators) {&nbsp; &nbsp; &nbsp; &nbsp; if (op.isApplicable(lhs, rhs)) return op.apply(lhs, rhs);&nbsp; &nbsp; }&nbsp; &nbsp; throw new TypeError("Can not take " + node.getOpName() + "of " + lhs.getClass() + " and " + rhs.getClass() + ".");}

慕的地8271018

您可以将这些检查提取到单独的对象中,并在需要时重用它。例如,通过为要处理转换的每种类型定义一个枚举值。例如public enum ConvertType {&nbsp; &nbsp; DOUBLE {&nbsp; &nbsp; &nbsp; &nbsp; Object apply(Object lhs, Object rhs) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (lhs instanceof Double && rhs instanceof Double) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return (double) lhs + (double) rhs;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; },&nbsp; &nbsp; LONG {&nbsp; &nbsp; &nbsp; &nbsp; Object apply(Object lhs, Object rhs) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (lhs instanceof Long && rhs instanceof Long) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return (long) lhs + (long) rhs;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; },&nbsp; &nbsp; STRING {&nbsp; &nbsp; &nbsp; &nbsp; Object apply(Object lhs, Object rhs) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (lhs instanceof String && rhs instanceof String) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return "" + lhs + lhs;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return null;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; };&nbsp; &nbsp; public static Object apply(Object a, Object b, ConvertType... convertTypes) {&nbsp; &nbsp; &nbsp; &nbsp; for (ConvertType convertType : convertTypes) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Object result = convertType.apply(a, b);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (result != null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; throw new TypeError("Can not take modulus of " + a.getClass() + " and " + b.getClass() + ".");&nbsp; &nbsp; }}转换的入口点是静态方法:public static Object apply(Object a, Object b, ConvertType... convertTypes)ConvertType多亏了var-args.例如 :@Overridepublic Object visitMultiplyNode(MultiplyNode multiplyNode) {&nbsp; &nbsp; Object lhs = multiplyNode.getLeftHandSide().accept(this);&nbsp; &nbsp; Object rhs = multiplyNode.getRightHandSide().accept(this);&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; &nbsp; return ConvertType.apply(lhs , rhs, ConvertType.DOUBLE, ConvertType.LONG);}或者 :@Overridepublic Object visitAddNode(AddNode addNode) {&nbsp; &nbsp; Object lhs = addNode.getLeftHandSide().accept(this);&nbsp; &nbsp; Object rhs = addNode.getRightHandSide().accept(this);&nbsp; &nbsp; return ConvertType.apply(lhs , rhs, ConvertType.DOUBLE, ConvertType.LONG, ConvertType.STRING);&nbsp; &nbsp;&nbsp;}
随时随地看视频慕课网APP

相关分类

Java
我要回答