package org.zwobble.couscous.backends.python; import java.util.List; import java.util.Map; import java.util.Optional; import org.zwobble.couscous.ast.Operator; import org.zwobble.couscous.ast.TypeName; import org.zwobble.couscous.backends.python.ast.PythonExpressionNode; import org.zwobble.couscous.backends.python.ast.PythonNotNode; import org.zwobble.couscous.values.BooleanValue; import org.zwobble.couscous.values.IntegerValue; import org.zwobble.couscous.values.InternalCouscousValue; import org.zwobble.couscous.values.StringValue; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap.Builder; import static java.util.Arrays.asList; import static org.zwobble.couscous.backends.python.ast.PythonAttributeAccessNode.pythonAttributeAccess; import static org.zwobble.couscous.backends.python.ast.PythonBinaryOperation.pythonIs; import static org.zwobble.couscous.backends.python.ast.PythonCallNode.pythonCall; import static org.zwobble.couscous.backends.python.ast.PythonGetSliceNode.pythonGetSlice; import static org.zwobble.couscous.backends.python.ast.PythonVariableReferenceNode.pythonVariableReference; public class PrimitiveMethods { private static final Map STRING_METHODS = ImmutableMap.builder() .put("length", (receiver, arguments) -> pythonCall( pythonVariableReference("len"), asList(receiver))) .put("substring", (receiver, arguments) -> pythonGetSlice(receiver, arguments)) .build(); private static final Map BOOLEAN_METHODS = ImmutableMap.builder() .put("negate", (receiver, arguments) -> PythonNotNode.pythonNot(receiver)) .build(); private static final Map INT_METHODS; static { ImmutableMap.Builder methods = ImmutableMap.builder(); addMethod(methods, Operator.ADD.getMethodName(), "__add__"); addMethod(methods, Operator.SUBTRACT.getMethodName(), "__sub__"); addMethod(methods, Operator.MULTIPLY.getMethodName(), "__mul__"); methods.put(Operator.DIVIDE.getMethodName(), (receiver, arguments) -> pythonCall( internalReference("_div_round_to_zero"), asList(receiver, arguments.get(0)))); methods.put(Operator.MOD.getMethodName(), (receiver, arguments) -> pythonCall( internalReference("_mod_round_to_zero"), asList(receiver, arguments.get(0)))); addMethod(methods, Operator.EQUALS.getMethodName(), "__eq__"); addMethod(methods, Operator.NOT_EQUALS.getMethodName(), "__ne__"); addMethod(methods, Operator.GREATER_THAN.getMethodName(), "__gt__"); addMethod(methods, Operator.GREATER_THAN_OR_EQUAL.getMethodName(), "__ge__"); addMethod(methods, Operator.LESS_THAN.getMethodName(), "__lt__"); addMethod(methods, Operator.LESS_THAN_OR_EQUAL.getMethodName(), "__le__"); INT_METHODS = methods.build(); } private static PythonExpressionNode internalReference(String name) { return pythonAttributeAccess(pythonVariableReference("_couscous"), name); } private static void addMethod( Builder methods, String methodName, String pythonMethodName) { methods.put(methodName, (receiver, arguments) -> pythonCall( pythonAttributeAccess(receiver, pythonMethodName), arguments)); } private static final Map> METHODS = ImmutableMap.>builder() .put(StringValue.REF, STRING_METHODS) .put(BooleanValue.REF, BOOLEAN_METHODS) .put(IntegerValue.REF, INT_METHODS) .build(); private static final Map INTERNAL_METHODS = ImmutableMap.builder() .put("same", arguments -> pythonIs(arguments.get(0), arguments.get(1))) .build(); private static final Map> STATIC_METHODS = ImmutableMap.>builder() .put(InternalCouscousValue.REF, INTERNAL_METHODS) .build(); public static boolean isPrimitive(TypeName type) { return METHODS.containsKey(type); } public static Optional getPrimitiveMethod(TypeName type, String methodName) { return Optional.ofNullable(METHODS.get(type)) .flatMap(methodsForType -> Optional.ofNullable(methodsForType.get(methodName))); } @FunctionalInterface public interface PrimitiveMethodGenerator { PythonExpressionNode generate(PythonExpressionNode receiver, List arguments); } public static Optional getPrimitiveStaticMethod(TypeName type, String methodName) { return Optional.ofNullable(STATIC_METHODS.get(type)) .flatMap(methodsForType -> Optional.ofNullable(methodsForType.get(methodName))); } @FunctionalInterface public interface PrimitiveStaticMethodGenerator { PythonExpressionNode generate(List arguments); } }