Revision: b170953484
Author: Michael Bayne <m...@samskivert.com>
Date: Wed Nov 24 11:00:46 2010
Log: Nixed two more comments that duplicated the target descriptions.
http://code.google.com/p/ductilej/source/detail?r=b170953484
Revision: 988aaa5b43
Author: Michael Bayne <m...@samskivert.com>
Date: Sat Nov 27 12:15:19 2010
Log: Separated source into src/main/java and src/test/java.
http://code.google.com/p/ductilej/source/detail?r=988aaa5b43
==============================================================================
Revision: b170953484
Author: Michael Bayne <m...@samskivert.com>
Date: Wed Nov 24 11:00:46 2010
Log: Nixed two more comments that duplicated the target descriptions.
http://code.google.com/p/ductilej/source/detail?r=b170953484
Modified:
/build.xml
=======================================
--- /build.xml Wed Nov 24 11:00:06 2010
+++ /build.xml Wed Nov 24 11:00:46 2010
@@ -78,7 +78,6 @@
description="Runs all tests.">
</target>
- <!-- builds our distribution jar file -->
<target name="dist" depends="compile"
description="Compiles the code and builds our jar file.">
<taskdef name="jarjar" classname="com.tonicsystems.jarjar.JarJarTask"
@@ -92,7 +91,6 @@
</jarjar>
</target>
- <!-- compiles our unit tests with the detyper and runs them -->
<target name="test-ductile" depends="compile"
description="Compiles and runs the unit tests (with detyper).">
<delete dir="${dtclass.dir}"/>
==============================================================================
Revision: 988aaa5b43
Author: Michael Bayne <m...@samskivert.com>
Date: Sat Nov 27 12:15:19 2010
Log: Separated source into src/main/java and src/test/java.
http://code.google.com/p/ductilej/source/detail?r=988aaa5b43
Added:
/src/main/java/org/ductilej/astviz/Processor.java
/src/main/java/org/ductilej/detyper/Backdoor.java
/src/main/java/org/ductilej/detyper/Detype.java
/src/main/java/org/ductilej/detyper/DetypeContext.java
/src/main/java/org/ductilej/detyper/Processor.java
/src/main/java/org/ductilej/detyper/Resolver.java
/src/main/java/org/ductilej/runtime/AmbiguousMethodError.java
/src/main/java/org/ductilej/runtime/BinOps.java
/src/main/java/org/ductilej/runtime/Binop.java
/src/main/java/org/ductilej/runtime/Debug.java
/src/main/java/org/ductilej/runtime/RT.java
/src/main/java/org/ductilej/runtime/Transformed.java
/src/main/java/org/ductilej/runtime/UnOps.java
/src/main/java/org/ductilej/runtime/Unop.java
/src/main/java/org/ductilej/runtime/WrappedException.java
/src/main/java/org/ductilej/runtime/ops/BooleanBooleanOps.java
/src/main/java/org/ductilej/runtime/ops/BooleanOps.java
/src/main/java/org/ductilej/runtime/ops/ByteByteOps.java
/src/main/java/org/ductilej/runtime/ops/ByteCharacterOps.java
/src/main/java/org/ductilej/runtime/ops/ByteDoubleOps.java
/src/main/java/org/ductilej/runtime/ops/ByteFloatOps.java
/src/main/java/org/ductilej/runtime/ops/ByteIntegerOps.java
/src/main/java/org/ductilej/runtime/ops/ByteLongOps.java
/src/main/java/org/ductilej/runtime/ops/ByteOps.java
/src/main/java/org/ductilej/runtime/ops/ByteShortOps.java
/src/main/java/org/ductilej/runtime/ops/CharacterByteOps.java
/src/main/java/org/ductilej/runtime/ops/CharacterCharacterOps.java
/src/main/java/org/ductilej/runtime/ops/CharacterDoubleOps.java
/src/main/java/org/ductilej/runtime/ops/CharacterFloatOps.java
/src/main/java/org/ductilej/runtime/ops/CharacterIntegerOps.java
/src/main/java/org/ductilej/runtime/ops/CharacterLongOps.java
/src/main/java/org/ductilej/runtime/ops/CharacterOps.java
/src/main/java/org/ductilej/runtime/ops/CharacterShortOps.java
/src/main/java/org/ductilej/runtime/ops/DoubleByteOps.java
/src/main/java/org/ductilej/runtime/ops/DoubleCharacterOps.java
/src/main/java/org/ductilej/runtime/ops/DoubleDoubleOps.java
/src/main/java/org/ductilej/runtime/ops/DoubleFloatOps.java
/src/main/java/org/ductilej/runtime/ops/DoubleIntegerOps.java
/src/main/java/org/ductilej/runtime/ops/DoubleLongOps.java
/src/main/java/org/ductilej/runtime/ops/DoubleOps.java
/src/main/java/org/ductilej/runtime/ops/DoubleShortOps.java
/src/main/java/org/ductilej/runtime/ops/FloatByteOps.java
/src/main/java/org/ductilej/runtime/ops/FloatCharacterOps.java
/src/main/java/org/ductilej/runtime/ops/FloatDoubleOps.java
/src/main/java/org/ductilej/runtime/ops/FloatFloatOps.java
/src/main/java/org/ductilej/runtime/ops/FloatIntegerOps.java
/src/main/java/org/ductilej/runtime/ops/FloatLongOps.java
/src/main/java/org/ductilej/runtime/ops/FloatOps.java
/src/main/java/org/ductilej/runtime/ops/FloatShortOps.java
/src/main/java/org/ductilej/runtime/ops/FloatingBinOps.tmpl
/src/main/java/org/ductilej/runtime/ops/FloatingUnOps.tmpl
/src/main/java/org/ductilej/runtime/ops/IntegerByteOps.java
/src/main/java/org/ductilej/runtime/ops/IntegerCharacterOps.java
/src/main/java/org/ductilej/runtime/ops/IntegerDoubleOps.java
/src/main/java/org/ductilej/runtime/ops/IntegerFloatOps.java
/src/main/java/org/ductilej/runtime/ops/IntegerIntegerOps.java
/src/main/java/org/ductilej/runtime/ops/IntegerLongOps.java
/src/main/java/org/ductilej/runtime/ops/IntegerOps.java
/src/main/java/org/ductilej/runtime/ops/IntegerShortOps.java
/src/main/java/org/ductilej/runtime/ops/IntegralBinOps.tmpl
/src/main/java/org/ductilej/runtime/ops/IntegralUnOps.tmpl
/src/main/java/org/ductilej/runtime/ops/LongByteOps.java
/src/main/java/org/ductilej/runtime/ops/LongCharacterOps.java
/src/main/java/org/ductilej/runtime/ops/LongDoubleOps.java
/src/main/java/org/ductilej/runtime/ops/LongFloatOps.java
/src/main/java/org/ductilej/runtime/ops/LongIntegerOps.java
/src/main/java/org/ductilej/runtime/ops/LongLongOps.java
/src/main/java/org/ductilej/runtime/ops/LongOps.java
/src/main/java/org/ductilej/runtime/ops/LongShortOps.java
/src/main/java/org/ductilej/runtime/ops/ShortByteOps.java
/src/main/java/org/ductilej/runtime/ops/ShortCharacterOps.java
/src/main/java/org/ductilej/runtime/ops/ShortDoubleOps.java
/src/main/java/org/ductilej/runtime/ops/ShortFloatOps.java
/src/main/java/org/ductilej/runtime/ops/ShortIntegerOps.java
/src/main/java/org/ductilej/runtime/ops/ShortLongOps.java
/src/main/java/org/ductilej/runtime/ops/ShortOps.java
/src/main/java/org/ductilej/runtime/ops/ShortShortOps.java
/src/main/java/org/ductilej/util/ASTUtil.java
/src/main/java/org/ductilej/util/LogBuilder.java
/src/main/java/org/ductilej/util/PathedTreeTranslator.java
/src/test/java/org/ductilej/dtests/ConstructorArgsTest.java
/src/test/java/org/ductilej/dtests/DuckTypingTest.java
/src/test/java/org/ductilej/dtests/InferredReceiverTest.java
/src/test/java/org/ductilej/dtests/IterableTest.java
/src/test/java/org/ductilej/dtests/MissingMethodTest.java
/src/test/java/org/ductilej/dtests/NullPointerExceptionTest.java
/src/test/java/org/ductilej/dtests/UncheckedExceptionTest.java
/src/test/java/org/ductilej/tests/ArgVisibilityTest.java
/src/test/java/org/ductilej/tests/ArrayAccessTest.java
/src/test/java/org/ductilej/tests/ArrayCloneTest.java
/src/test/java/org/ductilej/tests/ArrayCreateTest.java
/src/test/java/org/ductilej/tests/ArrayStoreTest.java
/src/test/java/org/ductilej/tests/ArrayTypeTest.java
/src/test/java/org/ductilej/tests/AssignExprTest.java
/src/test/java/org/ductilej/tests/BasicAssignTest.java
/src/test/java/org/ductilej/tests/BridgeMethodTest.java
/src/test/java/org/ductilej/tests/ChainedConsTest.java
/src/test/java/org/ductilej/tests/CloneTest.java
/src/test/java/org/ductilej/tests/CoerceTest.java
/src/test/java/org/ductilej/tests/ConditionalTest.java
/src/test/java/org/ductilej/tests/ConstTest.java
/src/test/java/org/ductilej/tests/ConstructorPackageTest.java
/src/test/java/org/ductilej/tests/ConversionTest.java
/src/test/java/org/ductilej/tests/CtorTest.java
/src/test/java/org/ductilej/tests/DefApplyTest.java
/src/test/java/org/ductilej/tests/DefPrimValTest.java
/src/test/java/org/ductilej/tests/EnumTest.java
/src/test/java/org/ductilej/tests/FieldInitTest.java
/src/test/java/org/ductilej/tests/ForeachTest.java
/src/test/java/org/ductilej/tests/HashCodeTest.java
/src/test/java/org/ductilej/tests/ImplInheritTest.java
/src/test/java/org/ductilej/tests/InfTypeVarTest.java
/src/test/java/org/ductilej/tests/InitOrderTest.java
/src/test/java/org/ductilej/tests/InnerClassTest.java
/src/test/java/org/ductilej/tests/InnerFieldTest.java
/src/test/java/org/ductilej/tests/InterfaceTest.java
/src/test/java/org/ductilej/tests/InvokeNonStaticTest.java
/src/test/java/org/ductilej/tests/InvokeStaticTest.java
/src/test/java/org/ductilej/tests/IterableTest.java
/src/test/java/org/ductilej/tests/LibInterfaceTest.java
/src/test/java/org/ductilej/tests/LibraryFieldAssignTest.java
/src/test/java/org/ductilej/tests/NameCollideTest.java
/src/test/java/org/ductilej/tests/NestedTypeVarTest.java
/src/test/java/org/ductilej/tests/NullVarArgsTest.java
/src/test/java/org/ductilej/tests/OldJUnitTest.java
/src/test/java/org/ductilej/tests/OpResolveTest.java
/src/test/java/org/ductilej/tests/OperatorTest.java
/src/test/java/org/ductilej/tests/OuterInnerTest.java
/src/test/java/org/ductilej/tests/OuterThisTest.java
/src/test/java/org/ductilej/tests/OverCtorTest.java
/src/test/java/org/ductilej/tests/OverVarArgsTest.java
/src/test/java/org/ductilej/tests/OverloadTest.java
/src/test/java/org/ductilej/tests/PackageAccessTest.java
/src/test/java/org/ductilej/tests/ParamVarArgsTest.java
/src/test/java/org/ductilej/tests/ParameterizedThisTest.java
/src/test/java/org/ductilej/tests/PromoteTest.java
/src/test/java/org/ductilej/tests/ProtectedConstructorTest.java
/src/test/java/org/ductilej/tests/QualifiedNameTest.java
/src/test/java/org/ductilej/tests/QualifiedThisTest.java
/src/test/java/org/ductilej/tests/RawTypesTest.java
/src/test/java/org/ductilej/tests/RawVarArgsTest.java
/src/test/java/org/ductilej/tests/ReflectiveInvokeTest.java
/src/test/java/org/ductilej/tests/RetTypeVarTest.java
/src/test/java/org/ductilej/tests/SelectSuperTest.java
/src/test/java/org/ductilej/tests/SelectTest.java
/src/test/java/org/ductilej/tests/SerializeTest.java
/src/test/java/org/ductilej/tests/ShadowedFinalArgTest.java
/src/test/java/org/ductilej/tests/SneakyThrowTest.java
/src/test/java/org/ductilej/tests/StaticBlockTest.java
/src/test/java/org/ductilej/tests/StaticHelper.java
/src/test/java/org/ductilej/tests/StaticImportTest.java
/src/test/java/org/ductilej/tests/StaticMethodAmbiguousInterfaceTest.java
/src/test/java/org/ductilej/tests/StaticMethodResolutionTest.java
/src/test/java/org/ductilej/tests/SuperCallTest.java
/src/test/java/org/ductilej/tests/SuperSuperTest.java
/src/test/java/org/ductilej/tests/SuperTypeVarTest.java
/src/test/java/org/ductilej/tests/SwitchTest.java
/src/test/java/org/ductilej/tests/ThrowsTest.java
/src/test/java/org/ductilej/tests/TypeVarTest.java
/src/test/java/org/ductilej/tests/VAEnumTest.java
/src/test/java/org/ductilej/tests/VarTypedExpTest.java
/src/test/java/org/ductilej/tests/WildcardTest.java
/src/test/java/org/ductilej/tests/helper/ConstructorPackageTestClass.java
/src/test/java/org/ductilej/tests/helper/HelperEnum.java
/src/test/java/org/ductilej/tests/helper/HelperUtil.java
/src/test/java/org/ductilej/tests/helper/ProtectedHelper.java
/src/test/java/org/ductilej/tests/helper/SelectSuperHelper.java
/src/test/java/org/ductilej/tests/helper/StaticMethodResolutionTestPackage.java
/src/test/java/org/ductilej/tests/helper/one/MyInterfaceTest.java
/src/test/java/org/ductilej/tests/helper/two/MyInterfaceTest.java
Deleted:
/src/org/ductilej/astviz/Processor.java
/src/org/ductilej/detyper/Backdoor.java
/src/org/ductilej/detyper/Detype.java
/src/org/ductilej/detyper/DetypeContext.java
/src/org/ductilej/detyper/Processor.java
/src/org/ductilej/detyper/Resolver.java
/src/org/ductilej/dtests/ConstructorArgsTest.java
/src/org/ductilej/dtests/DuckTypingTest.java
/src/org/ductilej/dtests/InferredReceiverTest.java
/src/org/ductilej/dtests/IterableTest.java
/src/org/ductilej/dtests/MissingMethodTest.java
/src/org/ductilej/dtests/NullPointerExceptionTest.java
/src/org/ductilej/dtests/UncheckedExceptionTest.java
/src/org/ductilej/runtime/AmbiguousMethodError.java
/src/org/ductilej/runtime/BinOps.java
/src/org/ductilej/runtime/Binop.java
/src/org/ductilej/runtime/Debug.java
/src/org/ductilej/runtime/RT.java
/src/org/ductilej/runtime/Transformed.java
/src/org/ductilej/runtime/UnOps.java
/src/org/ductilej/runtime/Unop.java
/src/org/ductilej/runtime/WrappedException.java
/src/org/ductilej/runtime/ops/BooleanBooleanOps.java
/src/org/ductilej/runtime/ops/BooleanOps.java
/src/org/ductilej/runtime/ops/ByteByteOps.java
/src/org/ductilej/runtime/ops/ByteCharacterOps.java
/src/org/ductilej/runtime/ops/ByteDoubleOps.java
/src/org/ductilej/runtime/ops/ByteFloatOps.java
/src/org/ductilej/runtime/ops/ByteIntegerOps.java
/src/org/ductilej/runtime/ops/ByteLongOps.java
/src/org/ductilej/runtime/ops/ByteOps.java
/src/org/ductilej/runtime/ops/ByteShortOps.java
/src/org/ductilej/runtime/ops/CharacterByteOps.java
/src/org/ductilej/runtime/ops/CharacterCharacterOps.java
/src/org/ductilej/runtime/ops/CharacterDoubleOps.java
/src/org/ductilej/runtime/ops/CharacterFloatOps.java
/src/org/ductilej/runtime/ops/CharacterIntegerOps.java
/src/org/ductilej/runtime/ops/CharacterLongOps.java
/src/org/ductilej/runtime/ops/CharacterOps.java
/src/org/ductilej/runtime/ops/CharacterShortOps.java
/src/org/ductilej/runtime/ops/DoubleByteOps.java
/src/org/ductilej/runtime/ops/DoubleCharacterOps.java
/src/org/ductilej/runtime/ops/DoubleDoubleOps.java
/src/org/ductilej/runtime/ops/DoubleFloatOps.java
/src/org/ductilej/runtime/ops/DoubleIntegerOps.java
/src/org/ductilej/runtime/ops/DoubleLongOps.java
/src/org/ductilej/runtime/ops/DoubleOps.java
/src/org/ductilej/runtime/ops/DoubleShortOps.java
/src/org/ductilej/runtime/ops/FloatByteOps.java
/src/org/ductilej/runtime/ops/FloatCharacterOps.java
/src/org/ductilej/runtime/ops/FloatDoubleOps.java
/src/org/ductilej/runtime/ops/FloatFloatOps.java
/src/org/ductilej/runtime/ops/FloatIntegerOps.java
/src/org/ductilej/runtime/ops/FloatLongOps.java
/src/org/ductilej/runtime/ops/FloatOps.java
/src/org/ductilej/runtime/ops/FloatShortOps.java
/src/org/ductilej/runtime/ops/FloatingBinOps.tmpl
/src/org/ductilej/runtime/ops/FloatingUnOps.tmpl
/src/org/ductilej/runtime/ops/IntegerByteOps.java
/src/org/ductilej/runtime/ops/IntegerCharacterOps.java
/src/org/ductilej/runtime/ops/IntegerDoubleOps.java
/src/org/ductilej/runtime/ops/IntegerFloatOps.java
/src/org/ductilej/runtime/ops/IntegerIntegerOps.java
/src/org/ductilej/runtime/ops/IntegerLongOps.java
/src/org/ductilej/runtime/ops/IntegerOps.java
/src/org/ductilej/runtime/ops/IntegerShortOps.java
/src/org/ductilej/runtime/ops/IntegralBinOps.tmpl
/src/org/ductilej/runtime/ops/IntegralUnOps.tmpl
/src/org/ductilej/runtime/ops/LongByteOps.java
/src/org/ductilej/runtime/ops/LongCharacterOps.java
/src/org/ductilej/runtime/ops/LongDoubleOps.java
/src/org/ductilej/runtime/ops/LongFloatOps.java
/src/org/ductilej/runtime/ops/LongIntegerOps.java
/src/org/ductilej/runtime/ops/LongLongOps.java
/src/org/ductilej/runtime/ops/LongOps.java
/src/org/ductilej/runtime/ops/LongShortOps.java
/src/org/ductilej/runtime/ops/ShortByteOps.java
/src/org/ductilej/runtime/ops/ShortCharacterOps.java
/src/org/ductilej/runtime/ops/ShortDoubleOps.java
/src/org/ductilej/runtime/ops/ShortFloatOps.java
/src/org/ductilej/runtime/ops/ShortIntegerOps.java
/src/org/ductilej/runtime/ops/ShortLongOps.java
/src/org/ductilej/runtime/ops/ShortOps.java
/src/org/ductilej/runtime/ops/ShortShortOps.java
/src/org/ductilej/tests/ArgVisibilityTest.java
/src/org/ductilej/tests/ArrayAccessTest.java
/src/org/ductilej/tests/ArrayCloneTest.java
/src/org/ductilej/tests/ArrayCreateTest.java
/src/org/ductilej/tests/ArrayStoreTest.java
/src/org/ductilej/tests/ArrayTypeTest.java
/src/org/ductilej/tests/AssignExprTest.java
/src/org/ductilej/tests/BasicAssignTest.java
/src/org/ductilej/tests/BridgeMethodTest.java
/src/org/ductilej/tests/ChainedConsTest.java
/src/org/ductilej/tests/CloneTest.java
/src/org/ductilej/tests/CoerceTest.java
/src/org/ductilej/tests/ConditionalTest.java
/src/org/ductilej/tests/ConstTest.java
/src/org/ductilej/tests/ConstructorPackageTest.java
/src/org/ductilej/tests/ConversionTest.java
/src/org/ductilej/tests/CtorTest.java
/src/org/ductilej/tests/DefApplyTest.java
/src/org/ductilej/tests/DefPrimValTest.java
/src/org/ductilej/tests/EnumTest.java
/src/org/ductilej/tests/FieldInitTest.java
/src/org/ductilej/tests/ForeachTest.java
/src/org/ductilej/tests/HashCodeTest.java
/src/org/ductilej/tests/ImplInheritTest.java
/src/org/ductilej/tests/InfTypeVarTest.java
/src/org/ductilej/tests/InitOrderTest.java
/src/org/ductilej/tests/InnerClassTest.java
/src/org/ductilej/tests/InnerFieldTest.java
/src/org/ductilej/tests/InterfaceTest.java
/src/org/ductilej/tests/InvokeNonStaticTest.java
/src/org/ductilej/tests/InvokeStaticTest.java
/src/org/ductilej/tests/IterableTest.java
/src/org/ductilej/tests/LibInterfaceTest.java
/src/org/ductilej/tests/LibraryFieldAssignTest.java
/src/org/ductilej/tests/NameCollideTest.java
/src/org/ductilej/tests/NestedTypeVarTest.java
/src/org/ductilej/tests/NullVarArgsTest.java
/src/org/ductilej/tests/OldJUnitTest.java
/src/org/ductilej/tests/OpResolveTest.java
/src/org/ductilej/tests/OperatorTest.java
/src/org/ductilej/tests/OuterInnerTest.java
/src/org/ductilej/tests/OuterThisTest.java
/src/org/ductilej/tests/OverCtorTest.java
/src/org/ductilej/tests/OverVarArgsTest.java
/src/org/ductilej/tests/OverloadTest.java
/src/org/ductilej/tests/PackageAccessTest.java
/src/org/ductilej/tests/ParamVarArgsTest.java
/src/org/ductilej/tests/ParameterizedThisTest.java
/src/org/ductilej/tests/PromoteTest.java
/src/org/ductilej/tests/ProtectedConstructorTest.java
/src/org/ductilej/tests/QualifiedNameTest.java
/src/org/ductilej/tests/QualifiedThisTest.java
/src/org/ductilej/tests/RawTypesTest.java
/src/org/ductilej/tests/RawVarArgsTest.java
/src/org/ductilej/tests/ReflectiveInvokeTest.java
/src/org/ductilej/tests/RetTypeVarTest.java
/src/org/ductilej/tests/SelectSuperTest.java
/src/org/ductilej/tests/SelectTest.java
/src/org/ductilej/tests/SerializeTest.java
/src/org/ductilej/tests/ShadowedFinalArgTest.java
/src/org/ductilej/tests/SneakyThrowTest.java
/src/org/ductilej/tests/StaticBlockTest.java
/src/org/ductilej/tests/StaticHelper.java
/src/org/ductilej/tests/StaticImportTest.java
/src/org/ductilej/tests/StaticMethodAmbiguousInterfaceTest.java
/src/org/ductilej/tests/StaticMethodResolutionTest.java
/src/org/ductilej/tests/SuperCallTest.java
/src/org/ductilej/tests/SuperSuperTest.java
/src/org/ductilej/tests/SuperTypeVarTest.java
/src/org/ductilej/tests/SwitchTest.java
/src/org/ductilej/tests/ThrowsTest.java
/src/org/ductilej/tests/TypeVarTest.java
/src/org/ductilej/tests/VAEnumTest.java
/src/org/ductilej/tests/VarTypedExpTest.java
/src/org/ductilej/tests/WildcardTest.java
/src/org/ductilej/tests/helper/ConstructorPackageTestClass.java
/src/org/ductilej/tests/helper/HelperEnum.java
/src/org/ductilej/tests/helper/HelperUtil.java
/src/org/ductilej/tests/helper/ProtectedHelper.java
/src/org/ductilej/tests/helper/SelectSuperHelper.java
/src/org/ductilej/tests/helper/StaticMethodResolutionTestPackage.java
/src/org/ductilej/tests/helper/one/MyInterfaceTest.java
/src/org/ductilej/tests/helper/two/MyInterfaceTest.java
/src/org/ductilej/util/ASTUtil.java
/src/org/ductilej/util/LogBuilder.java
/src/org/ductilej/util/PathedTreeTranslator.java
Modified:
/build.xml
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/astviz/Processor.java Sat Nov 27 12:15:19
2010
@@ -0,0 +1,470 @@
+//
+// $Id$
+
+package org.ductilej.astviz;
+
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+
+import com.sun.source.util.TreePath;
+import com.sun.source.util.Trees;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeScanner;
+
+import org.ductilej.util.ASTUtil;
+
+/**
+ * The main entry point for the visualizing processor.
+ */
+@SupportedAnnotationTypes("*")
+@SupportedSourceVersion(SourceVersion.RELEASE_6)
+public class Processor extends AbstractProcessor
+{
+ @Override // from AbstractProcessor
+ public void init (ProcessingEnvironment procenv)
+ {
+ super.init(procenv);
+
+ if (!(procenv instanceof JavacProcessingEnvironment)) {
+ procenv.getMessager().printMessage(
+ Diagnostic.Kind.WARNING, "ASTVIZ requires javac v1.6.");
+ return;
+ }
+ procenv.getMessager().printMessage(Diagnostic.Kind.NOTE, "ASTVIZ
initialized.");
+
+ _trees = Trees.instance(procenv);
+ _types =
Types.instance(((JavacProcessingEnvironment)procenv).getContext());
+ _rootmaker =
TreeMaker.instance(((JavacProcessingEnvironment)procenv).getContext());
+ }
+
+ @Override // from AbstractProcessor
+ public boolean process (Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv)
+ {
+ if (_trees == null) {
+ return false;
+ }
+
+ for (Element elem : roundEnv.getRootElements()) {
+ JCCompilationUnit unit = toUnit(elem);
+ System.out.println("Root elem " + elem);
+ unit.accept(new GraphingVisitor());
+ }
+ return false;
+ }
+
+ protected JCCompilationUnit toUnit (Element element)
+ {
+ TreePath path = _trees.getPath(element);
+ return (path == null) ? null :
(JCCompilationUnit)path.getCompilationUnit();
+ }
+
+ protected class GraphingVisitor extends TreeScanner
+ {
+ public void scan (JCTree tree)
+ {
+ _indent += 2;
+ super.scan(tree);
+ _indent -= 2;
+ }
+
+ public void visitTopLevel (JCCompilationUnit tree) {
+ println("Compilation unit: " + tree.sourcefile.getName());
+ println("Package annotations");
+ scan(tree.packageAnnotations);
+ println("Package id");
+ scan(tree.pid);
+ println("Definitions");
+ scan(tree.defs);
+ }
+
+ public void visitImport (JCImport tree) {
+ println("Import " + tree.isStatic());
+ super.visitImport(tree);
+// scan(tree.qualid);
+ }
+
+ public void visitClassDef (JCClassDecl tree) {
+ println("Class '" + tree.getSimpleName() + "' " +
what(tree.sym));
+ super.visitClassDef(tree);
+// scan(tree.mods);
+// scan(tree.typarams);
+// scan(tree.extending);
+// scan(tree.implementing);
+// scan(tree.defs);
+ }
+
+ public void visitMethodDef (JCMethodDecl tree) {
+ println("Method decl: " + tree.getName() + " " +
what(tree.sym) +
+ " " + ASTUtil.isLibraryOverrider(_types, tree.sym));
+ super.visitMethodDef(tree);
+// scan(tree.mods);
+// scan(tree.restype);
+// scan(tree.typarams);
+// scan(tree.params);
+// scan(tree.receiverAnnotations);
+// scan(tree.thrown);
+// scan(tree.defaultValue);
+// scan(tree.body);
+ }
+
+ public void visitVarDef (JCVariableDecl tree) {
+ println("Var def: " + tree.getName() + " " + what(tree.sym));
+ super.visitVarDef(tree);
+// scan(tree.mods);
+// scan(tree.vartype);
+// scan(tree.init);
+ }
+
+ public void visitSkip (JCSkip tree) {
+ println("Skip");
+ super.visitSkip(tree);
+ }
+
+ public void visitBlock (JCBlock tree) {
+ println("Block");
+ super.visitBlock(tree);
+// scan(tree.stats);
+ }
+
+ public void visitDoLoop (JCDoWhileLoop tree) {
+ println("Do loop");
+ super.visitDoLoop(tree);
+// scan(tree.body);
+// scan(tree.cond);
+ }
+
+ public void visitWhileLoop (JCWhileLoop tree) {
+ println("While loop");
+ super.visitWhileLoop(tree);
+// scan(tree.cond);
+// scan(tree.body);
+ }
+
+ public void visitForLoop (JCForLoop tree) {
+ println("For loop");
+ super.visitForLoop(tree);
+// scan(tree.init);
+// scan(tree.cond);
+// scan(tree.step);
+// scan(tree.body);
+ }
+
+ public void visitForeachLoop (JCEnhancedForLoop tree) {
+ println("Foreach loop");
+ super.visitForeachLoop(tree);
+// scan(tree.var);
+// scan(tree.expr);
+// scan(tree.body);
+ }
+
+ public void visitLabelled (JCLabeledStatement tree) {
+ println("Labeled stmt");
+ super.visitLabelled(tree);
+// scan(tree.body);
+ }
+
+ public void visitSwitch (JCSwitch tree) {
+ println("Switch stmt");
+ super.visitSwitch(tree);
+// scan(tree.selector);
+// scan(tree.cases);
+ }
+
+ public void visitCase (JCCase tree) {
+ println("Case stmt");
+ super.visitCase(tree);
+// scan(tree.pat);
+// scan(tree.stats);
+ }
+
+ public void visitSynchronized (JCSynchronized tree) {
+ println("Sync block");
+ super.visitSynchronized(tree);
+// scan(tree.lock);
+// scan(tree.body);
+ }
+
+ public void visitTry (JCTry tree) {
+ println("Try block");
+ super.visitTry(tree);
+// scan(tree.body);
+// scan(tree.catchers);
+// scan(tree.finalizer);
+ }
+
+ public void visitCatch (JCCatch tree) {
+ println("Catch block");
+ super.visitCatch(tree);
+// scan(tree.param);
+// scan(tree.body);
+ }
+
+ public void visitConditional (JCConditional tree) {
+ println("Conditional");
+ super.visitConditional(tree);
+// scan(tree.cond);
+// scan(tree.truepart);
+// scan(tree.falsepart);
+ }
+
+ public void visitIf (JCIf tree) {
+ println("If stmt");
+ super.visitIf(tree);
+// scan(tree.cond);
+// scan(tree.thenpart);
+// scan(tree.elsepart);
+ }
+
+ public void visitExec (JCExpressionStatement tree) {
+ println("Expr stmt");
+ super.visitExec(tree);
+// scan(tree.expr);
+ }
+
+ public void visitBreak (JCBreak tree) {
+ println("Break stmt");
+ super.visitBreak(tree);
+ }
+
+ public void visitContinue (JCContinue tree) {
+ println("Cont stmt");
+ super.visitContinue(tree);
+ }
+
+ public void visitReturn (JCReturn tree) {
+ println("Return stmt");
+ super.visitReturn(tree);
+// scan(tree.expr);
+ }
+
+ public void visitThrow (JCThrow tree) {
+ println("Throw stmt");
+ super.visitThrow(tree);
+// scan(tree.expr);
+ }
+
+ public void visitAssert (JCAssert tree) {
+ println("Assert stmt");
+ super.visitAssert(tree);
+// scan(tree.cond);
+// scan(tree.detail);
+ }
+
+ public void visitApply (JCMethodInvocation tree) {
+ println("Call method");
+ super.visitApply(tree);
+// scan(tree.meth);
+// scan(tree.args);
+ }
+
+ public void visitNewClass (JCNewClass tree) {
+ println("New stmt");
+ super.visitNewClass(tree);
+// scan(tree.encl);
+// scan(tree.clazz);
+// scan(tree.args);
+// scan(tree.def);
+ }
+
+ public void visitNewArray (JCNewArray tree) {
+ println("New array stmt");
+ super.visitNewArray(tree);
+// scan(tree.annotations);
+// scan(tree.elemtype);
+// scan(tree.dims);
+// for (List<JCTypeAnnotation> annos : tree.dimAnnotations)
+// scan(annos);
+// scan(tree.elems);
+ }
+
+ public void visitParens (JCParens tree) {
+ println("Paren expr");
+ super.visitParens(tree);
+// scan(tree.expr);
+ }
+
+ public void visitAssign (JCAssign tree) {
+ println("Assign stmt");
+ super.visitAssign(tree);
+// scan(tree.lhs);
+// scan(tree.rhs);
+ }
+
+ public void visitAssignop (JCAssignOp tree) {
+ println("Assignop expr: " + tree.getKind());
+ super.visitAssignop(tree);
+// scan(tree.lhs);
+// scan(tree.rhs);
+ }
+
+ public void visitUnary (JCUnary tree) {
+ println("Unary expr");
+ super.visitUnary(tree);
+// scan(tree.arg);
+ }
+
+ public void visitBinary (JCBinary tree) {
+ println("Binary expr: " + tree.getKind());
+ super.visitBinary(tree);
+// scan(tree.lhs);
+// scan(tree.rhs);
+ }
+
+ public void visitTypeCast (JCTypeCast tree) {
+ println("Type cast expr");
+ super.visitTypeCast(tree);
+// scan(tree.clazz);
+// scan(tree.expr);
+ }
+
+ public void visitTypeTest (JCInstanceOf tree) {
+ println("InstanceOf expr");
+ super.visitTypeTest(tree);
+// scan(tree.expr);
+// scan(tree.clazz);
+ }
+
+ public void visitIndexed (JCArrayAccess tree) {
+ println("Array access");
+ super.visitIndexed(tree);
+// scan(tree.indexed);
+// scan(tree.index);
+ }
+
+ public void visitSelect (JCFieldAccess tree) {
+ println("Field access: " + tree.getIdentifier());
+ super.visitSelect(tree);
+// scan(tree.selected);
+ }
+
+ public void visitIdent (JCIdent tree) {
+ println("Ident: " + tree.getName());
+ super.visitIdent(tree);
+ }
+
+ public void visitLiteral (JCLiteral tree) {
+ println("Literal: " + tree.value);
+ super.visitLiteral(tree);
+ }
+
+ public void visitTypeIdent (JCPrimitiveTypeTree tree) {
+ println("Type: " + tree.getKind() + " " +
tree.getPrimitiveTypeKind());
+ super.visitTypeIdent(tree);
+ }
+
+ public void visitTypeArray (JCArrayTypeTree tree) {
+ println("Type array");
+ super.visitTypeArray(tree);
+// scan(tree.elemtype);
+ }
+
+ public void visitTypeApply (JCTypeApply tree) {
+ println("Type apply");
+ super.visitTypeApply(tree);
+// scan(tree.clazz);
+// scan(tree.arguments);
+ }
+
+ public void visitTypeParameter (JCTypeParameter tree) {
+ println("Type param");
+ super.visitTypeParameter(tree);
+// scan(tree.annotations);
+// scan(tree.bounds);
+ }
+
+ public void visitWildcard (JCWildcard tree) {
+ println("Type wildcard");
+ super.visitWildcard(tree);
+// scan(tree.kind);
+// if (tree.inner != null)
+// scan(tree.inner);
+ }
+
+// public void visitTypeBoundKind (TypeBoundKind that) {
+// println("Type bound kind");
+// super.visitTypeBoundKind(that);
+// }
+
+ public void visitModifiers (JCModifiers tree) {
+ if (tree.getFlags().isEmpty() && tree.annotations.isEmpty()) {
+ return; // print nothing if we have no modifiers or
annotations
+ }
+ println("Modifiers: " + tree.getFlags());
+ super.visitModifiers(tree);
+// scan(tree.annotations);
+ }
+
+ public void visitAnnotation (JCAnnotation tree) {
+ println("Annotation");
+ super.visitAnnotation(tree);
+// scan(tree.annotationType);
+// scan(tree.args);
+ }
+
+// public void visitAnnotatedType (JCAnnotatedType tree) {
+// println("Annotated type");
+// super.visitAnnotatedType(tree);
+// // scan(tree.annotations);
+// // scan(tree.underlyingType);
+// }
+
+ public void visitErroneous (JCErroneous tree) {
+ println("Erroneousness");
+ super.visitErroneous(tree);
+ }
+
+ public void visitLetExpr (LetExpr tree) {
+ println("Let expr");
+ super.visitLetExpr(tree);
+// scan(tree.defs);
+// scan(tree.expr);
+ }
+
+ protected void println (String text) {
+ for (int ii = 0; ii < _indent; ii++) {
+ System.out.print(" ");
+ }
+ System.out.println(text);
+ }
+
+ protected int _indent;
+ }
+
+ protected static String what (JCTree node)
+ {
+ if (node == null) {
+ return "null";
+ } else {
+ return node.getClass().getSimpleName() + "[" + node + "]";
+ }
+ }
+
+ protected static String what (Symbol sym)
+ {
+ return (sym == null) ? "nullsym" : ("(sym " + sym.type + "/" +
what(sym.completer) + ")");
+ }
+
+ protected static String what (Object obj)
+ {
+ return (obj == null) ? "none" : obj.getClass().getSimpleName();
+ }
+
+ protected Trees _trees;
+ protected Types _types;
+ protected TreeMaker _rootmaker;
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/detyper/Backdoor.java Sat Nov 27 12:15:19
2010
@@ -0,0 +1,139 @@
+//
+// $Id$
+
+package org.ductilej.detyper;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+import com.sun.tools.javac.code.Attribute;
+import com.sun.tools.javac.code.Lint;
+import com.sun.tools.javac.code.Scope;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.comp.Annotate;
+import com.sun.tools.javac.comp.Attr;
+import com.sun.tools.javac.comp.AttrContext;
+import com.sun.tools.javac.comp.Enter;
+import com.sun.tools.javac.comp.MemberEnter;
+import com.sun.tools.javac.comp.Resolve;
+import com.sun.tools.javac.tree.JCTree.*;
+
+/**
+ * Does some backdoor reflective invocation of useful javac internal
methods.
+ */
+public class Backdoor<T>
+{
+ /** Provides type-safe access to reflected fields. */
+ public interface FieldRef<A, V> {
+ public V get (A arg);
+ public void set (A arg, V value);
+ }
+
+ /** Provides type-safe access to reflected methods. */
+ public interface MethodRef<R, V> {
+ public V invoke (R receiver, Object... args);
+ }
+
+ public static final MethodRef<Annotate, Attribute.Compound>
enterAnnotation =
+ newMethodRef(Annotate.class, "enterAnnotation", 3);
+ public static final MethodRef<Enter, Type> classEnter =
+ newMethodRef(Enter.class, "classEnter", 2);
+ public static final MethodRef<Resolve, Symbol> findIdent =
+ newMethodRef(Resolve.class, "findIdent", 3);
+ public static final MethodRef<Resolve, Symbol> findFun =
+ newMethodRef(Resolve.class, "findFun", 6);
+ public static final MethodRef<Resolve, Symbol> findMethod =
+ newMethodRef(Resolve.class, "findMethod", 8);
+ public static final MethodRef<Resolve, Symbol> resolveIdent =
+ newMethodRef(Resolve.class, "resolveIdent", 4);
+ public static final MethodRef<Resolve, Symbol> resolveMethod =
+ newMethodRef(Resolve.class, "resolveMethod", 5);
+ public static final MethodRef<Resolve, Symbol> resolveQualifiedMethod =
+ newMethodRef(Resolve.class, "resolveQualifiedMethod", 6);
+ public static final MethodRef<Resolve, Symbol> resolveConstructor =
+ newMethodRef(Resolve.class, "resolveConstructor", 5);
+ public static final MethodRef<Resolve, Type> instantiate =
+ newMethodRef(Resolve.class, "instantiate", 8);
+ public static final MethodRef<Attr, Symbol> selectSym =
+ newMethodRef(Attr.class, "selectSym", 5);
+ public static final MethodRef<MemberEnter, Type> signature =
+ newMethodRef(MemberEnter.class, "signature", 5);
+
+ public static final FieldRef<AttrContext, Scope> scope =
+ newFieldRef(AttrContext.class, "scope");
+ public static final FieldRef<AttrContext, Lint> lint =
+ newFieldRef(AttrContext.class, "lint");
+ public static final FieldRef<AttrContext, Boolean> selectSuper =
+ newFieldRef(AttrContext.class, "selectSuper");
+ public static final FieldRef<AttrContext, Boolean> varArgs =
+ newFieldRef(AttrContext.class, "varArgs");
+
+ protected static <A, V> FieldRef<A, V> newFieldRef (Class<A> clazz,
String name)
+ {
+ try {
+ for (final Field f : clazz.getDeclaredFields()) {
+ if (f.getName().equals(name)) {
+ f.setAccessible(true);
+ return new FieldRef<A, V>() {
+ public V get (A arg) {
+ try {
+ @SuppressWarnings("unchecked") V result =
(V)f.get(arg);
+ return result;
+ } catch (Exception e) {
+ throw new RuntimeException(unwrap(e));
+ }
+ }
+ public void set (A arg, V value) {
+ try {
+ f.set(arg, value);
+ } catch (Exception e) {
+ throw new RuntimeException(unwrap(e));
+ }
+ }
+ };
+ }
+ }
+ throw new RuntimeException("Unable to find '" + name + "' in "
+ clazz.getName());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected static <R, V> MethodRef<R, V> newMethodRef (Class<R> clazz,
String name, int argCount)
+ {
+ try {
+ for (final Method m : clazz.getDeclaredMethods()) {
+ if (m.getName().equals(name) &&
m.getParameterTypes().length == argCount) {
+ m.setAccessible(true);
+ return new MethodRef<R, V>() {
+ public V invoke (R receiver, Object... args) {
+ try {
+ @SuppressWarnings("unchecked") V result =
(V)m.invoke(receiver, args);
+ return result;
+ } catch (Exception e) {
+ throw new RuntimeException(unwrap(e));
+ }
+ }
+ @Override public String toString () {
+ return m.getName();
+ }
+ };
+ }
+ }
+ throw new RuntimeException(
+ "Unable to locate " + clazz.getSimpleName() + "." + name
+ " method.");
+ } catch (Exception e) {
+ throw new RuntimeException(
+ "Unable to access " + clazz.getSimpleName() + "." + name
+ " method.");
+ }
+ }
+
+ protected static Throwable unwrap (Throwable t)
+ {
+ return (t instanceof RuntimeException && t.getCause() != null) ?
unwrap(t.getCause()) : t;
+ }
+
+ protected Method _method;
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/detyper/Detype.java Sat Nov 27 12:15:19 2010
@@ -0,0 +1,1704 @@
+//
+// $Id$
+
+package org.ductilej.detyper;
+
+import javax.tools.JavaFileObject;
+
+import com.sun.source.tree.Tree;
+import com.sun.tools.javac.code.BoundKind;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Kinds;
+import com.sun.tools.javac.code.Lint;
+import com.sun.tools.javac.code.Scope;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.TypeTags;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.Annotate;
+import com.sun.tools.javac.comp.Attr;
+import com.sun.tools.javac.comp.AttrContext;
+import com.sun.tools.javac.comp.Enter;
+import com.sun.tools.javac.comp.Env;
+import com.sun.tools.javac.comp.MemberEnter;
+import com.sun.tools.javac.file.BaseFileObject;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.tree.TreeMaker;
+import com.sun.tools.javac.tree.TreeScanner;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Name; // Name.Table -> Names in OpenJDK
+import com.sun.tools.javac.util.Names;
+
+import org.ductilej.runtime.Binop;
+import org.ductilej.runtime.Debug;
+import org.ductilej.runtime.RT;
+import org.ductilej.runtime.Transformed;
+import org.ductilej.runtime.Unop;
+import org.ductilej.util.ASTUtil;
+import org.ductilej.util.PathedTreeTranslator;
+
+/**
+ * Performs the actual detyping.
+ */
+public class Detype extends PathedTreeTranslator
+{
+ /** Whether or not to remove methods from interfaces (TEMP). */
+ public static boolean KEEPIFCS =
Boolean.getBoolean("org.ductilej.keepifcs");
+
+ /** Whether or not to use full coercions in place of implicit
widenings. */
+ public static boolean COERCEALL =
Boolean.getBoolean("org.ductilej.coerceall");
+
+ /**
+ * Returns the detyping tree translator.
+ */
+ public static Detype instance (Context context)
+ {
+ Detype instance = context.get(DETYPE_KEY);
+ if (instance == null) {
+ instance = new Detype(context);
+ }
+ return instance;
+ }
+
+ /**
+ * Converts the supplied detype context into an attr context. Note:
the resulting context will
+ * not contain everything an AttrContext might normally contain. This
is only usable in
+ * situations where you carefully verify that javac's internals aren't
relying on things this
+ * conversion does not provide.
+ */
+ public static Env<AttrContext> toAttrEnv (Env<DetypeContext> env)
+ {
+ if (env == null) {
+ return null;
+ }
+
+ // copy over (translating along the way) our Env bits
+ Env<AttrContext> aenv = new Env<AttrContext>(env.tree, new
AttrContext());
+ aenv.next = toAttrEnv(env.next);
+ aenv.outer = toAttrEnv(env.outer);
+ aenv.toplevel = env.toplevel;
+ aenv.enclClass = env.enclClass;
+ aenv.enclMethod = env.enclMethod;
+ aenv.baseClause = env.baseClause; // not used by detype
+
+ // copy over detype context parts that are useful to attr context
+ Backdoor.scope.set(aenv.info, env.info.scope);
+ Backdoor.lint.set(aenv.info, env.info.lint);
+
+ return aenv;
+ }
+
+ /**
+ * Detypes the supplied compilation unit.
+ */
+ public void detype (JCCompilationUnit tree)
+ {
+ Env<DetypeContext> oenv = _env;
+ try {
+ _env = new Env<DetypeContext>(tree, new DetypeContext());
+ _env.toplevel = tree;
+ _env.enclClass = _predefClassDef;
+ _env.info.scope = tree.namedImportScope;
+ _env.info.lint = _lint;
+ tree.accept(this);
+ } catch (RuntimeException rte) {
+ Debug.warn("Fatal error", "file", tree.sourcefile);
+ throw rte;
+ } finally {
+ _env = oenv;
+ }
+ }
+
+ @Override public void visitTopLevel (JCCompilationUnit tree)
+ {
+ _tmaker = _rootmaker.forToplevel(tree);
+ super.visitTopLevel(tree);
+ }
+
+ @Override public void visitImport (JCImport tree) {
+ super.visitImport(tree);
+
+ // if this is a static method import, we want to remove it; the
method being imported may
+ // be renamed and in any event will not appear in the detyped
source of this class (all
+ // calls will be rewritten to invokeStatic)
+ if (tree.isStatic() && TreeInfo.name(tree.qualid) !=
_names.asterisk &&
+ !isVarImport(tree)) {
+ result = _tmaker.at(tree.pos).Skip();
+ }
+ }
+
+ @Override public void visitClassDef (JCClassDecl tree)
+ {
+ Debug.log("Visiting class '" + tree.name + "'", "sym", tree.sym);
+
+ // don't detype annotation classes; that causes myriad problems
+ if ((tree.mods.flags & Flags.ANNOTATION) != 0) {
+ result = tree;
+ return;
+ }
+
+ // local classes have not yet been entered, so we must manually do
so
+ JCClassDecl ctree = tree;
+ if (ctree.sym == null) {
+ // clone the tree to avoid modifying the AST in ways that will
confuse javac later
+ ctree = (JCClassDecl)ctree.clone();
+
+ JavaFileObject ofile =
_log.useSource(_env.toplevel.getSourceFile());
+ try {
+ Backdoor.classEnter.invoke(_enter, ctree, toAttrEnv(_env));
+ } finally {
+ _log.useSource(ofile);
+ }
+
+ // the above call set up MemberEnter as a completer, we must
now trigger it to cause
+ // entry to take place on all of the inner class's members
+ ctree.sym.complete();
+ Debug.log("Entered inner class '" + ctree.name + "'", "sym",
ctree.sym);
+ // ASTUtil.dumpSyms(ctree);
+ }
+
+ // the entering process should have created an environment for the
entered class, we need
+ // to extract its scope and use that in our environment so that
if/when we ask Resolve to
+ // do things, it ends up using the correct scope
+ Env<AttrContext> eenv = _enter.getEnv(ctree.sym);
+ // however, anonymous inner classes seem not to have an
environment created?
+ Scope escope;
+ if (eenv == null) {
+ Debug.warn("No enter scope for " + ctree.sym);
+ escope = new Scope(ctree.sym);
+ } else {
+ escope = Backdoor.scope.get(eenv.info);
+ }
+
+ // note the environment of the class we're processing
+ Env<DetypeContext> oenv = _env;
+ _env = _env.dup(ctree, oenv.info.dup(escope));
+ _env.enclClass = ctree;
+ _env.outer = oenv;
+
+ if (tree.name != _names.empty) {
+ // add our @Transformed annotation to the AST
+ JCAnnotation a = _tmaker.at(tree.pos).Annotation(
+ mkFA(Transformed.class.getName(), tree.pos),
List.<JCExpression>nil());
+ tree.mods.annotations = tree.mods.annotations.prepend(a);
+
+ // since the annotations AST has already been resolved into
type symbols, we have
+ // to manually add a type symbol for annotation to the
ClassSymbol
+ if (tree.sym != null) {
+ tree.sym.attributes_field =
tree.sym.attributes_field.prepend(
+ Backdoor.enterAnnotation.invoke(
+ _annotate, a, _syms.annotationType,
_enter.getEnv(tree.sym)));
+ }
+ }
+
+ // if this is an interface declaration, remove all method
declarations; we don't need them
+ // since all application methods are called reflectively, and if
we leave them here, they
+ // cause problems if classes don't implement the entire interface
(or inherit
+ // implementations from library classes)
+ if (!KEEPIFCS /*temp*/ && (ctree.sym.flags() & Flags.INTERFACE) !=
0) {
+ tree.defs = removeMethodDefs(tree.defs);
+ }
+
+ super.visitClassDef(ctree);
+ result = tree; // finally restore our unmodified tree
+ _env = oenv;
+ }
+
+ @Override public void visitMethodDef (JCMethodDecl tree)
+ {
+ Debug.log("Visiting method def", "name", tree.name);
+
+ // if we're visiting a method in a local or anonymous inner class,
we need to fake up
+ // symbols for our methods so that any local or anonymous inner
classes therein have value
+ // owner symbols; normally this happens when classes are
completed, but we can't complete
+ // our fake-entered classes without causing the compiler to fall
over later when it goes to
+ // do everything properly
+ if (tree.sym == null) {
+ Scope enclScope = (_env.tree.getTag() == JCTree.CLASSDEF) ?
+ ((JCClassDecl) _env.tree).sym.members_field :
_env.info.scope;
+// Type msig = Backdoor.signature.invoke(_memberEnter,
tree.typarams, tree.params,
+// tree.restype,
tree.thrown, toAttrEnv(_env));
+ Type msig = null;
+ // Debug.temp("Computed sig " + msig + " for " + tree);
+ tree.sym = new MethodSymbol(0, tree.name, msig,
enclScope.owner);
+ // tree.sym.flags_field = chk.checkFlags(tree.pos(),
tree.mods.flags, m, tree);
+ }
+
+ // in very limited circumstances (currently only for JUnit
TestCase constructors) we leave
+ // things completely intact (detyping neither the arguments nor
the method body)
+ if (isUndetypableMethod(tree)) {
+ result = tree;
+ return;
+ }
+
+ // create a local environment for this method definition
+ Env<DetypeContext> oenv = _env;
+ _env = _env.dup(tree,
oenv.info.dup(oenv.info.scope.dupUnshared()));
+ _env.enclMethod = tree;
+ _env.info.scope.owner = tree.sym;
+
+ // enter all type parameters into the local method scope
+ for (List<JCTypeParameter> l = tree.typarams; l.nonEmpty(); l =
l.tail) {
+ _env.info.scope.enterIfAbsent(l.head.type.tsym);
+ }
+
+ // if we're not in a library overrider, prepare our type-carrying
arguments (before we call
+ // super which will erase our argument's types)
+ boolean isLib = inLibraryOverrider();
+ // note: toTypeArgs has the side-effect that it turns off the
varargs flag on a varargs
+ // final argument because it "moves" the varargs flag to the final
type argument instead
+ List<JCVariableDecl> sigargs = isLib ?
List.<JCVariableDecl>nil() : toTypeArgs(tree.params);
+
+ // now we can call super and translate our children
+ super.visitMethodDef(tree);
+
+ // remove @Override annotations because those may cause problems
if they exist on an
+ // application interface method which has been removed from the
interface
+ tree.mods.annotations =
removeOverrideAnnotation(tree.mods.annotations);
+
+ // transform the return type if we're not in a library overrider
and it is not void
+ if (tree.restype != null && !ASTUtil.isVoid(tree.restype)
&& !isLib) {
+ tree.restype = _tmaker.Ident(_names.fromString("Object"));
+ }
+
+ // if we have type-carrying arguments to append, do so now
+ if (!sigargs.isEmpty()) {
+ // if we're signature mangling a non-constructor, note that in
its name
+ if (tree.name != _names.init) {
+ tree.name =
tree.name.append(_names.fromString(RT.MM_SUFFIX));
+ }
+ tree.params = tree.params.appendList(sigargs);
+
+ // if we are in a library overrider, we need to rename the formal
arguments and insert
+ // value carrying arguments for use in the method body:
+ // void someLibMethod (String arg1, int arg2) { ... } becomes
+ // void someLibMethod (String arg1$T, int arg2$T) {
+ // Object arg1 = arg1$T, arg2 = arg2$T; ... }
+ } else if (!tree.params.isEmpty() && tree.body != null) {
+ // we'll never have to insert shadow arguments into a
constructor because a constructor
+ // is never a library signature overrider; this it will always
be safe to jam
+ // declarations at the top of our method body (it would not be
safe to do so in a
+ // constructor because they'd end up above the super() call)
+ for (List<JCVariableDecl> p = tree.params; !p.isEmpty(); p =
p.tail) {
+ Name valname = p.head.name;
+ p.head.name = _names.fromString(valname + "$T");
+ tree.body.stats = tree.body.stats.prepend(
+ // preserve the flags (e.g. final), but strip off
PARAMETER as our synthesized
+ // shadow field is not, in fact, a method parameter
+ _tmaker.VarDef(_tmaker.Modifiers(p.head.mods.flags &
~Flags.PARAMETER),
+ valname, typeToTree(_syms.objectType,
p.head.pos),
+ _tmaker.Ident(p.head.name)));
+ }
+ }
+
+ // restore our previous environment
+ _env = oenv;
+ }
+
+ @Override public void visitVarDef (JCVariableDecl tree)
+ {
+ boolean isEnumDecl = (tree.sym != null) && Flags.isEnum(tree.sym);
+
+ // var symbols for member-level variables are already entered, we
just want to handle
+ // formal parameters and local variable declarations
+ if (_env.tree.getTag() != JCTree.CLASSDEF && !isEnumDecl) {
+ // create a placeholder VarSymbol for this variable so that we
can use it later
+ // during some simple name resolution
+ Type vtype = _resolver.resolveType(_env, tree.vartype,
Kinds.TYP);
+ // Debug.temp("Creating var symbol", "name",
tree.name, "type", vtype);
+ _env.info.scope.enter(new VarSymbol(0, tree.name, vtype,
_env.info.scope.owner));
+ }
+
+ // we need a new environment here to keep our Env tree isomorphic
to javac's
+ Env<DetypeContext> oenv = _env;
+ _env = _env.dup(tree, oenv.info.dup());
+ if (tree.sym != null && tree.sym.owner != null &&
tree.sym.owner.kind == Kinds.TYP) {
+ _env.info.scope = new Scope.DelegatedScope(_env.info.scope);
+ _env.info.scope.owner = tree.sym;
+ }
+// TODO: do we need static level?
+// if ((tree.mods.flags & STATIC) != 0 ||
+// (_env.enclClass.sym.flags() & INTERFACE) != 0)
+// _Env.info.staticLevel++;
+
+ // if we're declaring an array, put its type in the arrayElemType
as we may encounter a
+ // bare array initializer expression (i.e. int[] foo = { 1, 2, 3})
and we'll need to use
+ // this declared type when detyping the initializer
+ if (tree.vartype instanceof JCArrayTypeTree) {
+ _env.info.arrayElemType = tree.vartype;
+ }
+
+ // if the declaration has primitive type and an initializer, we
need to resolve the type of
+ // the initializer expression so that we can determine whether we
need coercions
+ boolean isPrimitive = tree.vartype.getTag() == JCTree.TYPEIDENT;
+ Type itype = (!isPrimitive || tree.init == null) ? null :
+ _resolver.resolveType(_env, tree.init, Kinds.VAL);
+
+ // determine whether we're defining a constant (a final variable
that references a constant
+ // expression, e.g. final int foo = 3)
+ boolean isConstDecl = isConstDecl(tree);
+
+ // we don't want to detype the initializer of a const field, it
would break the const-ness
+ // of switch case expressions, and it would prevent the constant
from being inlined (the
+ // latter in theory shouldn't change semantics but don't ask me to
provide a proof)
+ if (!isConstDecl) {
+ super.visitVarDef(tree);
+ } else {
+ result = tree;
+ }
+ _env = oenv;
+
+ String path = path();
+ if (isConstDecl || isEnumDecl ||
+ // don't detype the param(s) of a catch block
+ path.endsWith(".Catch") ||
+ // nor the arguments of a library
+ (path.contains(".MethodDef.params") && inLibraryOverrider())) {
+ return;
+ }
+
+ // if we're about to transform a primitive field with no
initializer, we need to synthesize
+ // an initializer that mimics the default initialization provided
for primitive fields
+ if (path.endsWith(".ClassDef") && tree.init == null && isPrimitive
&&
+ // if the field is final, they must assign it a non-default
value in the constructor,
+ // so we need not (and indeed cannot) supply a synthesized
initializer
+ !ASTUtil.isFinal(tree.mods)) {
+ // if this is an instance field, we have to do some reflection
finagling to obtain our
+ // default value because the field *may* have already been
initialized by an overridden
+ // method called from the superclass constructor; static
fields pose no such risk
+ if ((tree.mods.flags & Flags.STATIC) == 0) {
+ tree.init = callRT("initPrimitive", tree.pos,
+ _tmaker.Ident(_names._this),
+ _tmaker.Literal(tree.name.toString()),
+ classLiteral(tree.vartype, tree.pos));
+ } else {
+ // all primitive literals use (integer) 0 as their value
(even boolean)
+ tree.init =
_tmaker.Literal(((JCPrimitiveTypeTree)tree.vartype).typetag, 0);
+ }
+
+ // if the vardef is a primitive and has an initializer, we may
need to emulate an implicit
+ // narrowing or widening conversion if the rvalue differs from the
type of the lvalue
+ } else if (isPrimitive && tree.init != null) {
+ int vtag = ((JCPrimitiveTypeTree)tree.vartype).typetag;
+ // TODO: only implicitly narrow when RHS is a constant expr?
+ if (vtag != itype.tag &&
+ !_types.isSameType(_types.boxedClass(_syms.typeOfTag[vtag]).type,
itype))
{
+ tree.init = callRT("coerce", tree.init.pos,
+ classLiteral(tree.vartype,
tree.init.pos), tree.init);
+ }
+
+ // lastly, if this is just a plain old vardef with no initializer,
we add a default
+ // initializer to relax the requirement for definite assignment
+ } else if (RELAX_DEFASSIGN && tree.init == null &&
+ !path.endsWith(".ClassDef") &&
+ !path.endsWith("MethodDef.params") &&
+ !path.endsWith("Block.ForeachLoop") &&
+ !ASTUtil.isFinal(tree.mods)) {
+ tree.init = _tmaker.Literal(
+ isPrimitive ?
((JCPrimitiveTypeTree)tree.vartype).typetag : TypeTags.BOT, 0);
+ }
+
+ // Debug.log("Xforming vardef", "mods", tree.mods, "name",
tree.name, "init", tree.init);
+ tree.vartype = _tmaker.Ident(_names.fromString("Object"));
+ if (ASTUtil.isVarArgs(tree.mods.flags)) {
+ tree.vartype = _tmaker.TypeArray(tree.vartype);
+ }
+ }
+
+ @Override public void visitReturn (JCReturn tree)
+ {
+ super.visitReturn(tree);
+
+ // if we're in a method whose signature cannot be transformed, we
must cast the result of
+ // the return type back to the static method return type
+ if (tree.expr != null && inLibraryOverrider()) {
+ if (_env.enclMethod.sym.type == null) {
+ Debug.warn("Enclosing method missing type?",
+ "class",
((BaseFileObject)_env.toplevel.sourcefile).getShortName(),
+ "meth", _env.enclMethod);
+ } else {
+ // Debug.temp("Casting back to return type", "meth",
_env.enclMethod.sym.type);
+ tree.expr =
cast(_env.enclMethod.sym.type.asMethodType().restype, tree.expr);
+ }
+ }
+ }
+
+ @Override public void visitUnary (JCUnary tree)
+ {
+ // we don't call super because mkAssign needs the untranslated
expr for ++ and --
+
+ JCExpression expr = unop(tree.pos, tree.getKind(),
translate(tree.arg));
+ switch (tree.getKind()) {
+ case PREFIX_INCREMENT: // ++i -> (i = unop("++", i))
+ case POSTFIX_INCREMENT: // i++ -> unop("--", i = unop("++", i))
+ expr = mkAssign(tree.arg, expr, tree.pos);
+ if (tree.getKind() == Tree.Kind.POSTFIX_INCREMENT) {
+ // we use unop("--", e) here instead of binop("-", e, 1)
because unop-- avoids
+ // promoting its operand to int
+ expr = unop(tree.pos, Tree.Kind.POSTFIX_DECREMENT, expr);
+ }
+ break;
+
+ case PREFIX_DECREMENT: // --i -> (i = unop("--", i))
+ case POSTFIX_DECREMENT: // i-- -> unop("++", i = unop("--", i))
+ expr = mkAssign(tree.arg, expr, tree.pos);
+ if (tree.getKind() == Tree.Kind.POSTFIX_DECREMENT) {
+ // we use unop("++", e) here instead of binop("+", e, 1)
because unop++ avoids
+ // promoting its operand to int
+ expr = unop(tree.pos, Tree.Kind.POSTFIX_INCREMENT, expr);
+ }
+ break;
+ }
+
+ // Debug.log("Rewrote unop: " + tree + " -> " + expr);
+ result = expr;
+ }
+
+ @Override public void visitBinary (JCBinary tree)
+ {
+ super.visitBinary(tree);
+
+ switch (tree.getTag()) {
+ case JCTree.AND:
+ case JCTree.OR:
+ // and and or short-circuit, so we cannot turn them into a two
argument function call,
+ // we instead have to cast the left- and right-hand-sides back
to boolean and leave
+ // them inline
+ tree.lhs = callRT("asBoolean", tree.lhs.pos, tree.lhs);
+ tree.rhs = callRT("asBoolean", tree.rhs.pos, tree.rhs);
+ result = tree;
+ break;
+
+ default:
+ result = binop(tree.pos, tree.getKind(), tree.lhs, tree.rhs);
+ // Debug.log("Rewrote binop", "kind", tree.getKind(), "tp",
tree.pos);
+ break;
+ }
+ }
+
+ @Override public void visitAssignop (JCAssignOp tree)
+ {
+ // we don't call super because mkAssign needs the untranslated LHS
+
+ // assign ops implicitly coerce the result back to the type of the
left-hand-side, so we
+ // need to resolve said lhs type and insert a coercion
+ Type ltype = _resolver.resolveType(_env, tree.lhs, Kinds.VAR);
+
+ // we create this temporary JCBinary so that we can call
bop.getKind() below which calls
+ // into non-public code that would otherwise be annoying to call
+ JCExpression bop = _tmaker.Binary(tree.getTag() -
JCTree.ASGOffset, tree.lhs, tree.rhs);
+ bop = binop(tree.pos, bop.getKind(), translate(tree.lhs),
translate(tree.rhs));
+ // if the lhs is a primitive, we need to insert a coercion back to
its type; this is
+ // because 'shortv += intv' is equivalent to 'shortv =
(short)(shortv + intv)'.
+ if (ltype.isPrimitive()) {
+ bop = callRT("coerce", bop.pos, classLiteral(ltype, bop.pos),
bop);
+ }
+
+ // TODO: this a problem wrt evaluating the LHS more than once, we
need emit special code
+ // depending on the LHS (i.e. assignOpAt("+", array, val, idx),
etc.)
+ result = mkAssign(tree.lhs, bop, tree.pos);
+ // Debug.log("Rewrote assignop", "kind", tree.getKind(), "into",
result);
+ }
+
+ @Override public void visitNewClass (JCNewClass tree)
+ {
+// Debug.log("Class instantiation", "typeargs",
tree.typeargs, "class", what(tree.clazz),
+// "args", tree.args);
+
+ // we need a new environment here to keep our Env tree isomorphic
to javac's
+ Env<DetypeContext> oenv = _env;
+ _env = _env.dup(tree, oenv.info.dup());
+
+ // enums are already desugared somewhat by the time we are called;
the AST looks like so:
+ // public enum Type {
+ // /*public static final*/ ADD /* = new Type() */
+ // }
+ // we need to specially handle these desugared enum constructor
calls
+ boolean inEnumFieldInit = path().endsWith(".ClassDef.VarDef") &&
+ Flags.isEnum(_env.enclClass.sym);
+
+ // we can only transform the constructor into a reflective call if
we're not in an enum
+ // field initializer and we're not looking at an anonmyous inner
class declaration
+ boolean canReflect = (tree.def == null && !inEnumFieldInit);
+
+ // If we are seeing a qualified new, of the form:
+ // <expr>.new C <...> (...) ...
+ // we let clazz stand for the name of the allocated class C
prefixed with the type of the
+ // qualifier expression, so that we can resolve it with standard
techniques later. If
+ // <expr> has type T, then <expr>.new C <...> (...) yields a clazz
T.C.
+ JCExpression clazz = tree.clazz;
+ Type enctype = null;
+ if (tree.encl != null) {
+ enctype = _resolver.resolveType(_env, tree.encl, Kinds.VAL);
+ JCExpression clazzid = (clazz.getTag() == JCTree.TYPEAPPLY) ?
+ ((JCTypeApply) clazz).clazz : clazz;
+ clazzid = _tmaker.at(clazz.pos).Select(
+ typeToTree(enctype, clazz.pos), ((JCIdent) clazzid).name);
+ if (clazz.getTag() == JCTree.TYPEAPPLY) {
+ clazz = _tmaker.at(tree.pos).TypeApply(clazzid,
((JCTypeApply) clazz).arguments);
+ } else {
+ clazz = clazzid;
+ }
+ }
+
+ Resolver.MethInfo mi = _resolver.resolveConstructor(
+ _env, clazz, tree.args, tree.typeargs, tree.def != null);
+ Type ctype = mi.isValid() ? mi.site : _resolver.resolveType(_env,
clazz, Kinds.TYP);
+
+ // do some special processing for anonymous inner class
instantiation expressions
+ if (tree.def != null) {
+ _env.info.anonParent = ctype.tsym;
+ // Attr does some massaging of anonymous JCClassDecls which we
need to manually
+ // duplicate here because attribution won't happen for a
while, but we want to
+ // sneakily (and correctly) enter our anonymous inner class
+ if (ctype.tsym.isInterface()) {
+ tree.def.implementing = List.of(tree.clazz);
+ } else {
+ tree.def.extending = tree.clazz;
+ }
+ }
+
+ super.visitNewClass(tree);
+
+ if (canReflect) {
+ // if there is a specific enclosing instance provided, pass it
to newInstance()
+ JCExpression thisex;
+ if (tree.encl != null) {
+ thisex = tree.encl;
+ // we can no longer just use tree.clazz as our class
literal because the enclosing
+ // reference moves us into its namespace; thus outer.new
Inner() needs to result in
+ // a reflective instantiation of Outer.Inner.class not
just Inner.class; we already
+ // generated our fully qualified class name above, so we
use it here
+ tree.clazz = clazz;
+
+ // if we failed to resolve the class type, just do nothing for
now (TODO)
+ } else if (ctype == null) {
+ thisex = _tmaker.at(tree.pos).Literal(TypeTags.BOT, null);
+
+ // if we're in a static state or have a static inner class,
pass null
+ } else if (inStatic() || ctype.getEnclosingType() ==
Type.noType) {
+ thisex = _tmaker.at(tree.pos).Literal(TypeTags.BOT, null);
+
+ // otherwise we have to figure out the appropriate implicit
enclosing this
+ } else {
+ // we may be looking at a situation like:
+ // class A { class B {} class C { foo() { new B(); }}}
+ // in which case "this" is C.this but we really need
A.this to instantiate a B, so
+ // we have to resolve the "outer" type of the class we're
instantiating and compare
+ // it to the current enclosing class
+ Type otype = _types.erasure(ctype.getEnclosingType());
+ if
(_types.isSubtype(_types.erasure(_env.enclClass.sym.type), otype)) {
+ thisex = _tmaker.at(tree.pos).Ident(_names._this);
+ } else {
+ // we can't just use the owner type as we may be an
inner class inside a
+ // subtype of the owner type and we cannot use
Parent.this, we must use
+ // Child.this if we're defined in Child; so we step
outward through our
+ // enclosing types looking for the type that is a
subtype of the owner
+ Type etype = getEnclosingSubtype(
+ otype, _types.erasure(_env.enclClass.sym.type));
+ thisex = _tmaker.at(tree.pos).Select(typeToTree(etype,
tree.pos), _names._this);
+ }
+ }
+
+ // TODO: we can't reflectively create anonymous inner classes
so maybe we should not
+ // detype any constructor invocation...
+ JCMethodInvocation invoke = callRT(
+ "newInstance", tree.pos, classLiteral(tree.clazz,
tree.clazz.pos),
+ mkSigArgs(mi, tree.pos), thisex,
+ mkArray(_tmaker.Ident(_names.fromString("Object")),
tree.args));
+ invoke.varargsElement = tree.varargsElement;
+ result = invoke;
+
+ } else { /* !canReflect */
+ // if we didn't rewrite the constructor call to newInstance(),
we need to insert either
+ // runtime casts to the the formal parameter types, or type
carrying args
+ if (!tree.args.isEmpty() ||
+ // if we have a no-args call to a varargs constructor, we
can't leave it as a
+ // no-args call because the callee may have been detyped;
we need to insert an
+ // empty array in the varargs position and the type
carrying arg for the varargs
+ // array; if the callee is a library constructor, the
castList() call will noop
+ ASTUtil.isVarArgs(mi.msym.flags())) {
+ List<Type> ptypes = _resolver.instantiateType(_env,
mi).asMethodType().argtypes;
+ if (ASTUtil.isLibrary(_env.info.anonParent)) {
+ tree.args = castList(ptypes, tree.args);
+ } else {
+ tree.args = addManglingArgs(mi.msym, ptypes,
tree.args, mi.atypes, tree.pos);
+ }
+ }
+
+ // if we have an explicit enclosing instance, we need to
insert a cast of that instance
+ // back to its static type as it will likely have been detyped
+ if (tree.encl != null) {
+ tree.encl = _tmaker.TypeCast(typeToTree(enctype,
tree.encl.pos), tree.encl);
+ // NOTE: we'd like to use 'cast(enctype, tree.encl)'
above, but that triggers a bug
+ // in javac, so we have to insert a static cast directly;
this *could* result in an
+ // "unnecessary cast" warning, but c'est la vie
+ }
+ }
+
+ // finally restore our previous environment
+ _env = oenv;
+ }
+
+ @Override public void visitNewArray (JCNewArray tree)
+ {
+ // determine the type of the array elements
+ JCExpression etype = tree.elemtype;
+ if (etype == null) {
+ // if we're seeing something like 'int[] foo = { 1, 2, 3 }' or
we're inside a
+ // multidimensional initializer like 'int[][] foo = new int[]
{{ 1, 2, 3}, { 1 }}'
+ // we'll have stuffed our element type into the context
+ if (_env.info.arrayElemType instanceof JCArrayTypeTree) {
+ etype =
((JCArrayTypeTree)_env.info.arrayElemType).elemtype;
+ }
+ }
+
+ // note our current array element type in our context
+ JCExpression oetype = _env.info.arrayElemType;
+ _env.info.arrayElemType = etype;
+ // now translate any nested expressions
+ super.visitNewArray(tree);
+ // restore our previous array element type
+ _env.info.arrayElemType = oetype;
+
+ // Debug.log("Array creation", "expr", tree, "dims",
tree.dims, "elems", tree.elems);
+
+ // we need to cast the dimension expressions to int
+ tree.dims = castIntList(tree.dims);
+
+ if (etype == null) {
+ // do nothing, we're probably looking at syntactically
incorrect code
+ } else if (tree.elems != null) {
+ // if our argument is is a single element which is a null
literal, we need to add a
+ // cast to Object as we're going to translate it into a call
of the form:
+ // RT.boxArrayArgs(Type.class, null)
+ // which will be an ambiguous use of varargs
+ if (tree.elems.size() == 1 &&
ASTUtil.isNullLiteral(tree.elems.head)) {
+ tree.elems.head = toTypedNull(_syms.objectType,
tree.elems.head);
+ }
+ result = callRT("boxArrayArgs", tree.pos,
+ tree.elems.prepend(classLiteral(etype,
etype.pos)));
+ } else {
+ result = callRT("boxArray", tree.pos, classLiteral(etype,
etype.pos), tree);
+ }
+ }
+
+ @Override public void visitSelect (JCFieldAccess tree)
+ {
+ super.visitSelect(tree);
+
+ // if we know for sure this is a static select, then stop here
+ if (!TreeInfo.nonstaticSelect(tree)) {
+ return;
+ }
+
+ // determine if we're somewhere that we know we shouldn't be
fooling around
+ String path = path();
+ boolean wantXform = true;
+ wantXform = wantXform && !path.contains(".TopLevel.pid");
+ wantXform = wantXform && !path.contains(".Import");
+ wantXform = wantXform && !path.contains(".Annotation");
+ wantXform = wantXform && !path.endsWith(".Apply.meth");
+ wantXform = wantXform && !path.contains(".VarDef.vartype");
+ wantXform = wantXform && !path.contains(".NewClass.clazz");
+ wantXform = wantXform && !path.contains(".NewArray.type");
+ wantXform = wantXform && !path.contains(".ClassDef.typarams");
+ wantXform = wantXform && !path.contains(".ClassDef.extending");
+ wantXform = wantXform && !path.contains(".ClassDef.implementing");
+ if (!wantXform) {
+ return;
+ }
+
+ // if the selected expression is a static receiver (a class), or
we're looking at a class
+ // literal expression (Foo.class) then we don't want to transform,
otherwise we do
+ if (!_resolver.isStaticSite(_env, tree.selected) && tree.name !=
_names._class) {
+ // transform obj.field into RT.select(obj, "field")
+ result = callRT("select", tree.pos,
_tmaker.Literal(tree.name.toString()),
+ tree.selected);
+ }
+ }
+
+ @Override public void visitApply (JCMethodInvocation tree)
+ {
+// Debug.temp("Method invocation", "typeargs",
tree.typeargs, "method", tree.meth,
+// "args", tree.args, "varargs", tree.varargsElement);
+
+
assert !tree.meth.toString().startsWith(RT.class.getName()) : "Doubly
transforming";
+
+ // if this is a zero args super() call, we'll be doing no detyping
and we just stop here;
+ // normally going through the motions would be of no consequence,
but in the case of
+ // synthesized enum code we run into annoying warnings relating to
the fact that enums have
+ // no legal super constructor
+ Name mname = TreeInfo.name(tree.meth);
+ if (mname == _names._super && tree.args.isEmpty()) {
+ result = tree;
+ return;
+ }
+
+ // resolve the called method before we transform the leaves of
this tree
+ Resolver.MethInfo mi = _resolver.resolveMethod(_env, tree);
+ Symbol statsym = null;
+
+ // if we're not able to resolve the method, we need to obtain some
other information before
+ // we call super.visitApply (as it transforms things we need to
resolve)
+ if (!mi.isValid()) {
+ if (tree.meth instanceof JCFieldAccess) {
+ statsym = _resolver.inferStaticReceiver(_env,
((JCFieldAccess)tree.meth).selected);
+ }
+ }
+
+ // Debug.temp("Method invocation", "tree", tree, "sym", mi.msym);
+
+ // we need to track whether we're processing the arguments of a
this() or super()
+ // constructor because that is a "static" context in that it is
illegal to reference "this"
+ // during that time; there's no nice way to represent that in
path() so instead we track it
+ // explicitly in our environment and reference it in inStatic()...
elegance--.
+ boolean isChainedCons = (mname == _names._super || mname ==
_names._this);
+ boolean oldInChainedCons = _env.info.inChainedCons;
+ _env.info.inChainedCons = _env.info.inChainedCons || isChainedCons;
+ super.visitApply(tree);
+ _env.info.inChainedCons = oldInChainedCons;
+
+ // if this is a chained constructor call or super.foo(), we can't
call it reflectively
+ if (isChainedCons || isSuperMethodCall(tree)) {
+ if (!tree.args.isEmpty()) {
+ assert mi.isValid(); // TODO: cope when we can't resolve
this() or super()
+ // we need to convert any formal type parameters on this
method (as defined in
+ // the super class) to the actuals provided by our class
in the extends clause
+ List<Type> ptypes = _resolver.instantiateType(_env,
mi).asMethodType().argtypes;
+ // if the method is defined in a library class...
+ if (ASTUtil.isLibrary(mi.msym.owner) || // either the
owner is a library
+ // or we're overriding a detyped class that itself
overrides the library
+ ASTUtil.isLibraryOverrider(_types, mi.msym)) {
+ // ...we need to cast the argument types back to the
types it expects
+ tree.args = castList(ptypes, tree.args);
+ } else {
+ // if the declarer is not a library class, we need to
insert type carrying
+ // arguments that match the types of the method we
resolved; if the resolved
+ // method is overloaded, this will disambiguate, and
even if it's not
+ // overloaded, we need something legal in those
argument positions
+ tree.args = addManglingArgs(mi.msym, ptypes,
tree.args, mi.atypes, tree.pos);
+ // we also need to append the "is mangled" tag to the
method name if we're
+ // looking at a super non-constructor call (e.g.
super.foo())
+ if (tree.meth instanceof JCFieldAccess) {
+ ((JCFieldAccess)tree.meth).name =
_names.fromString(mname + RT.MM_SUFFIX);
+ }
+ }
+ }
+ return;
+ }
+
+ // if the receiver is of type Class<?> and the method being called
is newInstance(), we
+ // can't wrap the newInstance() call into a reflective call of our
own because the default
+ // constructor of the class being created may be inaccessible to
RT.invoke() and we have no
+ // opportunity to make it accessible, so calling it would be an
illegal access
+ if (mi.isValid() && mname == _names.fromString("newInstance") &&
+ _types.isSameType(_types.erasure(mi.site),
_types.erasure(_syms.classType))) {
+ // insert a cast to Class<?> if we have a non-implicit
receiver and it's not a C.class
+ // expression (which needs no cast)
+ if (tree.meth.getTag() == JCTree.SELECT) {
+ JCFieldAccess meth = (JCFieldAccess)tree.meth;
+ if (!(meth.selected.getTag() == JCTree.SELECT &&
+ TreeInfo.name(meth.selected) == _names._class)) {
+ meth.selected = cast(_wildcardClass, meth.selected);
+ }
+ }
+ return;
+ }
+
+ String invokeName;
+ JCExpression recv;
+ if (!mi.isValid()) {
+ Debug.temp("Coping with invalid method invocation", "site",
mi.site, "msym", mi.msym);
+ // if we were unable to resolve the target method, try some
fallback heuristics to
+ // determine whether it has a static or non-static receiver
+ if (tree.meth instanceof JCFieldAccess) {
+ if (statsym != null) {
+ String fqName = statsym.getQualifiedName().toString();
+ recv = classLiteral(mkFA(fqName, tree.pos), tree.pos);
+ invokeName = "invokeStatic";
+ } else {
+ recv = ((JCFieldAccess)tree.meth).selected;
+ invokeName = "invoke";
+ }
+ } else {
+ if (inStatic()) {
+ recv = classLiteral(mkFA(fqName, tree.pos), tree.pos);
+ invokeName = "invokeStatic";
+ } else {
+ recv = _tmaker.at(tree.pos).Ident(_names._this);
+ invokeName = "invoke";
+ }
+ }
+
+ } else if (Flags.isStatic(mi.msym)) {
+ // convert to RT.invokeStatic("method", decl.class, args)
+ String fqName = mi.msym.owner.getQualifiedName().toString();
+ recv = classLiteral(mkFA(fqName, tree.pos), tree.pos);
+ // TODO: this causes strangeness in weird places (See
LibInterfaceTest)
+ // recv =
_tmaker.at(tree.pos).ClassLiteral((ClassSymbol)mi.msym.owner);
+ invokeName = "invokeStatic";
+
+ } else if (tree.meth instanceof JCFieldAccess) {
+ // convert to RT.invoke("method", receiver, args)
+ recv = ((JCFieldAccess)tree.meth).selected;
+ invokeName = "invoke";
+
+ } else {
+ // if we're calling a method on an enclosing class, we need to
supply "Enclosing.this"
+ // instead of simply "this" for two reasons: it's more
efficient to do the runtime
+ // method lookup directly on its defining class, and we may be
calling an enclosing
+ // class's method as an argument to super(), where it is
illegal to reference "this"
+ JCExpression thisex;
+ Type etype = _types.erasure(_env.enclClass.sym.type);
+ Type otype = _types.erasure(mi.msym.owner.type);
+ if (_types.isSubtype(etype, otype)) {
+ recv = _tmaker.at(tree.pos).Ident(_names._this);
+ } else {
+ // we can't just use the method owner's type; the method
may be declared in a
+ // parent of our enclosing class and we need the type of
our enclosing class in
+ // our qualified this expression; for example:
+ // class A { void foo (); }
+ // class B extends A {
+ // class C { void bar () {
+ // foo(); // --> RT.invoke("foo", B.this); not A.this
+ // }}}
+ etype = getEnclosingSubtype(otype, etype);
+ recv = _tmaker.at(tree.pos).Select(typeToTree(etype,
tree.pos), _names._this);
+ }
+ // convert to RT.invoke("method", this, args)
+ invokeName = "invoke";
+ }
+
+ // if the method we're calling is varargs, we have to manually
group the variable arguments
+ // into an array so that we can create an array of the correct
dynamic type; for
+ // universally quantified methods, it is only possible at compile
time to know the correct
+ // dynamic type of the array
+ if (mi.isValid() && ASTUtil.isVarArgs(mi.msym.flags())) {
+ List<Type> ptypes = _resolver.instantiateType(_env,
mi).asMethodType().argtypes;
+ tree.args = groupVarArgs(ptypes, tree.args, mi.atypes,
tree.pos);
+ }
+
+ tree.args =
List.of(_tmaker.Literal(TreeInfo.name(tree.meth).toString()),
+ mkSigArgs(mi, tree.meth.pos), recv,
+
mkArray(_tmaker.Ident(_names.fromString("Object")), tree.args));
+ tree.meth = mkRT(invokeName, tree.meth.pos);
+ // Debug.log("APPLY " + mi.msym + " -> " + tree);
+ }
+
+ @Override public void visitSwitch (JCSwitch tree)
+ {
+ // we need to determine the static type of the selector and cast
back to that to avoid a
+ // complex transformation of switch into an equivalent set of if
statements nested inside a
+ // one loop for loop (to preserve 'break' semantics)
+ Type type = _resolver.resolveType(_env, tree.selector, Kinds.VAL);
+
+ // we have to look up the type *before* we transform the switch
expression
+ super.visitSwitch(tree);
+
+ // we have to apply our checked cast *after* we transform the
switch expression
+ if (type == null) {
+ Debug.warn("Can't resolve type for switch " + tree.selector);
+
+ } else if (Flags.isEnum(type.tsym)) {
+ tree.selector = cast(type, tree.selector);
+
+ } else {
+ // for integer types, we need to use asInt() rather than
casting to Integer because
+ // Java won't unbox and then coerce, whereas it will coerce;
so if our switch
+ // expression is int and the case constants are char,
compilation will fail if we
+ // promote the int to Integer
+ tree.selector = callRT("asInt", tree.selector.pos,
tree.selector);
+ }
+ }
+
+ @Override public void visitIf (JCIf tree)
+ {
+ super.visitIf(tree);
+ // we need to cast the if expression to boolean
+ tree.cond = condCast(tree.cond);
+ }
+
+ @Override public void visitAssert (JCAssert tree)
+ {
+ super.visitAssert(tree);
+ // we need to cast the assert expression to boolean
+ tree.cond = condCast(tree.cond);
+ }
+
+ @Override public void visitConditional (JCConditional tree)
+ {
+ super.visitConditional(tree);
+ // we need to cast the if expression to boolean
+ tree.cond = condCast(tree.cond);
+ }
+
+ @Override public void visitDoLoop (JCDoWhileLoop tree)
+ {
+ super.visitDoLoop(tree);
+ // we need to cast the while expression to boolean
+ tree.cond = condCast(tree.cond);
+ }
+
+ @Override public void visitWhileLoop (JCWhileLoop tree)
+ {
+ super.visitWhileLoop(tree);
+ // we need to cast the while expression to boolean
+ tree.cond = condCast(tree.cond);
+ }
+
+ @Override public void visitForLoop (JCForLoop tree)
+ {
+ super.visitForLoop(tree);
+ // "for (;;)" will have null condition
+ if (tree.cond != null) {
+ // we need to cast the for condition expression to boolean
+ tree.cond = condCast(tree.cond);
+ }
+ }
+
+ @Override public void visitForeachLoop (JCEnhancedForLoop tree)
+ {
+ super.visitForeachLoop(tree);
+
+ // rewrite the foreach loop as: foreach (iter :
RT.asIterable(expr))
+ tree.expr = callRT("asIterable", tree.expr.pos, tree.expr);
+ }
+
+ @Override public void visitTry (JCTry tree)
+ {
+ super.visitTry(tree);
+
+ // insert an inner try/catch that catches WrappedException,
dynamically checks whether its
+ // cause is the caught type and casts and rethrows the cause if so
+ if (!tree.catchers.isEmpty()) {
+ Name cvname = _names.fromString(tree.catchers.head.param.name
+ "$W");
+ JCCatch catcher = _tmaker.Catch(
+ _tmaker.VarDef(_tmaker.Modifiers(0L), cvname,
+
mkFA("org.ductilej.runtime.WrappedException", 0), null),
+ _tmaker.Block(0L, List.of(unwrapExns(cvname,
tree.catchers))));
+ tree.body = _tmaker.Block(
+ 0L, List.<JCStatement>of(_tmaker.Try(tree.body,
List.of(catcher), null)));
+ }
+ }
+
+ @Override public void visitThrow (JCThrow tree) {
+ // if the throw expression is not "new Something"
or "(SomeExn)expr", we need to insert a
+ // dynamic cast back to the expected type of the throw to preserve
exception flow analysis
+ Type etype = null;
+ if (tree.expr.getTag() != JCTree.NEWCLASS && tree.expr.getTag() !=
JCTree.TYPECAST) {
+ etype = _resolver.resolveType(_env, tree.expr, Kinds.VAL);
+ }
+ super.visitThrow(tree);
***The diff for this file has been truncated for email.***
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/detyper/DetypeContext.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,51 @@
+//
+// $Id$
+
+package org.ductilej.detyper;
+
+import com.sun.tools.javac.code.Lint;
+import com.sun.tools.javac.code.Scope;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+
+/**
+ * Used to compute scopes during the detyping process.
+ */
+public class DetypeContext
+{
+ /** The symbols in scope in this context. */
+ public Scope scope = null;
+
+ /** The parent of the anonymous inner class currently being created,
if any. */
+ public Symbol anonParent;
+
+ /** The type of the current array initializer element type, if any. */
+ public JCExpression arrayElemType;
+
+ /** True if we're in the middle of processing a call to this() or
super(). */
+ public boolean inChainedCons;
+
+ /** A record of the lint/SuppressWarnings currently in effect. */
+ public Lint lint;
+
+ /**
+ * Duplicates this context with the specified new scope.
+ */
+ public DetypeContext dup (Scope scope)
+ {
+ DetypeContext ctx = new DetypeContext();
+ ctx.scope = scope;
+ ctx.anonParent = anonParent;
+ ctx.arrayElemType = arrayElemType;
+ ctx.inChainedCons = inChainedCons;
+ return ctx;
+ }
+
+ /**
+ * Duplicates this context with the same scope.
+ */
+ public DetypeContext dup ()
+ {
+ return dup(this.scope);
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/detyper/Processor.java Sat Nov 27 12:15:19
2010
@@ -0,0 +1,137 @@
+//
+// $Id$
+
+package org.ductilej.detyper;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedAnnotationTypes;
+import javax.annotation.processing.SupportedOptions;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.tools.Diagnostic;
+
+import com.sun.source.util.TreePath;
+import com.sun.source.util.Trees;
+
+import com.sun.tools.javac.processing.JavacProcessingEnvironment;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.util.Context;
+
+import org.ductilej.runtime.Debug;
+import org.ductilej.util.ASTUtil;
+
+/**
+ * The main entry point for the detyping processor.
+ */
+@SupportedAnnotationTypes("*")
+@SupportedOptions({Processor.SHOWCLASS_ARG, Processor.WRITECLASS_ARG,
Processor.DEBUG_ARG,
+ Processor.WARNINGS_ARG, Processor.KEEPIFCS_ARG})
+@SupportedSourceVersion(SourceVersion.RELEASE_7)
+public class Processor extends AbstractProcessor
+{
+ @Override // from AbstractProcessor
+ public void init (ProcessingEnvironment procenv)
+ {
+ super.init(procenv);
+
+ if (!(procenv instanceof JavacProcessingEnvironment)) {
+ procenv.getMessager().printMessage(
+ Diagnostic.Kind.WARNING, "Detyper requires javac v1.6.");
+ return;
+ }
+
+ Context ctx = ((JavacProcessingEnvironment)procenv).getContext();
+ _trees = Trees.instance(procenv);
+ _detype = Detype.instance(ctx);
+
+ // note our options
+ _showclass
= "true".equalsIgnoreCase(procenv.getOptions().get(SHOWCLASS_ARG));
+ _writeclass
= "true".equalsIgnoreCase(procenv.getOptions().get(WRITECLASS_ARG));
+ Debug.DEBUG
= "true".equalsIgnoreCase(procenv.getOptions().get(DEBUG_ARG));
+ Resolver.WARNINGS
= "true".equalsIgnoreCase(procenv.getOptions().get(WARNINGS_ARG));
+ Detype.KEEPIFCS
= "true".equalsIgnoreCase(procenv.getOptions().get(KEEPIFCS_ARG));
+ Detype.COERCEALL
= "true".equalsIgnoreCase(procenv.getOptions().get(COERCEALL_ARG));
+
+ Debug.log("Detyper running", "vers", procenv.getSourceVersion());
+ }
+
+ @Override // from AbstractProcessor
+ public boolean process (Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv)
+ {
+ if (_trees == null) {
+ return false;
+ }
+
+ // peskily, we'll get an Element for every top-level class in a
compilation unit, but we
+ // only want to process each compilation unit once, so we have to
manually consolidate
+ List<JCCompilationUnit> units = new ArrayList<JCCompilationUnit>();
+ for (Element elem : roundEnv.getRootElements()) {
+ if (elem instanceof PackageElement) {
+ continue; // nothing to do for package elements
+ }
+ JCCompilationUnit unit = toUnit(elem);
+ if (unit == null) {
+ Debug.warn("Unable to obtain compilation unit for
element", "elem", elem);
+ continue;
+ }
+ // Debug.temp("Root elem " + elem, "unit",
unit.getClass().getSimpleName());
+ if (!units.contains(unit)) {
+ units.add(unit);
+ }
+ }
+
+ for (JCCompilationUnit unit : units) {
+ _detype.detype(unit);
+ if (_showclass) {
+ System.out.println(""+unit);
+ }
+ if (_writeclass) {
+ File dout = new
File(unit.getSourceFile().getName().replace(".java", ".djava"));
+ try {
+ PrintWriter out = new PrintWriter(new
FileWriter(dout));
+ out.print(unit);
+ out.close();
+ } catch (Exception e) {
+ Debug.warn("Failure writing detyped output", "file",
dout, "error", e);
+ }
+ }
+ }
+ return false;
+ }
+
+ protected JCCompilationUnit toUnit (Element element)
+ {
+ TreePath path = _trees.getPath(element);
+ return (path == null) ? null :
(JCCompilationUnit)path.getCompilationUnit();
+ }
+
+ protected Trees _trees;
+ protected Detype _detype;
+ protected boolean _showclass;
+ protected boolean _writeclass;
+
+ // -Aorg.ductilej.debug=true causes debug log messages to be printed
+ protected static final String DEBUG_ARG = "org.ductilej.debug";
+ // -Aorg.ductilej.showclass=true causes classes to be printed after
detyping
+ protected static final String SHOWCLASS_ARG = "org.ductilej.showclass";
+ // -Aorg.ductilej.writeclass=true causes classes to be written to
a .djava file after detyping
+ protected static final String WRITECLASS_ARG
= "org.ductilej.writeclass";
+ // -Aorg.ductilej.warnings=true causes warnings to be printed for
unresolvable symbols
+ protected static final String WARNINGS_ARG = "org.ductilej.warnings";
+ // -Aorg.ductilej.keepifcs=true disables removal of interface method
declarations (TEMP)
+ protected static final String KEEPIFCS_ARG = "org.ductilej.keepifcs";
+ // -Aorg.ductilej.coerceall=true makes primitive narrowing and format
coercions implicit
+ protected static final String COERCEALL_ARG = "org.ductilej.coerceall";
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/detyper/Resolver.java Sat Nov 27 12:15:19
2010
@@ -0,0 +1,896 @@
+//
+// $Id$
+
+package org.ductilej.detyper;
+
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ElementVisitor;
+import javax.tools.JavaFileObject;
+
+import com.sun.tools.javac.code.BoundKind;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Kinds;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Symbol;
+import com.sun.tools.javac.code.Symtab;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.TypeTags;
+import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.comp.Attr;
+import com.sun.tools.javac.comp.AttrContext;
+import com.sun.tools.javac.comp.Env;
+import com.sun.tools.javac.comp.Infer;
+import com.sun.tools.javac.comp.Resolve;
+import com.sun.tools.javac.jvm.ClassReader;
+import com.sun.tools.javac.tree.JCTree.*;
+import com.sun.tools.javac.tree.JCTree;
+import com.sun.tools.javac.tree.TreeInfo;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.List;
+import com.sun.tools.javac.util.Log;
+import com.sun.tools.javac.util.Name;
+import com.sun.tools.javac.util.Names;
+import com.sun.tools.javac.util.Warner;
+
+import org.ductilej.runtime.Debug;
+
+/**
+ * Handles some simple name resolution tasks.
+ */
+public class Resolver
+{
+ /** Whether or not to allow javac to report resolve errors. */
+ public static boolean WARNINGS =
Boolean.getBoolean("org.ductilej.warnings");
+
+ /** Used to return data from {@link #resolveMethod}. */
+ public static class MethInfo {
+ public Type site;
+ public Symbol msym;
+ public List<Type> atypes;
+ public List<Type> tatypes;
+ // were varargs used at this call site? (needed by
Resolve.instantiate)
+ public boolean varArgs;
+
+ /** Returns true if we were able to resolve the method, false if
not. */
+ public boolean isValid () {
+ return msym.kind < Kinds.ERR;
+ }
+ }
+
+ /**
+ * Returns our simple symbol resolver.
+ */
+ public static Resolver instance (Context context)
+ {
+ Resolver instance = context.get(RESOLVER_KEY);
+ if (instance == null) {
+ instance = new Resolver(context);
+ }
+ return instance;
+ }
+
+ /**
+ * Resolves the symbol for the supplied expression. Currently only
handles idents and select
+ * expressions.
+ */
+ public Symbol resolveSymbol (Env<DetypeContext> env, JCTree expr, int
pkind)
+ {
+ Symbol sym;
+ switch (expr.getTag()) {
+ case JCTree.IDENT: {
+ Name name = TreeInfo.name(expr);
+ // Debug.temp("Resolving ident", "name", name, "pkind", pkind);
+ if (WARNINGS) {
+ sym = invoke(env, Backdoor.resolveIdent, _resolve,
+ expr.pos(), Detype.toAttrEnv(env), name,
pkind);
+ } else {
+ sym = invoke(env, Backdoor.findIdent, _resolve,
+ Detype.toAttrEnv(env), name, pkind);
+ }
+ break;
+ }
+
+ case JCTree.SELECT: {
+ JCFieldAccess facc = (JCFieldAccess)expr;
+ Type site = resolveSelectSite(env, facc, pkind);
+ if (site == null) {
+ Debug.warn("Unable to resolve receiver of field select: "
+ expr);
+ return _syms.errSymbol;
+ }
+ sym = invoke(env, Backdoor.selectSym, _attr, facc, site,
Detype.toAttrEnv(env),
+ Type.noType, pkind);
+ break;
+ }
+
+ default:
+ Debug.warn("Unknown expr type in resolveSymbol()", "tag",
expr.getTag(), "expr", expr,
+ "etype", expr.getClass().getSimpleName());
+ return _syms.errSymbol;
+ }
+
+ if (sym.kind >= Kinds.ERR) {
+ Debug.warn("Symbol resolution failed", "expr", expr, "sym",
sym);
+ }
+ return sym;
+ }
+
+ /**
+ * Resolves a constructor for the specified class, given the supplied
arguments and type
+ * arguments, using information in the supplied context. Performs
static resolution to choose
+ * between overloaded candidates.
+ *
+ * @param isAnonInner true if the constructor represents the
instantiation of an anonymous
+ * inner class.
+ */
+ public MethInfo resolveConstructor (Env<DetypeContext> env,
JCExpression clazz,
+ List<JCExpression> args,
List<JCExpression> typeargs,
+ boolean isAnonInner)
+ {
+ MethInfo mi = resolveArgs(env, args, typeargs);
+ if (mi.tatypes.contains(null) || mi.atypes.contains(null)) {
+ return mi;
+ }
+
+ mi.site = resolveType(env, clazz, Kinds.TYP);
+ if (mi.site == null) {
+ Debug.warn("Can't resolve class for ctor", "expr", clazz);
+ return mi;
+ }
+
+ // this is not strictly correct, but if we're resolving the
constructor for an anonymous
+ // class created using an interface type, return the constructor
for Object
+ Type site = isAnonInner && mi.site.tsym.isInterface() ?
_syms.objectType : mi.site;
+
+ // Debug.temp("Resolving ctor " + site + "<" + mi.tatypes + ">(" +
mi.atypes + ")");
+ Env<AttrContext> aenv = Detype.toAttrEnv(env);
+ // if we're instantiating an anonymous inner class, javac's
Resolve uses the selectSuper
+ // flag to denote that protected constructors are accessible in
this context
+ Backdoor.selectSuper.set(aenv.info, isAnonInner);
+ mi.msym = invoke(env, Backdoor.resolveConstructor, _resolve,
clazz.pos(),
+ aenv, site, mi.atypes, mi.tatypes);
+ mi.varArgs = Backdoor.varArgs.get(aenv.info);
+ if (mi.msym.kind >= Kinds.ERR) {
+ Debug.log("Unable to resolve ctor", "clazz", clazz, "args",
args, "targrs", typeargs);
+ }
+ // Debug.temp("Asked javac to resolve ctor " + clazz + " got " +
mi.msym);
+ return mi;
+ }
+
+ /**
+ * Resolves the supplied method invocation into a symbol using
information in the supplied
+ * context. Performs static resolution to choose between overloaded
candidates.
+ */
+ public MethInfo resolveMethod (Env<DetypeContext> env,
JCMethodInvocation mexpr)
+ {
+ MethInfo mi = resolveArgs(env, mexpr.args, mexpr.typeargs);
+ if (mi.tatypes.contains(null) || mi.atypes.contains(null)) {
+ return mi;
+ }
+ Name mname = TreeInfo.name(mexpr.meth);
+
+ switch (mexpr.meth.getTag()) {
+ case JCTree.IDENT: {
+ Symbol sym;
+ mi.site = env.enclClass.sym.type;
+
+ // pass the buck to javac's Resolve to do the heavy lifting
+ Env<AttrContext> aenv = Detype.toAttrEnv(env);
+ if (mname == _names._this || mname == _names._super) {
+ if (mname == _names._super) {
+ if (_types.isSameType(mi.site, _syms.objectType)) {
+ mi.site = _types.createErrorType(_syms.objectType);
+ } else {
+ mi.site = _types.supertype(mi.site);
+ }
+ // we need to twiddle the selectSuper bit in the env
we pass to Resolve
+ Backdoor.selectSuper.set(aenv.info, true);
+ }
+ // Debug.temp("Resolving " + mname + "<" + mi.tatypes
+ ">(" + mi.atypes + ")");
+ mi.msym = invoke(env, Backdoor.resolveConstructor,
_resolve, mexpr.pos(),
+ aenv, mi.site, mi.atypes, mi.tatypes);
+ mi.varArgs = Backdoor.varArgs.get(aenv.info);
+
+ } else {
+ // Debug.temp("Resolving " + mname + "<" + mi.tatypes
+ ">(" + mi.atypes + ")");
+ if (WARNINGS) {
+ mi.msym = invoke(env, Backdoor.resolveMethod,
_resolve, mexpr.pos(),
+ aenv, mname, mi.atypes, mi.tatypes);
+ mi.varArgs = Backdoor.varArgs.get(aenv.info);
+ } else {
+ mi.msym = ABSENT_MTH;
+ List<MethodResolutionPhase> steps = RESOLVE_STEPS;
+ while (!steps.isEmpty() &&
+ steps.head.isApplicable(true /*boxing*/, true
/*varargs*/) &&
+ mi.msym.kind >= Kinds.ERRONEOUS) {
+ mi.varArgs = steps.head.isVarargsRequired;
+ mi.msym = invoke(env, Backdoor.findFun, _resolve,
+ aenv, mname, mi.atypes,
mi.tatypes,
+ steps.head.isBoxingRequired,
steps.head.isVarargsRequired);
+ steps = steps.tail;
+ }
+ }
+ }
+ if (mi.msym.kind >= Kinds.ERR) {
+ Debug.log("Unable to resolve method", "expr",
mexpr, "site", mi.site,
+ "encl", env.enclClass.sym);
+ }
+ // Debug.temp("Asked javac to resolve method " + mexpr + "
got " + mi.msym);
+ return mi;
+ }
+
+ case JCTree.SELECT: {
+ // we erase the type parameters from the site because we want
javac to ignore the type
+ // arguments when resolving our method (to be maximally
lenient)
+ // Debug.temp("Resolving method receiver", "expr", mexpr);
+ JCExpression selexp = ((JCFieldAccess)mexpr.meth).selected;
+ mi.site = resolveType(env, selexp, Kinds.VAL | Kinds.TYP);
+ if (mi.site == null) {
+ Debug.warn("Can't resolve receiver type", "expr", mexpr);
+ return mi;
+ }
+ // Debug.temp("Resolved method receiver", "expr",
mexpr, "site", mi.site);
+
+ // the receiver may also be a wildcard (or a type variable),
in which case we need to
+ // convert it to its upper bound
+ switch (mi.site.tag) {
+ case TypeTags.WILDCARD:
+ mi.site = _types.upperBound(mi.site);
+ break;
+ case TypeTags.TYPEVAR:
+ mi.site = mi.site.getUpperBound();
+ break;
+ }
+ if (mi.site == null) {
+ Debug.warn("Site yielded no upper bound!", "expr", mexpr);
+ return mi;
+ }
+
+ // if our site is 'super' we need to twiddle a bit in the env
we pass to Resolve
+ Env<AttrContext> aenv = Detype.toAttrEnv(env);
+ if (selexp instanceof JCIdent && ((JCIdent)selexp).name ==
_names._super) {
+ Backdoor.selectSuper.set(aenv.info, true);
+ }
+
+ // Debug.temp("Resolving {"+mi.site+"}." + mname
+ "<"+mi.tatypes+">("+mi.atypes+")");
+ if (WARNINGS) {
+ mi.msym = invoke(env, Backdoor.resolveQualifiedMethod,
_resolve, mexpr.pos(),
+ aenv, mi.site, mname, mi.atypes,
mi.tatypes);
+ mi.varArgs = Backdoor.varArgs.get(aenv.info);
+ } else {
+ mi.msym = ABSENT_MTH;
+ List<MethodResolutionPhase> steps = RESOLVE_STEPS;
+ while (steps.nonEmpty() &&
+ steps.head.isApplicable(true /*boxingEnabled*/,
true /*varargsEnabled*/) &&
+ mi.msym.kind >= Kinds.ERRONEOUS) {
+ mi.varArgs = steps.head.isVarargsRequired;
+ mi.msym = invoke(env, Backdoor.findMethod, _resolve,
aenv, mi.site, mname,
+ mi.atypes, mi.tatypes,
steps.head.isBoxingRequired,
+ steps.head.isVarargsRequired, false);
+ steps = steps.tail;
+ }
+ }
+ if (mi.msym.kind >= Kinds.ERR) {
+ Debug.log("Unable to resolve method", "expr",
mexpr, "site", mi.site);
+ }
+ // Debug.temp("Asked javac to resolve method " + mexpr + "
got " + mi.msym);
+ return mi;
+ }
+
+ default:
+ throw new IllegalArgumentException("Method not ident or
select? " + mexpr);
+ }
+ }
+
+ /**
+ * Resolves the types of all expressions in the supplied list.
+ */
+ public List<Type> resolveRawTypes (Env<DetypeContext> env,
List<JCExpression> exprs, int pkind)
+ {
+ return exprs.isEmpty() ? List.<Type>nil() :
+ resolveRawTypes(env, exprs.tail,
pkind).prepend(resolveRawType(env, exprs.head, pkind));
+ }
+
+ /**
+ * Returns the erased type of the supplied expression.
+ */
+ public Type resolveRawType (Env<DetypeContext> env, JCTree expr, int
pkind)
+ {
+ Type type = resolveType(env, expr, pkind);
+ return (type == null) ? null : _types.erasure(type);
+ }
+
+ /**
+ * Resolves the types of all expressions in the supplied list.
+ */
+ public List<Type> resolveTypes (Env<DetypeContext> env,
List<JCExpression> exprs, int pkind)
+ {
+ return exprs.isEmpty() ? List.<Type>nil() :
+ resolveTypes(env, exprs.tail, pkind).prepend(resolveType(env,
exprs.head, pkind));
+ }
+
+ /**
+ * Instantiates the type of a method for its call site. This binds
type variables as
+ * appropriate (via Resolve.instantiate) and converts the method to a
member of its calling
+ * site (via Types.memberType).
+ */
+ public Type instantiateType (Env<DetypeContext> env, MethInfo mi)
+ {
+ // if the method is universally quantified, we need to bind its
type variables based on the
+ // types of its actual arguments
+ if (mi.msym.type.tag == TypeTags.FORALL) {
+ // Resolve.instantiate handles member type conversion for us
+ Type mtype = invoke(env, Backdoor.instantiate, _resolve,
Detype.toAttrEnv(env),
+ mi.site, mi.msym, mi.atypes, mi.tatypes,
true, mi.varArgs,
+ new Warner());
+ if (mtype == null) {
+ Debug.warn("Failed to instantiate forall type", "sym",
mi.msym);
+ }
+ return mtype;
+ } else {
+ // otherwise we just need to convert it to a member type
+ return _types.memberType(mi.site, mi.msym);
+ }
+ }
+
+ /**
+ * Returns the (possibly parameterized) type of the supplied
expression.
+ */
+ public Type resolveType (Env<DetypeContext> env, JCTree expr, int
pkind)
+ {
+ // if we already have a resolved type, just use that
+ if (expr.type != null) {
+ // Debug.temp("Using expression type", "expr", expr, "pkind",
pkind, "type", expr.type);
+ return expr.type;
+ }
+
+ // Debug.temp("Resolving type", "expr", expr, "pkind", pkind);
+ switch (expr.getTag()) {
+ case JCTree.IDENT: {
+ Symbol sym = resolveSymbol(env, expr, pkind);
+ if (sym.kind >= Kinds.ERR) {
+ Debug.warn("Unable to resolve type", "expr",
expr, "pkind", pkind);
+ return null;
+ }
+
+ Env<DetypeContext> env1 = env;
+ if (sym.kind < Kinds.ERR && sym.owner != null && sym.owner !=
env1.enclClass.sym) {
+// TODO: we'll need this eventually
+// // If the found symbol is inaccessible, then it is
accessed through an enclosing
+// // instance. Locate this enclosing instance:
+// while (env1.outer != null && !rs.isAccessible(env,
env1.enclClass.sym.type, sym))
+// env1 = env1.outer;
+ }
+
+ // Attr.checkId does some small massaging of types that we
need to emulate here
+ return typeFromSym(expr, env1.enclClass.sym.type, sym);
+ }
+
+ case JCTree.SELECT: {
+ JCFieldAccess facc = (JCFieldAccess)expr;
+
+ // we'd just use resolveSymbol(), but annoyingly we need the
array 'length' handling
+ // interjected between site type resolution and symbol
resolution; sigh...
+ Type site = resolveSelectSite(env, facc, pkind);
+ if (site == null) {
+ Debug.warn("Unable to resolve receiver of field select: "
+ expr);
+ return null;
+ }
+
+ // if the site is an array and the field is 'length', it's
just an int (for some reason
+ // Attr.selectSym() doesn't handle .length)
+ if (site.tag == TypeTags.ARRAY && facc.name == _names.length) {
+ return _syms.typeOfTag[TypeTags.INT];
+ }
+
+ Symbol sym = invoke(env, Backdoor.selectSym, _attr, facc,
site, Detype.toAttrEnv(env),
+ Type.noType, pkind);
+ return typeFromSym(facc, site, sym);
+ }
+
+ case JCTree.APPLY: {
+ final Env<DetypeContext> fenv = env;
+ JCMethodInvocation app = (JCMethodInvocation)expr;
+ MethInfo mi = resolveMethod(env, app);
+ if (mi.msym.kind >= Kinds.ERR) {
+ return null;
+ }
+
+ // we need to instantiate the type of this method which binds
type variables based on
+ // actual type arguments and/or converts it to a member type
+ Type mtype = instantiateType(env, mi);
+ if (mtype == null) {
+ return null;
+ }
+
+ // if have a universally quantified return type, we need to
instantiate the remaining
+ // type variables to their upper bounds; this is normally
handled in a twisty maze of
+ // calls originating from Attr.checkReturn()
+ Type rtype = mtype.getReturnType();
+ if (rtype.tag == TypeTags.FORALL) {
+ // if the quantified return type is a primitive, we can't
try to find its maximal
+ // instantiation as a subtype of Object; we don't need to
instantiate anything
+ if (((Type.ForAll)rtype).qtype.isPrimitive()) {
+ rtype = ((Type.ForAll)rtype).qtype;
+ } else {
+ // TODO: if we have an expected type (i.e. we're in an
initializer expression),
+ // at some point we're going to need that here instead
of Object; oh boy!
+ rtype = _infer.instantiateExpr(
+ (Type.ForAll)rtype, _syms.objectType, new
Warner());
+ }
+ }
+
+ // (from Attr) as a special case, array.clone() has a result
that is the same as
+ // static type of the array being cloned
+ Name methName = TreeInfo.name(app.meth);
+ if (app.meth.getTag() == JCTree.SELECT && methName ==
_names.clone &&
+ /* allowCovariantReturns && */ _types.isArray(mi.site)) {
+ rtype = mi.site;
+ }
+
+ // (from Attr) as a special case, x.getClass() has type
Class<? extends |X|>
+ if (methName == _names.getClass && app.args.isEmpty()) {
+ Type qualifier = (app.meth.getTag() == JCTree.SELECT) ?
mi.site :
+ env.enclClass.sym.type;
+ rtype = new Type.ClassType(
+ rtype.getEnclosingType(),
+ List.<Type>of(new
Type.WildcardType(_types.erasure(qualifier),
+ BoundKind.EXTENDS,
_syms.boundClass)),
+ rtype.tsym);
+ }
+
+ return rtype;
+ }
+
+ case JCTree.NEWCLASS:
+ // TODO: this isn't quite right since it doesn't return the
correct symbol for
+ // anonymous inner classes...
+ return resolveType(env, ((JCNewClass)expr).clazz, Kinds.TYP);
+
+ case JCTree.TYPECAST:
+ return resolveType(env, ((JCTypeCast)expr).clazz, Kinds.TYP);
+
+ case JCTree.PARENS:
+ return resolveType(env, ((JCParens)expr).expr, pkind);
+
+ case JCTree.INDEXED: {
+ Type atype = resolveType(env, ((JCArrayAccess)expr).indexed,
pkind);
+ if (atype instanceof Type.ArrayType) {
+ return ((Type.ArrayType)atype).elemtype;
+ } else {
+ Debug.warn("Can't resolveType() of array index
expr", "expr", expr, "atype", atype);
+ return null;
+ }
+ }
+
+ case JCTree.CONDEXPR: {
+ // if one side is null, use type of other side (in general
should we unify?)
+ Type type = resolveType(env, ((JCConditional)expr).truepart,
pkind);
+ return (type.tag != TypeTags.BOT) ? type :
+ resolveType(env, ((JCConditional)expr).falsepart, pkind);
+ }
+
+ case JCTree.TYPETEST: // instanceof
+ case JCTree.OR: // ||
+ case JCTree.AND: // &&
+ case JCTree.EQ: // ==
+ case JCTree.NE: // !=
+ case JCTree.LT: // <
+ case JCTree.GT: // >
+ case JCTree.LE: // <=
+ case JCTree.GE: // >=
+ case JCTree.NOT: // !
+ return _syms.typeOfTag[TypeTags.BOOLEAN];
+
+ case JCTree.SL: // <<
+ case JCTree.SR: // >>
+ case JCTree.USR: // >>>
+ case JCTree.BITOR: // |
+ case JCTree.BITXOR: // ^
+ case JCTree.BITAND: // &
+ case JCTree.MINUS: // -
+ case JCTree.MUL: // *
+ case JCTree.DIV: // /
+ case JCTree.MOD: // %
+ return numericPromote(env, ((JCBinary)expr).lhs,
((JCBinary)expr).rhs);
+
+ case JCTree.POS: // +
+ case JCTree.NEG: // -
+ case JCTree.COMPL: // ~
+ return numericPromote(env, ((JCUnary)expr).arg);
+
+ case JCTree.PREINC: // ++ _
+ case JCTree.PREDEC: // -- _
+ case JCTree.POSTINC: // _ ++
+ case JCTree.POSTDEC: // _ --
+ return resolveType(env, ((JCUnary)expr).arg, Kinds.VAR);
+
+ case JCTree.PLUS: { // +
+ // if lhs or rhs is string, then expr is string
+ Type lhs = resolveType(env, ((JCBinary)expr).lhs, pkind);
+ Type rhs = resolveType(env, ((JCBinary)expr).rhs, pkind);
+ if (_types.isSameType(lhs, _syms.stringType) ||
+ _types.isSameType(rhs, _syms.stringType)) {
+ return _syms.stringType;
+ } else {
+ return numericPromote(lhs, rhs);
+ }
+ }
+
+ case JCTree.PLUS_ASG: { // +=
+ // if lhs is string, then expr is string
+ Type lhs = resolveType(env, ((JCAssignOp)expr).lhs, pkind);
+ if (_types.isSameType(lhs, _syms.stringType)) {
+ return _syms.stringType;
+ } else {
+ return lhs;
+ }
+ }
+
+ case JCTree.BITOR_ASG: // |=
+ case JCTree.BITXOR_ASG: // ^=
+ case JCTree.BITAND_ASG: // &=
+ return _syms.typeOfTag[TypeTags.INT]; // TODO: is this true?
+
+ case JCTree.SL_ASG: // <<=
+ case JCTree.SR_ASG: // >>=
+ case JCTree.USR_ASG: // >>>=
+ case JCTree.MINUS_ASG: // -=
+ case JCTree.MUL_ASG: // *=
+ case JCTree.DIV_ASG: // /=
+ case JCTree.MOD_ASG: // %=
+ return _syms.typeOfTag[TypeTags.INT]; // TODO: is this true?
+
+ case JCTree.LITERAL: {
+ int tag = ((JCLiteral)expr).typetag;
+ // TODO: are there other literals that don't have direct type
tag mapping?
+ return (tag == TypeTags.CLASS) ? _syms.stringType :
_syms.typeOfTag[tag];
+ }
+
+ case JCTree.TYPEIDENT:
+ return _syms.typeOfTag[((JCPrimitiveTypeTree)expr).typetag];
+
+ case JCTree.TYPEARRAY: {
+ Type etype = resolveType(env,
((JCArrayTypeTree)expr).elemtype, Kinds.TYP);
+ return (etype == null) ? null : new Type.ArrayType(etype,
_syms.arrayClass);
+ }
+
+ case JCTree.TYPEAPPLY: {
+ JCTypeApply tapp = (JCTypeApply)expr;
+ Type clazz = resolveType(env, tapp.clazz, Kinds.TYP);
+ List<Type> actuals = resolveTypes(env, tapp.arguments,
Kinds.TYP);
+ Type clazzOuter = clazz.getEnclosingType();
+ return new Type.ClassType(clazzOuter, actuals, clazz.tsym);
+ }
+
+ case JCTree.WILDCARD: {
+ JCWildcard wc = (JCWildcard)expr;
+ Type type = (wc.kind.kind == BoundKind.UNBOUND) ?
_syms.objectType :
+ resolveType(env, wc.inner, Kinds.TYP);
+ return new Type.WildcardType(type, wc.kind.kind,
_syms.boundClass);
+ }
+
+ case JCTree.NEWARRAY:
+ return new Type.ArrayType(
+ resolveType(env, ((JCNewArray)expr).elemtype, Kinds.TYP),
_syms.arrayClass);
+
+ case JCTree.ASSIGN:
+ return resolveType(env, ((JCAssign)expr).lhs, Kinds.VAR);
+
+ default:
+ Debug.warn("Can't resolveType() of expr", "tag",
expr.getTag(), "expr", expr,
+ "etype", expr.getClass().getSimpleName());
+ return null;
+ }
+ }
+
+ /**
+ * Returns true if the supplied expression resolves to a class.
+ */
+ public boolean isStaticSite (Env<DetypeContext> env, JCExpression expr)
+ {
+ // Debug.log("isStaticReceiver(" + fa + ")");
+
+ switch (expr.getTag()) {
+ case JCTree.IDENT: {
+ Name name = TreeInfo.name(expr);
+ if (name == _names._this || name == _names._super) {
+ return false;
+ } else {
+ Symbol sym = invoke(env, Backdoor.findIdent, _resolve,
Detype.toAttrEnv(env),
+ name, Kinds.PCK | Kinds.TYP |
Kinds.VAL);
+ return (sym != null) && ((sym.kind == Kinds.TYP) ||
(sym.kind == Kinds.PCK));
+ }
+ }
+
+ case JCTree.SELECT: {
+ JCFieldAccess facc = (JCFieldAccess)expr;
+ if (facc.name == _names._this || facc.name == _names._super ||
+ facc.name == _names._class) {
+ return false;
+ }
+ int skind = Kinds.PCK | Kinds.TYP | Kinds.VAL;
+ Type site = resolveType(env, facc.selected, skind);
+ if (site == null) {
+ Debug.warn("Unable to resolve receiver of field select: "
+ expr);
+ return false;
+ }
+ Symbol sym = invoke(env, Backdoor.selectSym, _attr, facc,
site, Detype.toAttrEnv(env),
+ Type.noType, skind);
+ return (sym != null) && ((sym.kind == Kinds.TYP) || (sym.kind
== Kinds.PCK));
+ }
+
+ default:
+ return false;
+ }
+ }
+
+ public Symbol inferStaticReceiver (Env<DetypeContext> env,
JCExpression expr)
+ {
+ switch (expr.getTag()) {
+ case JCTree.IDENT:
+ case JCTree.SELECT:
+ Symbol rsym = resolveSymbol(env, expr, Kinds.VAL|Kinds.TYP);
+ return (rsym.getKind() == ElementKind.CLASS) ? rsym : null;
+ case JCTree.APPLY:
+ case JCTree.INDEXED:
+ return null; // these are necessarily non-static receivers
+ default:
+ Debug.warn("Unable to infer static receivership", "expr", expr,
+ "etype", expr.getClass().getName());
+ return null;
+ }
+ }
+
+ protected Resolver (Context ctx)
+ {
+ ctx.put(RESOLVER_KEY, this);
+ _reader = ClassReader.instance(ctx);
+ _types = Types.instance(ctx);
+ _syms = Symtab.instance(ctx);
+ _names = Names.instance(ctx);
+ _resolve = Resolve.instance(ctx);
+ _attr = Attr.instance(ctx);
+ _infer = Infer.instance(ctx);
+ _log = Log.instance(ctx);
+ }
+
+ protected <R, V> V invoke (Env<DetypeContext> env,
Backdoor.MethodRef<R, V> method,
+ R receiver, Object... args)
+ {
+ JavaFileObject ofile =
_log.useSource(env.toplevel.getSourceFile());
+ try {
+ return method.invoke(receiver, args);
+ } finally {
+ _log.useSource(ofile);
+ }
+ }
+
+ protected List<Type> upperBounds (List<Type> types)
+ {
+ if (types.isEmpty()) {
+ return List.nil();
+ }
+ Type ubound = (types.head == null) ? null :
_types.upperBound(types.head);
+ return upperBounds(types.tail).prepend(ubound);
+ }
+
+ protected Type resolveSelectSite (Env<DetypeContext> env,
JCFieldAccess facc, int pkind)
+ {
+ // determine the expected kind of the qualifier expression
+ int skind = 0;
+ if (facc.name == _names._this || facc.name == _names._super ||
+ facc.name == _names._class) {
+ skind = Kinds.TYP;
+ } else {
+ if ((pkind & Kinds.PCK) != 0) skind = skind | Kinds.PCK;
+ if ((pkind & Kinds.TYP) != 0) skind = skind | Kinds.TYP |
Kinds.PCK;
+ if ((pkind & (Kinds.VAL | Kinds.MTH)) != 0) skind = skind |
Kinds.VAL | Kinds.TYP;
+ }
+ return resolveType(env, facc.selected, skind);
+ }
+
+ /**
+ * Helper for {@link #resolveConstructor} and {@link #resolveMethod}.
+ */
+ protected MethInfo resolveArgs (Env<DetypeContext> env,
List<JCExpression> args,
+ List<JCExpression> typeargs)
+ {
+ MethInfo mi = new MethInfo();
+ mi.msym = _syms.errSymbol; // assume failure! we're so optimistic
+
+ // resolve our argument and type argument types
+ mi.atypes = resolveTypes(env, args, Kinds.VAL);
+ mi.tatypes = resolveTypes(env, typeargs, Kinds.TYP);
+
+ // convert any wildcard types to their upper bounds; I'm not sure
why this is strictly
+ // necessary, but Resolve's methods throw assertion failures if I
don't...
+ mi.atypes = upperBounds(mi.atypes);
+
+ return mi;
+ }
+
+ /**
+ * Helper for {@link #resolveType} that mimics some sneaky type
adjustment in
+ * <code>Attr.checkId()</code>.
+ */
+ protected Type typeFromSym (JCTree tree, Type site, Symbol sym)
+ {
+ // For types, the computed type equals the symbol's type, except
for two situations:
+ Type rtype;
+ switch (sym.kind) {
+ case Kinds.TYP:
+ rtype = sym.type;
+ if (rtype.tag == TypeTags.CLASS) {
+ Type ownOuter = rtype.getEnclosingType();
+
+ // (a) If the symbol's type is parameterized, erase it
because no type parameters
+ // were given. We recover generic outer type later in
visitTypeApply.
+ if (rtype.tsym.type.getTypeArguments().nonEmpty()) {
+ rtype = _types.erasure(rtype);
+ }
+ // (b) If the symbol's type is an inner class, then we
have to interpret its
+ // outer type as a superclass of the site type. Example:
+ //
+ // class Tree<A> { class Visitor { ... } }
+ // class PointTree extends Tree<Point> { ... }
+ // ...PointTree.Visitor...
+ //
+ // Then the type of the last expression above is
Tree<Point>.Visitor.
+ else if (ownOuter.tag == TypeTags.CLASS && site !=
ownOuter) {
+ Type normOuter = site;
+ if (normOuter.tag == TypeTags.CLASS) {
+ normOuter = _types.asEnclosingSuper(site,
ownOuter.tsym);
+ }
+ if (normOuter == null) { // perhaps from an import
+ normOuter = _types.erasure(ownOuter);
+ }
+ if (normOuter != ownOuter) {
+ rtype = new Type.ClassType(normOuter,
List.<Type>nil(), rtype.tsym);
+ }
+ }
+ }
+ break;
+
+ case Kinds.VAR: {
+ VarSymbol v = (VarSymbol)sym;
+ // The computed type of a variable is the type of the variable
symbol, taken as a
+ // member of the site type.
+ rtype = (sym.owner.kind == Kinds.TYP &&
+ sym.name != _names._this && sym.name !=
_names._super) ?
+ _types.memberType(site, sym) : sym.type;
+
+// TODO
+// if (env.info.tvars.nonEmpty()) {
+// Type owntype1 = new ForAll(env.info.tvars, owntype);
+// for (List<Type> l = env.info.tvars; l.nonEmpty(); l =
l.tail)
+// if (!owntype.contains(l.head)) {
+// log.error(tree.pos(), "undetermined.type",
owntype1);
+// owntype1 = types.createErrorType(owntype1);
+// }
+// owntype = owntype1;
+// }
+
+// TODO
+// // If the variable is a constant, record constant value in
computed type.
+// if (v.getConstValue() != null && isStaticReference(tree))
+// owntype = owntype.constType(v.getConstValue());
+
+// if (pkind == VAL) {
+// owntype = capture(owntype); // capture "names as
expressions"
+// }
+ break;
+ }
+
+ case Kinds.MTH:
+// for now fall through
+// case MTH: {
+// JCMethodInvocation app = (JCMethodInvocation)env.tree;
+// owntype = checkMethod(site, sym, env, app.args,
+// pt.getParameterTypes(),
pt.getTypeArguments(),
+// env.info.varArgs);
+// break;
+// }
+
+ case Kinds.PCK:
+ case Kinds.ERR:
+ rtype = sym.type;
+ break;
+
+ default:
+ throw new AssertionError("Unexpected kind: " + sym.kind + " in
tree " + tree);
+ }
+
+ return rtype;
+ }
+
+ protected Type numericPromote (Env<DetypeContext> env, JCTree arg)
+ {
+ return numericPromote(resolveType(env, arg, Kinds.VAL));
+ }
+
+ protected Type numericPromote (Type arg)
+ {
+ if (arg.tag == TypeTags.CLASS) {
+ arg = _types.unboxedType(arg);
+ }
+ switch (arg.tag) {
+ case TypeTags.BOOLEAN: return _syms.booleanType;
+ case TypeTags.BYTE:
+ case TypeTags.SHORT:
+ case TypeTags.CHAR:
+ case TypeTags.INT: return _syms.intType;
+ case TypeTags.LONG: return _syms.longType;
+ case TypeTags.FLOAT: return _syms.floatType;
+ case TypeTags.DOUBLE: return _syms.doubleType;
+ default:
+ throw new IllegalArgumentException("Cannot promote non-numeric
type " + arg);
+ }
+ }
+
+ protected Type numericPromote (Env<DetypeContext> env, JCTree lhs,
JCTree rhs)
+ {
+ return numericPromote(resolveType(env, lhs, Kinds.VAL),
resolveType(env, rhs, Kinds.VAL));
+ }
+
+ protected Type numericPromote (Type lhs, Type rhs)
+ {
+ if (lhs.tag == TypeTags.CLASS) {
+ lhs = _types.unboxedType(lhs);
+ }
+ if (rhs.tag == TypeTags.CLASS) {
+ rhs = _types.unboxedType(rhs);
+ }
+ switch (Math.max(lhs.tag, rhs.tag)) {
+ case TypeTags.BOOLEAN: return _syms.booleanType;
+ case TypeTags.BYTE:
+ case TypeTags.SHORT:
+ case TypeTags.CHAR:
+ case TypeTags.INT: return _syms.intType;
+ case TypeTags.LONG: return _syms.longType;
+ case TypeTags.FLOAT: return _syms.floatType;
+ case TypeTags.DOUBLE: return _syms.doubleType;
+ default:
+ throw new IllegalArgumentException(
+ "Cannot promote non-numeric type [lhs=" + lhs + ", rhs=" +
rhs + "]");
+ }
+ }
+
+ protected static enum MethodResolutionPhase {
+ BASIC(false, false),
+ BOX(true, false),
+ VARARITY(true, true);
+
+ public final boolean isBoxingRequired;
+ public final boolean isVarargsRequired;
+
+ public boolean isApplicable (boolean boxingEnabled, boolean
varargsEnabled) {
+ return (varargsEnabled || !isVarargsRequired) &&
+ (boxingEnabled || !isBoxingRequired);
+ }
+
+ MethodResolutionPhase (boolean isBoxingRequired, boolean
isVarargsRequired) {
+ this.isBoxingRequired = isBoxingRequired;
+ this.isVarargsRequired = isVarargsRequired;
+ }
+ }
+
+ protected ClassReader _reader;
+ protected Types _types;
+ protected Symtab _syms;
+ protected Names _names;
+ protected Resolve _resolve;
+ protected Attr _attr;
+ protected Infer _infer;
+ protected Log _log;
+
+ protected static final Context.Key<Resolver> RESOLVER_KEY = new
Context.Key<Resolver>();
+
+ protected static final List<MethodResolutionPhase> RESOLVE_STEPS =
List.of(
+ MethodResolutionPhase.BASIC, MethodResolutionPhase.BOX,
MethodResolutionPhase.VARARITY);
+
+ protected static final Symbol ABSENT_MTH = new
Symbol(Kinds.ABSENT_MTH, 0, null, null, null) {
+ @Override public <R, P> R accept(ElementVisitor<R, P> v, P p) {
+ throw new AssertionError();
+ }
+ };
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/AmbiguousMethodError.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,16 @@
+//
+// $Id$
+
+package org.ductilej.runtime;
+
+/**
+ * Thrown when two or more methods match the arguments provided to a
runtime method call that was
+ * not resolvable at compile time.
+ */
+public class AmbiguousMethodError extends RuntimeException
+{
+ public AmbiguousMethodError (String error)
+ {
+ super(error);
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/BinOps.java Sat Nov 27 12:15:19 2010
@@ -0,0 +1,32 @@
+//
+// $Id$
+
+package org.ductilej.runtime;
+
+/**
+ * Encapsulates binary operations on primitive types. Specialized
instances of this class are
+ * automatically generated for the cartesian product of all compatible
primitive types for
+ * reasonably fast dispatch of ad-hoc polymorphic binary operators.
+ */
+public interface BinOps
+{
+ public Object plus (Object lhs, Object rhs);
+ public Object minus (Object lhs, Object rhs);
+ public Object multiply (Object lhs, Object rhs);
+ public Object divide (Object lhs, Object rhs);
+ public Object remainder (Object lhs, Object rhs);
+
+ public Object bitOr (Object lhs, Object rhs);
+ public Object bitAnd (Object lhs, Object rhs);
+ public Object bitXor (Object lhs, Object rhs);
+
+ public Object leftShift (Object lhs, Object rhs);
+ public Object rightShift (Object lhs, Object rhs);
+ public Object unsignedRightShift (Object lhs, Object rhs);
+
+ public boolean equalTo (Object lhs, Object rhs);
+ public boolean lessThan (Object lhs, Object rhs);
+ public boolean lessThanEq (Object lhs, Object rhs);
+ public boolean greaterThan (Object lhs, Object rhs);
+ public boolean greaterThanEq (Object lhs, Object rhs);
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/Binop.java Sat Nov 27 12:15:19 2010
@@ -0,0 +1,245 @@
+//
+// $Id$
+
+package org.ductilej.runtime;
+
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.ductilej.runtime.ops.*;
+
+/**
+ * Used to dispatch binary operations at runtime.
+ */
+public enum Binop {
+ EQUAL_TO {
+ public Object invoke (Object lhs, Object rhs) {
+ return isEqualTo(lhs, rhs);
+ }
+ },
+ NOT_EQUAL_TO {
+ public Object invoke (Object lhs, Object rhs) {
+ return !isEqualTo(lhs, rhs);
+ }
+ },
+
+ PLUS {
+ public Object invoke (Object lhs, Object rhs) {
+ if (lhs instanceof String || rhs instanceof String) {
+ return String.valueOf(lhs) + String.valueOf(rhs);
+ } else {
+ return get(lhs, rhs).plus(lhs, rhs);
+ }
+ }
+ },
+ MINUS {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).minus(lhs, rhs);
+ }
+ },
+ MULTIPLY {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).multiply(lhs, rhs);
+ }
+ },
+ DIVIDE {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).divide(lhs, rhs);
+ }
+ },
+ REMAINDER {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).remainder(lhs, rhs);
+ }
+ },
+
+ LESS_THAN {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).lessThan(lhs, rhs);
+ }
+ },
+ GREATER_THAN {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).greaterThan(lhs, rhs);
+ }
+ },
+ LESS_THAN_EQUAL {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).lessThanEq(lhs, rhs);
+ }
+ },
+ GREATER_THAN_EQUAL {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).greaterThanEq(lhs, rhs);
+ }
+ },
+
+ OR {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).bitOr(lhs, rhs);
+ }
+ },
+ AND {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).bitAnd(lhs, rhs);
+ }
+ },
+ XOR {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).bitXor(lhs, rhs);
+ }
+ },
+
+ LEFT_SHIFT {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).leftShift(lhs, rhs);
+ }
+ },
+ RIGHT_SHIFT {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).rightShift(lhs, rhs);
+ }
+ },
+ UNSIGNED_RIGHT_SHIFT {
+ public Object invoke (Object lhs, Object rhs) {
+ return get(lhs, rhs).unsignedRightShift(lhs, rhs);
+ }
+ },
+
+ CONDITIONAL_AND {
+ public Object invoke (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("&& should not be lifted");
+ }
+ },
+ CONDITIONAL_OR {
+ public Object invoke (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("|| should not be lifted");
+ }
+ };
+
+ // conditional and and or are not detyped
+ // CONDITIONAL_AND
+ // CONDITIONAL_OR
+
+ // the assignment operators are transformed into non-assignment
versions by the detyper
+ // MULTIPLY_ASSIGNMENT
+ // DIVIDE_ASSIGNMENT
+ // REMAINDER_ASSIGNMENT
+ // PLUS_ASSIGNMENT
+ // MINUS_ASSIGNMENT
+ // LEFT_SHIFT_ASSIGNMENT
+ // RIGHT_SHIFT_ASSIGNMENT
+ // UNSIGNED_RIGHT_SHIFT_ASSIGNMENT
+ // AND_ASSIGNMENT
+ // XOR_ASSIGNMENT
+ // OR_ASSIGNMENT
+
+ /**
+ * Executes this operation.
+ */
+ public abstract Object invoke (Object lhs, Object rhs);
+
+ /**
+ * Returns the {@link BinOps} instance appropriate for the supplied
left- and right-hand-sides
+ * of a binary expression.
+ */
+ protected BinOps get (Object lhs, Object rhs)
+ {
+ try {
+ return BINOPS.get(lhs.getClass()).get(rhs.getClass());
+ } catch (NullPointerException npe) {
+ throw new NullPointerException(
+ "Binary op (" + this + ") on null arg (lhs=" + lhs + ",
rhs=" + rhs + ")");
+ }
+ }
+
+ /**
+ * Compares the two instances for equality. If the instances represent
primitive types,
+ * implicit coercions may be performed on them as appropriate. If
either instance is not a
+ * coercible primitive type (non-boolean), reference equality is
returned.
+ */
+ protected static boolean isEqualTo (Object lhs, Object rhs)
+ {
+ if (lhs != null && rhs != null) {
+ Map<Class<?>, BinOps> omap = BINOPS.get(lhs.getClass());
+ if (omap != null) {
+ BinOps ops = omap.get(rhs.getClass());
+ if (ops != null) {
+ return ops.equalTo(lhs, rhs);
+ }
+ }
+ }
+ return (lhs == rhs);
+ }
+
+ protected static final Map<Class<?>, Map<Class<?>, BinOps>> BINOPS =
+ ImmutableMap.<Class<?>, Map<Class<?>, BinOps>>builder().
+ put(Boolean.class, ImmutableMap.<Class<?>, BinOps>builder().
+ put(Boolean.class, new BooleanBooleanOps()).
+ build()).
+ put(Byte.class, ImmutableMap.<Class<?>, BinOps>builder().
+ put(Byte.class, new ByteByteOps()).
+ put(Short.class, new ByteShortOps()).
+ put(Character.class, new ByteCharacterOps()).
+ put(Integer.class, new ByteIntegerOps()).
+ put(Long.class, new ByteLongOps()).
+ put(Float.class, new ByteFloatOps()).
+ put(Double.class, new ByteDoubleOps()).
+ build()).
+ put(Short.class, ImmutableMap.<Class<?>, BinOps>builder().
+ put(Byte.class, new ShortByteOps()).
+ put(Short.class, new ShortShortOps()).
+ put(Character.class, new ShortCharacterOps()).
+ put(Integer.class, new ShortIntegerOps()).
+ put(Long.class, new ShortLongOps()).
+ put(Float.class, new ShortFloatOps()).
+ put(Double.class, new ShortDoubleOps()).
+ build()).
+ put(Character.class, ImmutableMap.<Class<?>, BinOps>builder().
+ put(Byte.class, new CharacterByteOps()).
+ put(Short.class, new CharacterShortOps()).
+ put(Character.class, new CharacterCharacterOps()).
+ put(Integer.class, new CharacterIntegerOps()).
+ put(Long.class, new CharacterLongOps()).
+ put(Float.class, new CharacterFloatOps()).
+ put(Double.class, new CharacterDoubleOps()).
+ build()).
+ put(Integer.class, ImmutableMap.<Class<?>, BinOps>builder().
+ put(Byte.class, new IntegerByteOps()).
+ put(Short.class, new IntegerShortOps()).
+ put(Character.class, new IntegerCharacterOps()).
+ put(Integer.class, new IntegerIntegerOps()).
+ put(Long.class, new IntegerLongOps()).
+ put(Float.class, new IntegerFloatOps()).
+ put(Double.class, new IntegerDoubleOps()).
+ build()).
+ put(Long.class, ImmutableMap.<Class<?>, BinOps>builder().
+ put(Byte.class, new LongByteOps()).
+ put(Short.class, new LongShortOps()).
+ put(Character.class, new LongCharacterOps()).
+ put(Integer.class, new LongIntegerOps()).
+ put(Long.class, new LongLongOps()).
+ put(Float.class, new LongFloatOps()).
+ put(Double.class, new LongDoubleOps()).
+ build()).
+ put(Float.class, ImmutableMap.<Class<?>, BinOps>builder().
+ put(Byte.class, new FloatByteOps()).
+ put(Short.class, new FloatShortOps()).
+ put(Character.class, new FloatCharacterOps()).
+ put(Integer.class, new FloatIntegerOps()).
+ put(Long.class, new FloatLongOps()).
+ put(Float.class, new FloatFloatOps()).
+ put(Double.class, new FloatDoubleOps()).
+ build()).
+ put(Double.class, ImmutableMap.<Class<?>, BinOps>builder().
+ put(Byte.class, new DoubleByteOps()).
+ put(Short.class, new DoubleShortOps()).
+ put(Character.class, new DoubleCharacterOps()).
+ put(Integer.class, new DoubleIntegerOps()).
+ put(Long.class, new DoubleLongOps()).
+ put(Float.class, new DoubleFloatOps()).
+ put(Double.class, new DoubleDoubleOps()).
+ build()).
+ build();
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/Debug.java Sat Nov 27 12:15:19 2010
@@ -0,0 +1,128 @@
+//
+// $Id$
+
+package org.ductilej.runtime;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+import org.ductilej.util.LogBuilder;
+
+/**
+ * Contains debugging related routines.
+ */
+public class Debug
+{
+ /** Whether or not debug logging is enabled. */
+ public static boolean DEBUG = Boolean.getBoolean("org.ductilej.debug");
+
+ /**
+ * Emits a debug message to stderr.
+ *
+ * @param args key/value pairs, (e.g. "age", someAge, "size",
someSize) which will be appended
+ * to the log message as [age=someAge, size=someSize].
+ */
+ public static void log (String message, Object... args)
+ {
+ if (DEBUG) {
+ System.err.println(format(message, args));
+ }
+ }
+
+ /**
+ * Emits a temporary debugging message to stderr.
+ *
+ * @param args key/value pairs, (e.g. "age", someAge, "size",
someSize) which will be appended
+ * to the log message as [age=someAge, size=someSize].
+ */
+ public static void temp (String message, Object... args)
+ {
+ System.err.println("*** " + format(message, args));
+ }
+
+ /**
+ * Emits a warning message to stderr.
+ *
+ * @param args key/value pairs, (e.g. "age", someAge, "size",
someSize) which will be appended
+ * to the log message as [age=someAge, size=someSize].
+ */
+ public static void warn (String message, Object... args)
+ {
+ System.err.println("!!! " + format(message, args));
+ }
+
+ /**
+ * Formats a debug message.
+ *
+ * @param args key/value pairs, (e.g. "age", someAge, "size",
someSize) which will be appended
+ * to the log message as [age=someAge, size=someSize].
+ */
+ public static String format (String message, Object... args)
+ {
+ return new LogBuilder(message, args).toString();
+ }
+
+ /**
+ * Generates a string representation of the supplied object of the
form <code>[field=value,
+ * field=value, ...]</code> using reflection. Handy for debugging.
+ */
+ public static String fieldsToString (Object object)
+ {
+ if (object == null) {
+ return "[null]";
+ }
+
+ StringBuilder buf = new StringBuilder("[");
+ int written = 0;
+ Class<?> clazz = object.getClass();
+ while (clazz != null) {
+ for (Field field : clazz.getDeclaredFields()) {
+ int mods = field.getModifiers();
+ if ((mods & Modifier.STATIC) != 0) {
+ continue; // we only want non-static fields
+ }
+ if (written > 0) {
+ buf.append(", ");
+ }
+ buf.append(field.getName()).append("=");
+ try {
+ field.setAccessible(true);
+ buf.append(field.get(object));
+ } catch (Exception e) {
+ buf.append("<error: " + e + ">");
+ }
+ written++;
+ }
+ clazz = clazz.getSuperclass();
+ }
+ return buf.append("]").toString();
+ }
+
+ /**
+ * Forcibly extracts the named field from the supplied object. For
circumventing protected and
+ * private access control when debugging.
+ */
+ public static Object get (Object obj, String field)
+ {
+ Field f = getField(obj.getClass(), field);
+ try {
+ f.setAccessible(true);
+ return f.get(obj);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to get " + field + " of " +
obj, e);
+ }
+ }
+
+ public static Field getField (Class<?> clazz, String fname)
+ {
+ if (clazz == null) {
+ return null;
+ }
+ for (Field field : clazz.getDeclaredFields()) {
+ if (field.getName().equals(fname)) {
+ return field;
+ }
+ }
+ return getField(clazz.getSuperclass(), fname);
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/RT.java Sat Nov 27 12:15:19 2010
@@ -0,0 +1,1412 @@
+//
+// $Id$
+
+package org.ductilej.runtime;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableBiMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.primitives.*;
+
+/**
+ * Provides dynamic method dispatch, operator evaluation and other bits.
+ */
+public class RT
+{
+ /** A suffix appended to signature mangled method names. */
+ public static final String MM_SUFFIX = "$M";
+
+ /** Whether or not to use full coercions in place of implicit
widenings. */
+ public static boolean COERCEALL =
Boolean.getBoolean("org.ductilej.coerceall");
+
+ /**
+ * Invokes the constructor of the supplied class, with the specified
arguments and returns the
+ * newly created instance.
+ *
+ * @param clazz the class to be instantiated.
+ * @param encl the enclosing instance to use in the case of a
non-static inner class.
+ * @param args the arguments to be supplied to the constructor, if any.
+ */
+ public static <T> T newInstance (Class<T> clazz, Class<?>[] atypes,
Object encl, Object[] args)
+ {
+ boolean needsOuterThis = isInnerInNonStaticContext(clazz);
+ boolean isMangled = (clazz.getAnnotation(Transformed.class) !=
null);
+
+ // if we were able to resolve the method at compile time, the
exact argument types will be
+ // provided in atypes which we can use to precise and fast(er)
method lookup
+ Constructor<?> ctor;
+ if (atypes != null) {
+ ctor = findConstructor(clazz, needsOuterThis, isMangled,
atypes);
+ } else {
+ ctor = findConstructor(clazz, needsOuterThis, isMangled, args);
+ }
+
+ if (ctor == null) {
+ // TODO: if argument mismatch, clarify that
+ throw new NoSuchMethodError(Debug.format("Can't find
constructor for " +
+
clazz.getSimpleName(), "args", args));
+ }
+
+ List<Class<?>> ptypes = Arrays.asList(ctor.getParameterTypes());
+ int pcount = ptypes.size();
+ if (isMangled) {
+ pcount /= 2;
+ }
+
+ // if this ctor is varargs we need to extract the variable
arguments, place them into an
+ // Object[] and create a new args array that has the varargs array
in the final position
+ Object[] rargs = ctor.isVarArgs() ? collectVarArgs(ptypes, pcount,
args) : args;
+
+ // if this method is mangled, we need to add dummy arguments in
the type-carrying parameter
+ // positions
+ if (isMangled) {
+ if (needsOuterThis) {
+ ptypes = ptypes.subList(1, ptypes.size());
+ }
+ rargs = addMangleArgs(ptypes, rargs);
+ }
+
+ // if this is an inner class in a non-static context, we need to
shift a reference to the
+ // containing class onto the constructor arguments
+ if (needsOuterThis) {
+ Object[] eargs = new Object[rargs.length+1];
+ // our enclosing instance may be an instance of the inner
class or an instance of the
+ // enclosing class, in the former case, we need to extract the
secret reference to the
+ // enclosing class from the inner class and use that as our
first argument
+ eargs[0] = clazz.isInstance(encl) ?
+ getEnclosingReference(clazz.getEnclosingClass(), encl) :
encl;
+ System.arraycopy(rargs, 0, eargs, 1, rargs.length);
+ rargs = eargs;
+ }
+
+ try {
+ ctor.setAccessible(true);
+ @SuppressWarnings("unchecked") T inst =
(T)ctor.newInstance(rargs);
+ return inst;
+ } catch (InstantiationException ie) {
+ throw new WrappedException(ie);
+ } catch (IllegalAccessException iae) {
+ throw new WrappedException(iae);
+ } catch (InvocationTargetException ite) {
+ unwrap(ite.getCause());
+ return null; // unreached
+ } catch (IllegalArgumentException iae) {
+ decode(iae);
+ return null; // unreached
+ }
+ }
+
+ /**
+ * Creates a new empty array with the specified dimensions. TODO: we
may need to box the array
+ * and preserve the original type information.
+ */
+ public static Object boxArray (Class<?> etype, Object array)
+ {
+ return array;
+ }
+
+ /**
+ * Creates a new empty array with the supplied initial arguments.
TODO: we may need to box the
+ * array and preserve the original type information.
+ */
+ public static Object boxArrayArgs (Class<?> etype, Object... elems)
+ {
+ try {
+ // try to put the values into an array of the requested type
+ Object tarray = Array.newInstance(etype, elems.length);
+ for (int ii = 0, ll = elems.length; ii < ll; ii++) {
+ // we explicitly coerce the element values to the array
element type if we're
+ // dealing with an array of primitives; Java allows
delcarations like "byte[] foo =
+ // { 1, 2, -128 }" where it automatically coerces the
integers to bytes; TODO:
+ // there are probably limitations on the coercion that we
should emulate
+ Object elem = etype.isPrimitive() ? coerce(etype,
elems[ii]) : elems[ii];
+ Array.set(tarray, ii, elem);
+ }
+ return tarray;
+ } catch (ArrayStoreException ase) {
+ return elems; // fall back to an object array to contain the
values
+ }
+ }
+
+ /**
+ * Invokes the specified method via reflection, handling the necessary
signature de-mangling.
+ */
+ public static Object invoke (String mname, Class<?>[] atypes, Object
receiver, Object[] args)
+ {
+ if (receiver == null) {
+ throw new NullPointerException(
+ Debug.format("Null receiver for " + mname, "atypes",
toArgTypes(args)));
+ }
+ Class<?> rclass = receiver.getClass();
+ Method m;
+
+ // if we were able to resolve the method at compile time, the
exact argument types will be
+ // provided in atypes which we can use to do precise and fast(er)
method lookup
+ if (atypes != null) {
+ Class<?> cclass = rclass;
+ do {
+ m = getMethod(cclass, mname, atypes);
+ if (m == null) {
+ if (!isInnerInNonStaticContext(cclass)) {
+ break;
+ }
+ cclass = cclass.getEnclosingClass();
+ receiver = getEnclosingReference(cclass, receiver);
+ }
+ } while (m == null);
+
+ } else {
+ // otherwise we've got to do an expensive search using the
runtime argument types
+ atypes = toArgTypes(args);
+ Class<?> cclass = rclass;
+ do {
+ m = resolveMethod(cclass, mname, atypes);
+ if (m == null) {
+ if (!isInnerInNonStaticContext(cclass)) {
+ break;
+ }
+ cclass = cclass.getEnclosingClass();
+ receiver = getEnclosingReference(cclass, receiver);
+ }
+ } while (m == null);
+ }
+
+ return invoke(checkMethod(m, mname, rclass, atypes, args),
receiver, args);
+ }
+
+ /**
+ * Invokes the specified static method via reflection, handling the
necessary signature
+ * de-mangling.
+ */
+ public static Object invokeStatic (String mname, Class<?>[] atypes,
Class<?> clazz,
+ Object[] args)
+ {
+ // if we were able to resolve the method at compile time, the
exact argument types will be
+ // provided in atypes which we can use to precise and fast(er)
method lookup
+ Method m = (atypes != null) ? getMethod(clazz, mname, atypes) :
+ // otherwise we've got to do an expensive search using the
runtime argument types
+ resolveMethod(clazz, mname, toArgTypes(args));
+ return invoke(checkMethod(m, mname, clazz, atypes, args), null,
args);
+ }
+
+ /**
+ * Returns the value of the field with the specified name in the
specified target object. Also
+ * handles the necessary magic to perform
<code>someArray.length</code>.
+ */
+ public static Object select (String fname, Object target)
+ {
+ if (target == null) {
+ throw new NullPointerException("Field access on null target");
+ }
+
+ Class<?> clazz = target.getClass();
+ if (clazz.isArray()) {
+ if (!fname.equals("length")) {
+ throw new RuntimeException("Arrays have no fields other
than 'length'");
+ }
+ return Array.getLength(target);
+ }
+
+ try {
+ Field field = getField(clazz, fname);
+ field.setAccessible(true);
+ return field.get(target);
+ } catch (NoSuchFieldException nsfe) {
+ throw new WrappedException(nsfe);
+ } catch (IllegalAccessException iae) {
+ throw new WrappedException(iae);
+ }
+ }
+
+ /**
+ * Assigns the specified value into the specified field of the target
object.
+ */
+ public static Object assign (Object target, String fname, Object value)
+ {
+ if (target == null) {
+ throw new NullPointerException("Field assignment to null
target: " + fname);
+ }
+
+ try {
+ Field field = getField(target.getClass(), fname);
+ field.setAccessible(true);
+ field.set(target, value);
+ return value; // TODO: is the result of assignment the coerced
type? in that case we
+ // need to return field.get(fname)
+
+ } catch (NoSuchFieldException nsfe) {
+ throw new WrappedException(nsfe);
+ } catch (IllegalAccessException iae) {
+ throw new WrappedException(iae);
+ }
+ }
+
+ /**
+ * Casts an object to an iterable over objects. Used to massage
foreach expressions.
+ */
+ public static Iterable<?> asIterable (final Object arg)
+ {
+ if (arg == null) {
+ throw new NullPointerException("Null iterable in foreach?");
+ } else if (arg instanceof Object[]) {
+ return Arrays.asList((Object[])arg);
+ } else if (arg instanceof Iterable<?>) {
+ @SuppressWarnings("unchecked") Iterable<Object> casted =
(Iterable<Object>)arg;
+ return casted;
+ } else if (arg instanceof boolean[]) {
+ return Booleans.asList((boolean[])arg);
+ } else if (arg instanceof byte[]) {
+ return Bytes.asList((byte[])arg);
+ } else if (arg instanceof char[]) {
+ return Chars.asList((char[])arg);
+ } else if (arg instanceof short[]) {
+ return Shorts.asList((short[])arg);
+ } else if (arg instanceof int[]) {
+ return Ints.asList((int[])arg);
+ } else if (arg instanceof long[]) {
+ return Longs.asList((long[])arg);
+ } else if (arg instanceof float[]) {
+ return Floats.asList((float[])arg);
+ } else if (arg instanceof double[]) {
+ return Doubles.asList((double[])arg);
+ } else {
+ // if none of those things matched, just try wrapping the
object in a proxy that treats
+ // it as an Iterable
+ return (Iterable<?>)asInterface(Iterable.class, arg);
+ }
+ }
+
+ /**
+ * Performs assignment of the specified value into the specified array
at the specified index.
+ * Returns the assigned value.
+ */
+ public static Object assignAt (Object array, Object index, Object
value)
+ {
+ if (array.getClass().getComponentType().isPrimitive()) {
+ Array.set(array, asInt(index), value);
+ } else {
+ // Array.set throws IllegalArgumentException instead of
ArrayStoreException when
+ // assigning a value of incorrect type to an element, so we
don't use it for
+ // non-primitive arrays
+ ((Object[])array)[asInt(index)] = value;
+ }
+ return value;
+ }
+
+ /**
+ * Returns the element of the supplied array at the specified index.
+ */
+ public static Object atIndex (Object array, Object index)
+ {
+ return Array.get(array, ((Number)index).intValue());
+ }
+
+ /**
+ * Performs primitive numeric widening on a value.
+ */
+ public static Object widen (Class<?> clazz, Object value)
+ {
+ if (COERCEALL) {
+ return coerce(clazz, value);
+ }
+ if (value == null) {
+ throw new NullPointerException("Cannot widen null to " +
clazz.getName());
+ }
+ // TODO: differentiate between coercers and wideners
+ Coercer c = COERCERS.get(Tuple.create(value.getClass(), clazz));
+ if (c == null) {
+ throw new IllegalArgumentException(
+ "Cannot widen " + value.getClass().getName() + " to " +
clazz.getName());
+ }
+ return c.coerce(value);
+ }
+
+ /**
+ * Performs primitive numeric coercion on a value.
+ */
+ public static Object coerce (Class<?> clazz, Object value)
+ {
+ if (value == null) {
+ throw new NullPointerException("Cannot coerce null to " +
clazz.getName());
+ }
+ Coercer c = COERCERS.get(Tuple.create(value.getClass(), clazz));
+ if (c == null) {
+ throw new IllegalArgumentException(
+ "Cannot coerce " + value.getClass().getName() + " to " +
clazz.getName());
+ }
+ return c.coerce(value);
+ }
+
+ /**
+ * Casts the supplied value to the specified type. Triggers full
context dump if the cast will
+ * fail and we are forced to abort execution with a ClassCastException.
+ */
+ public static <T> T checkedCast (Class<T> clazz, Object value)
+ {
+ Class<?> ptype = WRAPPERS.get(clazz);
+ try {
+ if (ptype == null) {
+ return clazz.cast(value);
+ } else {
+ @SuppressWarnings("unchecked") T cvalue =
(T)ptype.cast(value);
+ return cvalue;
+ }
+ } catch (ClassCastException cce) {
+ String vclass = (value == null) ? "<none>" :
value.getClass().getName();
+ Debug.warn("Runtime cast failure", "target", clazz, "value",
value, "vclass", vclass);
+ // TODO: trigger context dump, terminate program?
+ throw cce;
+ }
+ }
+
+ /**
+ * Casts the supplied value to the specified type. Triggers full
context dump if the cast will
+ * fail and we are forced to abort execution with a ClassCastException.
+ *
+ * <p>Note: we don't allow the type parameter of the supplied class to
specify the return type
+ * because we need to be able to supply the class literal for the
upper bound of a type
+ * variable but force the result type to be that of the type variable.
For example given a type
+ * variable <code>T</code> with upper bound <code>Object</code> we
want to be able to do:
+ * <code>T val = RT.<T>checkedCast(Object.class, oval)</code>
+ */
+ public static <T> T typeVarCast (Class<?> clazz, Object value)
+ {
+ try {
+ // the upper bound of a type variable will never be a
primitive type, so we don't need
+ // to check WRAPPERS like we do in checkedCast()
+ @SuppressWarnings("unchecked") T cvalue = (T)clazz.cast(value);
+ return cvalue;
+ } catch (ClassCastException cce) {
+ String vclass = (value == null) ? "<none>" :
value.getClass().getName();
+ Debug.warn("Runtime cast failure", "target", clazz, "value",
value, "vclass", vclass);
+ // TODO: trigger context dump, terminate program?
+ throw cce;
+ }
+ }
+
+ /**
+ * Notes that the code contained a cast to the specified type. Does
not fail with a
+ * ClassCastException if the types do not match, rather notes the
discrepancy and allows the
+ * code to proceed.
+ */
+ public static Object noteCast (Class<?> clazz, Object value)
+ {
+ // casts of null are NOOPs
+ if (value != null) {
+ // TODO: check whether the value is of the specified type
+ }
+ return value;
+ }
+
+ /**
+ * Converts the supplied value to a boolean. Supplying any non-Boolean
instance will result in
+ * a runtime failure.
+ */
+ public static boolean asBoolean (Object value)
+ {
+ if (value instanceof Boolean) {
+ return ((Boolean)value).booleanValue();
+ } else {
+ String type = (value == null) ? null :
value.getClass().getSimpleName();
+ throw new ClassCastException("Needed Boolean, got " + type);
+ }
+ }
+
+ /**
+ * Converts the supplied value to an int. If it is a boxed primitive
type, it will first be
+ * unboxed and then coerced to int which may result in loss of
precision. Supplying any
+ * non-numeric type will result in a runtime failure.
+ */
+ public static int asInt (Object value)
+ {
+ if (value instanceof Number) {
+ return ((Number)value).intValue();
+ } else if (value instanceof Character) {
+ return (int)(Character)value;
+ } else {
+ String type = (value == null) ? null :
value.getClass().getSimpleName();
+ throw new ClassCastException("Needed numeric type, got " +
type);
+ }
+ }
+
+ /**
+ * Creates a proxy that implements the supplied interface by calling
through to methods with
+ * the same name and parameter types in the supplied underlying object.
+ */
+ public static <T> T asInterface (Class<T> iface, final Object inst)
+ {
+ Preconditions.checkNotNull(iface);
+ Preconditions.checkNotNull(inst);
+
+ Object pinst = Proxy.newProxyInstance(
+ iface.getClassLoader(), new Class<?>[] { iface }, new
InvocationHandler() {
+ public Object invoke (Object proxy, Method method, Object[]
args) {
+ // find the method to which this interface method maps
(using a cache)
+ Method target = _meths.get(method);
+ if (target == null) {
+ target = findProxyMethod(inst.getClass(),
method.getName(),
+ method.getParameterTypes(),
+ Lists.<Method>newArrayList());
+ target.setAccessible(true);
+ _meths.put(method, target);
+ }
+
+ // if this method is mangled, we need to add dummy
arguments in the type-carrying
+ // parameter positions
+ if (isMangled(target.getName())) {
+ args =
addMangleArgs(Arrays.asList(target.getParameterTypes()), args);
+ }
+
+ // finally invoke the method
+ return checkedInvoke(target, inst, args);
+ }
+ protected Map<Method, Method> _meths = Maps.newHashMap();
+ });
+
+ @SuppressWarnings("unchecked") T proxy = (T)pinst;
+ return proxy;
+ }
+
+ /**
+ * A helper method for initializing primitive values.
+ *
+ * It is supplied the default value
+ * appropriate to the type of the primitive field and the field's
current value. If the
+ * (detyped) field has not yet been initialized, curVal will be null
and the appropriate
+ * initial value will be returned. Otherwise the current value will be
returned.
+ *
+ * <p> This preserves correct behavior in situations where primitive
fields are initialized by
+ * abstract methods called by a parent class constructor, because our
primitive initialization
+ * code runs (of necessity) after the superclass constructor.
+ */
+ public static Object initPrimitive (Object target, String fieldName,
Class<?> fieldType)
+ {
+ Object curVal = select(fieldName, target);
+ return (curVal != null) ? curVal : DEFAULT_VALUES.get(fieldType);
+ }
+
+ /**
+ * A helper for {@link #select} and {@link #assign}.
+ *
+ * @throws NoSuchFieldException if the field could not be found.
+ */
+ protected static Field getField (Class<?> clazz, String fname)
+ throws NoSuchFieldException
+ {
+ FieldKey key = new FieldKey(clazz, fname);
+ Field field = _fieldCache.get(key);
+ if (field == null) {
+ _fieldCache.put(key, field = findField(clazz, fname));
+ }
+ return field;
+ }
+
+ /**
+ * A helper for {@link #getField}.
+ */
+ protected static Field findField (Class<?> clazz, String fname)
+ throws NoSuchFieldException
+ {
+ for (Field field : clazz.getDeclaredFields()) {
+ if (field.getName().equals(fname)) {
+ return field;
+ }
+ }
+ Class<?> parent = clazz.getSuperclass();
+ if (parent == null) {
+ throw new NoSuchFieldException(fname);
+ }
+ return findField(parent, fname);
+ }
+
+ /**
+ * Invokes the specified method with the supplied arguments.
+ */
+ protected static Object invoke (Method method, Object receiver,
Object[] rargs)
+ {
+ boolean isMangled = isMangled(method.getName());
+ List<Class<?>> ptypes = Arrays.asList(method.getParameterTypes());
+ int pcount = ptypes.size();
+ if (isMangled) {
+ pcount /= 2;
+ }
+
+ // if this method is varargs we need to extract the variable
arguments, place them into an
+ // Object[] and create a new args array that has the varargs array
in the final position
+ Object[] aargs = method.isVarArgs() ? collectVarArgs(ptypes,
pcount, rargs) : rargs;
+
+ // if this method is mangled, we need to add dummy arguments in
the type-carrying parameter
+ // positions
+ if (isMangled) {
+ aargs = addMangleArgs(ptypes, (aargs == null) ? new
Object[1] : aargs);
+ }
+
+ // for any argument position that does not match, but which takes
an interface, create a
+ // proxy to that interface using the actual argument
+ if (!isMangled) {
+ for (int ii = 0; ii < pcount; ii++) {
+ if (ptypes.get(ii).isInterface()
&& !ptypes.get(ii).isInstance(aargs[ii])) {
+ aargs[ii] = asInterface(ptypes.get(ii), aargs[ii]);
+ }
+ }
+ }
+
+ // Debug.temp("Invoking " + method, "recv", receiver, "args",
aargs);
+ method.setAccessible(true); // TODO: cache which methods we've
toggled if slow
+ return checkedInvoke(method, receiver, aargs);
+ }
+
+ /**
+ * A helper for {@link #newInstance}.
+ */
+ protected static Constructor<?> findConstructor (
+ Class<?> clazz, boolean needsOuterThis, boolean isMangled,
Class<?>[] atypes)
+ {
+ MethodKey key = new MethodKey(clazz, "<init>", atypes);
+ Constructor<?> cached = _ctorCache.get(key);
+ if (cached != null) {
+ return cached;
+ }
+
+ OUTER:
+ for (Constructor<?> ctor : clazz.getDeclaredConstructors()) {
+ Class<?>[] ptypes = ctor.getParameterTypes();
+ int poff = isMangled ? ptypes.length/2 : 0;
+ // ignore the outer this argument when testing for
applicability
+ if (needsOuterThis) {
+ poff += 1;
+ }
+ if (ptypes.length - poff != atypes.length) {
+ continue;
+ }
+ for (int ii = 0; ii < atypes.length; ii++) {
+ if (ptypes[ii+poff] != atypes[ii]) {
+ continue OUTER;
+ }
+ }
+ _ctorCache.put(key, ctor);
+ return ctor;
+ }
+ return null;
+ }
+
+ /**
+ * A helper for {@link #invoke(Method,Object,Object[])}.
+ */
+ protected static Method getMethod (Class<?> clazz, String mname,
Class<?>[] atypes)
+ {
+ MethodKey key = new MethodKey(clazz, mname, atypes);
+ Method method = _methodCache.get(key);
+ if (method == null) {
+ // find method may return null, in which case we'll cache that
this method was
+ // unresolvable and immediately return so on future invocations
+ _methodCache.put(key, method = findMethod(clazz, mname,
atypes));
+ }
+ return method;
+ }
+
+ /**
+ * A helper for {@link #getMethod}.
+ */
+ protected static Method findMethod (Class<?> clazz, String mname,
Class<?>[] atypes)
+ {
+ OUTER:
+ for (Method method : clazz.getDeclaredMethods()) {
+ String cmname = method.getName();
+ boolean isMangled = isMangled(cmname);
+ if (isMangled) {
+ cmname = cmname.substring(0,
cmname.length()-MM_SUFFIX.length());
+ }
+ if (!cmname.equals(mname)) {
+ continue;
+ }
+ Class<?>[] ptypes = method.getParameterTypes();
+ int poff = isMangled ? ptypes.length/2 : 0;
+ if (ptypes.length - poff != atypes.length) {
+ continue;
+ }
+ for (int ii = 0; ii < atypes.length; ii++) {
+ if (ptypes[ii+poff] != atypes[ii]) {
+ continue OUTER;
+ }
+ }
+ return method;
+ }
+ Class<?> parent = clazz.getSuperclass();
+ return (parent == null) ? null : findMethod(parent, mname, atypes);
+ }
+
+ /**
+ * Resolves the best matching method given the supplied runtime
argument types. This is used
+ * for methods that could not be resolved at compile time and thus for
which we do not have to
+ * preserve method resolution equivalent equivalent to that done for
type correct code.
+ */
+ protected static Method resolveMethod (Class<?> clazz, String mname,
Class<?>[] atypes)
+ {
+ MethodData mdata = new MethodData();
+ resolveMethod(clazz, mname, atypes, mdata);
+ return mdata.best;
+ }
+
+ protected static void resolveMethod (Class<?> clazz, String mname,
Class<?>[] atypes,
+ MethodData mdata)
+ {
+ for (Method method : clazz.getDeclaredMethods()) {
+ String cmname = method.getName();
+ boolean isMangled = isMangled(cmname);
+ if (isMangled) {
+ cmname = cmname.substring(0,
cmname.length()-MM_SUFFIX.length());
+ }
+ if (!cmname.equals(mname)) {
+ continue;
+ }
+
+ Class<?>[] ptypes = method.getParameterTypes();
+ if (!argCountMatch(isMangled, method.isVarArgs(),
ptypes.length, atypes.length)) {
+ continue;
+ }
+
+ Match match = argTypeMatch(
+ Arrays.asList(ptypes), isMangled, method.isVarArgs(),
atypes);
+ if (match == Match.NONE) {
+ // no match, keep looking
+
+ } else if (match.isCloser(mdata.match)) {
+ mdata.best = method;
+ mdata.match = match;
+
+ } else if (match == mdata.match) {
+ // if the argument types are exactly the same and the
declaring class differs,
+ // we're just seeing a parent method that has been
overridden by our best match
+ if (!mdata.best.getDeclaringClass().equals(clazz) &&
+ Arrays.equals(mdata.best.getParameterTypes(), ptypes))
{
+ continue;
+ }
+ throw new AmbiguousMethodError(
+ Debug.format("Two methods (or more) with matching
types", "mname", mname,
+ "atypes", atypes, "m1", mdata.best, "m2",
method));
+ } // else: keep our existing match, it's closer
+ }
+
+ Class<?> parent = clazz.getSuperclass();
+ if (parent != null) {
+ resolveMethod(parent, mname, atypes, mdata);
+ }
+ }
+
+ /**
+ * A helper for {@link #asInterface}.
+ */
+ protected static Method findProxyMethod (
+ Class<?> clazz, String mname, Class<?>[] atypes, List<Method>
candidates)
+ {
+ OUTER:
+ for (Method method : clazz.getDeclaredMethods()) {
+ String cmname = method.getName();
+ boolean isMangled = isMangled(cmname);
+ if (isMangled) {
+ cmname = cmname.substring(0,
cmname.length()-MM_SUFFIX.length());
+ }
+ if (!cmname.equals(mname)) {
+ continue;
+ }
+ Class<?>[] ptypes = method.getParameterTypes();
+ int poff = isMangled ? ptypes.length/2 : 0;
+ if (ptypes.length - poff != atypes.length) {
+ continue;
+ }
+ for (int ii = 0; ii < atypes.length; ii++) {
+ if (ptypes[ii+poff] != atypes[ii]) {
+ candidates.add(method);
+ continue OUTER;
+ }
+ }
+ return method;
+ }
+
+ // if we have a superclass, check it for an exact match (or
additional candidates)
+ Class<?> parent = clazz.getSuperclass();
+ if (parent != null) {
+ return findProxyMethod(parent, mname, atypes, candidates);
+ }
+
+ switch (candidates.size()) {
+ case 1:
+ return candidates.get(0);
+ case 0:
+ throw new NoSuchMethodError(Debug.format(clazz + "." +
mname, "atypes", atypes));
+ default:
+ throw new AmbiguousMethodError(
+ Debug.format("No exact match and multiple inexact matches
for method",
+ "mname", mname, "atypes", atypes));
+ }
+ }
+
+ /**
+ * Helper for {@link #invokeStatic} and {@link #invoke}.
+ */
+ protected static Method checkMethod (
+ Method m, String mname, Class<?> clazz, Class<?>[] atypes,
Object[] args)
+ {
+ if (m == null) {
+ // TODO: if argument mismatch, clarify that, if total method
lacking, clarify that
+ throw new NoSuchMethodError(
+ Debug.format(clazz + "." + mname, "ftypes",
atypes, "atypes", toArgTypes(args)));
+ } else {
+ return m;
+ }
+ }
+
+ /**
+ * Helper for {@link #invoke} and {@link #asInterface}.
+ */
+ protected static Object checkedInvoke (Method method, Object receiver,
Object[] args)
+ {
+ try {
+ return method.invoke(receiver, args);
+ } catch (IllegalAccessException iae) {
+ throw new WrappedException(iae);
+ } catch (InvocationTargetException ite) {
+ unwrap(ite.getCause());
+ return null; // unreached
+ } catch (IllegalArgumentException iae) {
+ decode(iae);
+ return null; // unreached
+ }
+ }
+
+ /**
+ * A helper for {@link #newInstance}.
+ */
+ protected static Constructor<?> findConstructor (
+ Class<?> clazz, boolean needsOuterThis, boolean isMangled,
Object[] args)
+ {
+ Constructor<?> best = null;
+ Match bestMatch = Match.NONE;
+
+ Class<?>[] atypes = toArgTypes(args);
+ for (Constructor<?> ctor : clazz.getDeclaredConstructors()) {
+ List<Class<?>> ptypes =
Arrays.asList(ctor.getParameterTypes());
+ if (needsOuterThis) {
+ // ignore the outer this argument when testing for
applicability
+ ptypes = ptypes.subList(1, ptypes.size());
+ }
+
+ if (!argCountMatch(isMangled, ctor.isVarArgs(), ptypes.size(),
atypes.length)) {
+ continue;
+ }
+
+ Match match = argTypeMatch(ptypes, isMangled,
ctor.isVarArgs(), atypes);
+ if (match == Match.NONE) {
+ // no match, keep looking
+
+ } else if (match.isCloser(bestMatch)) {
+ best = ctor;
+ bestMatch = match;
+
+ } else if (match == bestMatch) {
+ throw new AmbiguousMethodError(
+ Debug.format("Two (or more) matching ctors", "clazz",
clazz.getName(),
+ "atypes", atypes, "c1", best, "c2",
ctor));
+ } // else: existing match is better, move it along
+ }
+
+ return best;
+ }
+
+ protected static boolean argCountMatch (
+ boolean isMangled, boolean isVarArgs, int pcount, int acount)
+ {
+ if (isMangled) {
+ // we use this in favor of pcount/=2 because sometimes the
compiler inserts synthetic
+ // ctors which tack an argument onto a mangled method (giving
it an odd number of
+ // arguments, which would otherwise cause confusion); TODO:
find out why they're added
+ pcount -= pcount / 2;
+ }
+ return (pcount == acount) || (isVarArgs && (pcount-1) <= acount);
+ }
+
+ protected static Match argTypeMatch (
+ List<Class<?>> ptypes, boolean isMangled, boolean isVarArgs,
Class<?>[] atypes)
+ {
+ // determine whether all fixed arity arguments match
+ int pcount = isMangled ? ptypes.size()/2 : ptypes.size();
+ int fpcount = isVarArgs ? pcount-1 : pcount, poff = isMangled ?
pcount : 0;
+ Match match = Match.EXACT; // assume exact match
+ for (int ii = 0; ii < fpcount; ii++) {
+ Class<?> atype = atypes[ii];
+ if (atype == null) {
+ continue;
+ }
+ Class<?> ptype = ptypes.get(poff + ii);
+ if (atype == ptype) {
+ continue; // exact match, no conversion demotion
+ }
+ if (ptype.isAssignableFrom(atype)) {
+ match = match.lesser(Match.SUBTYPE); // reduce to subtype
conversion
+ continue;
+ }
+ if (boxType(ptype).equals(atype) ||
+ (ptype.isPrimitive() && COERCIONS.containsEntry(atype,
ptype))) {
+ match = match.lesser(Match.CONVERT); // reduce to
boxing/widening conversion
+ continue;
+ }
+ if (ptype.isInterface()) {
+ match = match.lesser(Match.PROXIED); // we'll proxy this
interface
+ continue;
+ }
+ return Match.NONE; // argument mismatch
+ }
+
+// TODO: should we leave this out, or is there some better check we can do
given that detyped
+// varargs becomes foo(Object vargs) and library varargs is foo(T[]
vargs); maybe only enforce type
+// if we see an actual array type (since we then know we have to cast)
+
+// // make sure all variable artity arguments match
+// if (isVarArgs) {
+// Class<?> ptype = boxType(ptypes[poff+fpcount]);
+// for (int ii = fpcount; ii < args.length; ii++) {
+// if (atypes[ii] != null && !isAssignableFrom(ptype,
atypes[ii])) {
+// return false;
+// }
+// }
+// }
+ return match;
+ }
+
+ /**
+ * Returns the class to which to promote both sides of a numeric
operation involving the
+ * supplied left- and right-hand-sides.
+ */
+ protected static Class<?> promote (Object lhs, Object rhs)
+ {
+ // if either is a double, we promote to double
+ Class<?> lhc = lhs.getClass(), rhc = rhs.getClass();
+ if (lhc == Double.class || rhc == Double.class) {
+ return Double.class;
+ }
+
+ // if either side is a long we'll either promote to long or double
+ if (lhs == Long.class) {
+ return (rhc == Float.class) ? Double.class : Long.class;
+ } else if (rhs == Long.class) {
+ return (lhc == Float.class) ? Double.class : Long.class;
+ }
+
+ // if one side is a float, then we promote to float
+ if (lhc == Float.class || rhc == Float.class) {
+ return Float.class;
+ }
+
+ // otherwise we promote to int
+ return Integer.class;
+ }
+
+ protected static Class<?> promoteFloat (Class<?> other)
+ {
+ return (other == Long.class) ? Double.class : Float.class;
+ }
+
+ protected static boolean isMangled (String name)
+ {
+ return name.endsWith(MM_SUFFIX);
+ }
+
+ protected static Class<?>[] toArgTypes (Object[] args)
+ {
+ Class<?>[] atypes = new Class<?>[args == null ? 0 : args.length];
+ for (int ii = 0, ll = atypes.length; ii < ll; ii++) {
+ // it'd be nice to have bottom here rather than null, alas
+ atypes[ii] = (args[ii] == null) ? null : args[ii].getClass();
+ }
+ return atypes;
+ }
+
+ protected static Object[] collectVarArgs (List<Class<?>> ptypes, int
pcount, Object[] rargs)
+ {
+ // if the caller is passing null in the varargs position, we need
to wrap that in an object
+ // array so that when we pass it to Method.invoke, the null is
properly passed on to the
+ // underlying varargs method
+ if (rargs == null) {
+ return new Object[] { null };
+ }
+
+ // if we have more than one argument in varargs position or we
have a non-array in varargs
+ // position, we need to wrap the varargs into an array (this is
normally done by javac); we
+ // heuristically assume that if there's only one argument in the
varargs position and it's
+ // an array, then the caller did the wrapping already
+ int fpcount = pcount-1, vacount = rargs.length-fpcount;
+ if (vacount != 1 || (rargs[fpcount] != null
&& !rargs[fpcount].getClass().isArray())) {
+ // the final argument position indicates the type of the
varargs array
+ Class<?> vatype = ptypes.get(ptypes.size()-1);
+ assert vatype.getComponentType() != null : "Varargs position
not array type";
+ Object vargs = Array.newInstance(vatype.getComponentType(),
vacount);
+ System.arraycopy(rargs, fpcount, vargs, 0,
rargs.length-fpcount);
+ Object[] aargs = new Object[fpcount+1];
+ System.arraycopy(rargs, 0, aargs, 0, fpcount);
+ aargs[fpcount] = vargs;
+ return aargs;
+ }
+
+ return rargs;
+ }
+
+ protected static Object[] addMangleArgs (List<Class<?>> ptypes,
Object[] args)
+ {
+ Object[] margs = new Object[args.length*2];
+ System.arraycopy(args, 0, margs, 0, args.length);
+ for (int ii = args.length; ii < ptypes.size(); ii++) {
+ // if the argument is a primitive type, DEFAULT_VALUES will
contain a suitable dummy
+ // value for that type, otherwise it will return null which is
the desired dummy value
+ // for all non-primitive types
+ margs[ii] = DEFAULT_VALUES.get(ptypes.get(ii));
+ // if the argument type is primitive, insert a coercion from
the argument type to the
+ // parameter type (JLS 5.3 requires widening; TODO: we're also
doing narrowing here
+ // which is probably not desirable in the long term)
+ int aii = ii-args.length;
+ if (margs[aii] != null && margs[ii] != null) {
+ margs[aii] = widen(ptypes.get(ii), margs[aii]);
+ }
+ }
+ return margs;
+ }
+
+ protected static boolean isInnerInNonStaticContext (Class<?> clazz)
+ {
+ if (clazz.isLocalClass() || clazz.isAnonymousClass()) {
+ // a local or anonymous class must be declared in a method or
a constructor, in the
***The diff for this file has been truncated for email.***
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/Transformed.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,18 @@
+//
+// $Id$
+
+package org.ductilej.runtime;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * An annotation that identifies a class that has been transformed.
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Transformed
+{
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/UnOps.java Sat Nov 27 12:15:19 2010
@@ -0,0 +1,19 @@
+//
+// $Id$
+
+package org.ductilej.runtime;
+
+/**
+ * Encapsulates unary operations on primitive types. Specialized instances
of this class are
+ * automatically generated for all primitive types for reasonably fast
dispatch of ad-hoc
+ * polymorphic unary operators.
+ */
+public interface UnOps
+{
+ public Object plus (Object arg);
+ public Object minus (Object arg);
+ public Object increment (Object arg);
+ public Object decrement (Object arg);
+ public Object bitComp (Object arg);
+ public Object logicalComp (Object arg);
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/Unop.java Sat Nov 27 12:15:19 2010
@@ -0,0 +1,89 @@
+//
+// $Id$
+
+package org.ductilej.runtime;
+
+import java.util.Map;
+
+import com.google.common.collect.ImmutableMap;
+
+import org.ductilej.runtime.ops.*;
+
+/**
+ * Used to dispatch unary operations at runtime.
+ */
+public enum Unop
+{
+ UNARY_MINUS {
+ public Object invoke (Object arg) {
+ return get(arg).minus(arg);
+ }
+ },
+ UNARY_PLUS {
+ public Object invoke (Object arg) {
+ return get(arg).plus(arg);
+ }
+ },
+
+ BITWISE_COMPLEMENT {
+ public Object invoke (Object arg) {
+ return get(arg).bitComp(arg);
+ }
+ },
+ LOGICAL_COMPLEMENT {
+ public Object invoke (Object arg) {
+ return get(arg).logicalComp(arg);
+ }
+ },
+
+ // the side effects for these operations are handled by rewriting the
AST, so they simply
+ // need to return an incremented or decremented value
+ PREFIX_INCREMENT {
+ public Object invoke (Object arg) {
+ return get(arg).increment(arg);
+ }
+ },
+ POSTFIX_INCREMENT {
+ public Object invoke (Object arg) {
+ return get(arg).increment(arg);
+ }
+ },
+ PREFIX_DECREMENT {
+ public Object invoke (Object arg) {
+ return get(arg).decrement(arg);
+ }
+ },
+ POSTFIX_DECREMENT {
+ public Object invoke (Object arg) {
+ return get(arg).decrement(arg);
+ }
+ };
+
+ /**
+ * Executes this unary operation.
+ */
+ public abstract Object invoke (Object arg);
+
+ /**
+ * Returns the {@link UnOps} instance appropriate for the supplied
expression argument type.
+ */
+ protected UnOps get (Object arg)
+ {
+ try {
+ return UNOPS.get(arg.getClass());
+ } catch (NullPointerException npe) {
+ throw new NullPointerException("Unary op (" + this + ") on
null arg.");
+ }
+ }
+
+ protected static final Map<Class<?>, UnOps> UNOPS =
ImmutableMap.<Class<?>, UnOps>builder().
+ put(Boolean.class, new BooleanOps()).
+ put(Byte.class, new ByteOps()).
+ put(Short.class, new ShortOps()).
+ put(Character.class, new CharacterOps()).
+ put(Integer.class, new IntegerOps()).
+ put(Long.class, new LongOps()).
+ put(Float.class, new FloatOps()).
+ put(Double.class, new DoubleOps()).
+ build();
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/WrappedException.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,15 @@
+//
+// $Id$
+
+package org.ductilej.runtime;
+
+/**
+ * Used to note checked exceptions wrapped during reflective invocation so
that they can be
+ * unwrapped in the appropriate places.
+ */
+public class WrappedException extends RuntimeException
+{
+ public WrappedException (Throwable cause) {
+ super(cause);
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/BooleanBooleanOps.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Boolean and rhs of Boolean.
+ */
+public class BooleanBooleanOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Plus illegal on boolean");
+ }
+ public Object minus (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Minus illegal on boolean");
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Multiply illegal on boolean");
+ }
+ public Object divide (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Divide illegal on boolean");
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Remainder illegal on boolean");
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Boolean)lhs).booleanValue() |
((Boolean)rhs).booleanValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Boolean)lhs).booleanValue() &
((Boolean)rhs).booleanValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Boolean)lhs).booleanValue() ^
((Boolean)rhs).booleanValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Left shift illegal on
boolean");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Right shift illegal on
boolean");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Unsigned right shift illegal
on boolean");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Boolean)lhs).booleanValue() ==
((Boolean)rhs).booleanValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Less than illegal on boolean");
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Less than equal illegal on
boolean");
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Greater than illegal on
boolean");
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ throw new IllegalArgumentException("Greater than equal illegal on
boolean");
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/BooleanOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,31 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.UnOps;
+
+/**
+ * Implements unary operations for Boolean.
+ */
+public class BooleanOps implements UnOps
+{
+ public Object plus (Object arg) {
+ throw new IllegalArgumentException("Plus illegal on boolean");
+ }
+ public Object minus (Object arg) {
+ throw new IllegalArgumentException("Minus illegal on boolean");
+ }
+ public Object increment (Object arg) {
+ throw new IllegalArgumentException("Increment illegal on boolean");
+ }
+ public Object decrement (Object arg) {
+ throw new IllegalArgumentException("Decrement illegal on boolean");
+ }
+ public Object bitComp (Object arg) {
+ throw new IllegalArgumentException("Bitwise complement illegal on
boolean");
+ }
+ public Object logicalComp (Object arg) {
+ return !((Boolean)arg).booleanValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/ByteByteOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Byte and rhs of Byte.
+ */
+public class ByteByteOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() + ((Byte)rhs).byteValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() - ((Byte)rhs).byteValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() * ((Byte)rhs).byteValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() / ((Byte)rhs).byteValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() % ((Byte)rhs).byteValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() | ((Byte)rhs).byteValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() & ((Byte)rhs).byteValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() ^ ((Byte)rhs).byteValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() << ((Byte)rhs).byteValue();
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >> ((Byte)rhs).byteValue();
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >>> ((Byte)rhs).byteValue();
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() == ((Byte)rhs).byteValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() < ((Byte)rhs).byteValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() <= ((Byte)rhs).byteValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() > ((Byte)rhs).byteValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >= ((Byte)rhs).byteValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/ByteCharacterOps.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Byte and rhs of Character.
+ */
+public class ByteCharacterOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() + ((Character)rhs).charValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() - ((Character)rhs).charValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() * ((Character)rhs).charValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() / ((Character)rhs).charValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() % ((Character)rhs).charValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() | ((Character)rhs).charValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() & ((Character)rhs).charValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() ^ ((Character)rhs).charValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() << ((Character)rhs).charValue();
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >> ((Character)rhs).charValue();
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >>> ((Character)rhs).charValue();
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() == ((Character)rhs).charValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() < ((Character)rhs).charValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() <= ((Character)rhs).charValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() > ((Character)rhs).charValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >= ((Character)rhs).charValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/ByteDoubleOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Byte and rhs of Double.
+ */
+public class ByteDoubleOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() + ((Double)rhs).doubleValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() - ((Double)rhs).doubleValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() * ((Double)rhs).doubleValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() / ((Double)rhs).doubleValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() % ((Double)rhs).doubleValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() == ((Double)rhs).doubleValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() < ((Double)rhs).doubleValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() <= ((Double)rhs).doubleValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() > ((Double)rhs).doubleValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >= ((Double)rhs).doubleValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/ByteFloatOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Byte and rhs of Float.
+ */
+public class ByteFloatOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() + ((Float)rhs).floatValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() - ((Float)rhs).floatValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() * ((Float)rhs).floatValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() / ((Float)rhs).floatValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() % ((Float)rhs).floatValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() == ((Float)rhs).floatValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() < ((Float)rhs).floatValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() <= ((Float)rhs).floatValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() > ((Float)rhs).floatValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >= ((Float)rhs).floatValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/ByteIntegerOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Byte and rhs of Integer.
+ */
+public class ByteIntegerOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() + ((Integer)rhs).intValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() - ((Integer)rhs).intValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() * ((Integer)rhs).intValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() / ((Integer)rhs).intValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() % ((Integer)rhs).intValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() | ((Integer)rhs).intValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() & ((Integer)rhs).intValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() ^ ((Integer)rhs).intValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() << ((Integer)rhs).intValue();
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >> ((Integer)rhs).intValue();
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >>> ((Integer)rhs).intValue();
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() == ((Integer)rhs).intValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() < ((Integer)rhs).intValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() <= ((Integer)rhs).intValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() > ((Integer)rhs).intValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >= ((Integer)rhs).intValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/ByteLongOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Byte and rhs of Long.
+ */
+public class ByteLongOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() + ((Long)rhs).longValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() - ((Long)rhs).longValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() * ((Long)rhs).longValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() / ((Long)rhs).longValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() % ((Long)rhs).longValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() | ((Long)rhs).longValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() & ((Long)rhs).longValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() ^ ((Long)rhs).longValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() << ((Long)rhs).longValue();
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >> ((Long)rhs).longValue();
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >>> ((Long)rhs).longValue();
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() == ((Long)rhs).longValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() < ((Long)rhs).longValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() <= ((Long)rhs).longValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() > ((Long)rhs).longValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >= ((Long)rhs).longValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/ByteOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,33 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.UnOps;
+
+/**
+ * Implements unary operations for Byte.
+ */
+public class ByteOps implements UnOps
+{
+ public Object plus (Object arg) {
+ return +((Byte)arg).byteValue();
+ }
+ public Object minus (Object arg) {
+ return -((Byte)arg).byteValue();
+ }
+ public Object increment (Object arg) {
+ byte tmp = ((Byte)arg).byteValue();
+ return ++tmp;
+ }
+ public Object decrement (Object arg) {
+ byte tmp = ((Byte)arg).byteValue();
+ return --tmp;
+ }
+ public Object bitComp (Object arg) {
+ return ~((Byte)arg).byteValue();
+ }
+ public Object logicalComp (Object arg) {
+ throw new IllegalArgumentException("Logical complement illegal on
byte");
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/ByteShortOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Byte and rhs of Short.
+ */
+public class ByteShortOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() + ((Short)rhs).shortValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() - ((Short)rhs).shortValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() * ((Short)rhs).shortValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() / ((Short)rhs).shortValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() % ((Short)rhs).shortValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() | ((Short)rhs).shortValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() & ((Short)rhs).shortValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() ^ ((Short)rhs).shortValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() << ((Short)rhs).shortValue();
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >> ((Short)rhs).shortValue();
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >>> ((Short)rhs).shortValue();
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() == ((Short)rhs).shortValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() < ((Short)rhs).shortValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() <= ((Short)rhs).shortValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() > ((Short)rhs).shortValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Byte)lhs).byteValue() >= ((Short)rhs).shortValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/CharacterByteOps.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Character and rhs of Byte.
+ */
+public class CharacterByteOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() + ((Byte)rhs).byteValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() - ((Byte)rhs).byteValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() * ((Byte)rhs).byteValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() / ((Byte)rhs).byteValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() % ((Byte)rhs).byteValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() | ((Byte)rhs).byteValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() & ((Byte)rhs).byteValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() ^ ((Byte)rhs).byteValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() << ((Byte)rhs).byteValue();
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >> ((Byte)rhs).byteValue();
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >>> ((Byte)rhs).byteValue();
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() == ((Byte)rhs).byteValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() < ((Byte)rhs).byteValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() <= ((Byte)rhs).byteValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() > ((Byte)rhs).byteValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >= ((Byte)rhs).byteValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/CharacterCharacterOps.java Sat
Nov 27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Character and rhs of Character.
+ */
+public class CharacterCharacterOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() + ((Character)rhs).charValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() - ((Character)rhs).charValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() * ((Character)rhs).charValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() / ((Character)rhs).charValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() % ((Character)rhs).charValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() | ((Character)rhs).charValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() & ((Character)rhs).charValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() ^ ((Character)rhs).charValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() <<
((Character)rhs).charValue();
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >>
((Character)rhs).charValue();
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >>>
((Character)rhs).charValue();
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() ==
((Character)rhs).charValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() < ((Character)rhs).charValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() <=
((Character)rhs).charValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() > ((Character)rhs).charValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >=
((Character)rhs).charValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/CharacterDoubleOps.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Character and rhs of Double.
+ */
+public class CharacterDoubleOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() + ((Double)rhs).doubleValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() - ((Double)rhs).doubleValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() * ((Double)rhs).doubleValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() / ((Double)rhs).doubleValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() % ((Double)rhs).doubleValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() == ((Double)rhs).doubleValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() < ((Double)rhs).doubleValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() <= ((Double)rhs).doubleValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() > ((Double)rhs).doubleValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >= ((Double)rhs).doubleValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/CharacterFloatOps.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Character and rhs of Float.
+ */
+public class CharacterFloatOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() + ((Float)rhs).floatValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() - ((Float)rhs).floatValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() * ((Float)rhs).floatValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() / ((Float)rhs).floatValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() % ((Float)rhs).floatValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() == ((Float)rhs).floatValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() < ((Float)rhs).floatValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() <= ((Float)rhs).floatValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() > ((Float)rhs).floatValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >= ((Float)rhs).floatValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/CharacterIntegerOps.java Sat
Nov 27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Character and rhs of Integer.
+ */
+public class CharacterIntegerOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() + ((Integer)rhs).intValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() - ((Integer)rhs).intValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() * ((Integer)rhs).intValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() / ((Integer)rhs).intValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() % ((Integer)rhs).intValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() | ((Integer)rhs).intValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() & ((Integer)rhs).intValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() ^ ((Integer)rhs).intValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() << ((Integer)rhs).intValue();
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >> ((Integer)rhs).intValue();
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >>> ((Integer)rhs).intValue();
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() == ((Integer)rhs).intValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() < ((Integer)rhs).intValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() <= ((Integer)rhs).intValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() > ((Integer)rhs).intValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >= ((Integer)rhs).intValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/CharacterLongOps.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Character and rhs of Long.
+ */
+public class CharacterLongOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() + ((Long)rhs).longValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() - ((Long)rhs).longValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() * ((Long)rhs).longValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() / ((Long)rhs).longValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() % ((Long)rhs).longValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() | ((Long)rhs).longValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() & ((Long)rhs).longValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() ^ ((Long)rhs).longValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() << ((Long)rhs).longValue();
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >> ((Long)rhs).longValue();
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >>> ((Long)rhs).longValue();
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() == ((Long)rhs).longValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() < ((Long)rhs).longValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() <= ((Long)rhs).longValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() > ((Long)rhs).longValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >= ((Long)rhs).longValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/CharacterOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,33 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.UnOps;
+
+/**
+ * Implements unary operations for Character.
+ */
+public class CharacterOps implements UnOps
+{
+ public Object plus (Object arg) {
+ return +((Character)arg).charValue();
+ }
+ public Object minus (Object arg) {
+ return -((Character)arg).charValue();
+ }
+ public Object increment (Object arg) {
+ char tmp = ((Character)arg).charValue();
+ return ++tmp;
+ }
+ public Object decrement (Object arg) {
+ char tmp = ((Character)arg).charValue();
+ return --tmp;
+ }
+ public Object bitComp (Object arg) {
+ return ~((Character)arg).charValue();
+ }
+ public Object logicalComp (Object arg) {
+ throw new IllegalArgumentException("Logical complement illegal on
char");
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/CharacterShortOps.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Character and rhs of Short.
+ */
+public class CharacterShortOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() + ((Short)rhs).shortValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() - ((Short)rhs).shortValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() * ((Short)rhs).shortValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() / ((Short)rhs).shortValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() % ((Short)rhs).shortValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() | ((Short)rhs).shortValue();
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() & ((Short)rhs).shortValue();
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() ^ ((Short)rhs).shortValue();
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() << ((Short)rhs).shortValue();
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >> ((Short)rhs).shortValue();
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >>> ((Short)rhs).shortValue();
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() == ((Short)rhs).shortValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() < ((Short)rhs).shortValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() <= ((Short)rhs).shortValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() > ((Short)rhs).shortValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Character)lhs).charValue() >= ((Short)rhs).shortValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/DoubleByteOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Double and rhs of Byte.
+ */
+public class DoubleByteOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() + ((Byte)rhs).byteValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() - ((Byte)rhs).byteValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() * ((Byte)rhs).byteValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() / ((Byte)rhs).byteValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() % ((Byte)rhs).byteValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() == ((Byte)rhs).byteValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() < ((Byte)rhs).byteValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() <= ((Byte)rhs).byteValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() > ((Byte)rhs).byteValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() >= ((Byte)rhs).byteValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/DoubleCharacterOps.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Double and rhs of Character.
+ */
+public class DoubleCharacterOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() + ((Character)rhs).charValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() - ((Character)rhs).charValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() * ((Character)rhs).charValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() / ((Character)rhs).charValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() % ((Character)rhs).charValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() == ((Character)rhs).charValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() < ((Character)rhs).charValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() <= ((Character)rhs).charValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() > ((Character)rhs).charValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() >= ((Character)rhs).charValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/DoubleDoubleOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Double and rhs of Double.
+ */
+public class DoubleDoubleOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() + ((Double)rhs).doubleValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() - ((Double)rhs).doubleValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() * ((Double)rhs).doubleValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() / ((Double)rhs).doubleValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() % ((Double)rhs).doubleValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() == ((Double)rhs).doubleValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() < ((Double)rhs).doubleValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() <= ((Double)rhs).doubleValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() > ((Double)rhs).doubleValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() >= ((Double)rhs).doubleValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/DoubleFloatOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Double and rhs of Float.
+ */
+public class DoubleFloatOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() + ((Float)rhs).floatValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() - ((Float)rhs).floatValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() * ((Float)rhs).floatValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() / ((Float)rhs).floatValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() % ((Float)rhs).floatValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() == ((Float)rhs).floatValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() < ((Float)rhs).floatValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() <= ((Float)rhs).floatValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() > ((Float)rhs).floatValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() >= ((Float)rhs).floatValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/DoubleIntegerOps.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Double and rhs of Integer.
+ */
+public class DoubleIntegerOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() + ((Integer)rhs).intValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() - ((Integer)rhs).intValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() * ((Integer)rhs).intValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() / ((Integer)rhs).intValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() % ((Integer)rhs).intValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() == ((Integer)rhs).intValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() < ((Integer)rhs).intValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() <= ((Integer)rhs).intValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() > ((Integer)rhs).intValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() >= ((Integer)rhs).intValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/DoubleLongOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Double and rhs of Long.
+ */
+public class DoubleLongOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() + ((Long)rhs).longValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() - ((Long)rhs).longValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() * ((Long)rhs).longValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() / ((Long)rhs).longValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() % ((Long)rhs).longValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() == ((Long)rhs).longValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() < ((Long)rhs).longValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() <= ((Long)rhs).longValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() > ((Long)rhs).longValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() >= ((Long)rhs).longValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/DoubleOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,33 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.UnOps;
+
+/**
+ * Implements unary operations for Double.
+ */
+public class DoubleOps implements UnOps
+{
+ public Object plus (Object arg) {
+ return +((Double)arg).doubleValue();
+ }
+ public Object minus (Object arg) {
+ return -((Double)arg).doubleValue();
+ }
+ public Object increment (Object arg) {
+ double tmp = ((Double)arg).doubleValue();
+ return ++tmp;
+ }
+ public Object decrement (Object arg) {
+ double tmp = ((Double)arg).doubleValue();
+ return --tmp;
+ }
+ public Object bitComp (Object arg) {
+ throw new IllegalArgumentException("Bitwise complement illegal on
double");
+ }
+ public Object logicalComp (Object arg) {
+ throw new IllegalArgumentException("Logical complement illegal on
double");
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/DoubleShortOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Double and rhs of Short.
+ */
+public class DoubleShortOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() + ((Short)rhs).shortValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() - ((Short)rhs).shortValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() * ((Short)rhs).shortValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() / ((Short)rhs).shortValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() % ((Short)rhs).shortValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() == ((Short)rhs).shortValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() < ((Short)rhs).shortValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() <= ((Short)rhs).shortValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() > ((Short)rhs).shortValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Double)lhs).doubleValue() >= ((Short)rhs).shortValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/FloatByteOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Float and rhs of Byte.
+ */
+public class FloatByteOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() + ((Byte)rhs).byteValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() - ((Byte)rhs).byteValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() * ((Byte)rhs).byteValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() / ((Byte)rhs).byteValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() % ((Byte)rhs).byteValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() == ((Byte)rhs).byteValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() < ((Byte)rhs).byteValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() <= ((Byte)rhs).byteValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() > ((Byte)rhs).byteValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() >= ((Byte)rhs).byteValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/FloatCharacterOps.java Sat Nov
27 12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Float and rhs of Character.
+ */
+public class FloatCharacterOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() + ((Character)rhs).charValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() - ((Character)rhs).charValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() * ((Character)rhs).charValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() / ((Character)rhs).charValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() % ((Character)rhs).charValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() == ((Character)rhs).charValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() < ((Character)rhs).charValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() <= ((Character)rhs).charValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() > ((Character)rhs).charValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() >= ((Character)rhs).charValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/FloatDoubleOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Float and rhs of Double.
+ */
+public class FloatDoubleOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() + ((Double)rhs).doubleValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() - ((Double)rhs).doubleValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() * ((Double)rhs).doubleValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() / ((Double)rhs).doubleValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() % ((Double)rhs).doubleValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() == ((Double)rhs).doubleValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() < ((Double)rhs).doubleValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() <= ((Double)rhs).doubleValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() > ((Double)rhs).doubleValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() >= ((Double)rhs).doubleValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/FloatFloatOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Float and rhs of Float.
+ */
+public class FloatFloatOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() + ((Float)rhs).floatValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() - ((Float)rhs).floatValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() * ((Float)rhs).floatValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() / ((Float)rhs).floatValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() % ((Float)rhs).floatValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() == ((Float)rhs).floatValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() < ((Float)rhs).floatValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() <= ((Float)rhs).floatValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() > ((Float)rhs).floatValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() >= ((Float)rhs).floatValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/FloatIntegerOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Float and rhs of Integer.
+ */
+public class FloatIntegerOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() + ((Integer)rhs).intValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() - ((Integer)rhs).intValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() * ((Integer)rhs).intValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() / ((Integer)rhs).intValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() % ((Integer)rhs).intValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() == ((Integer)rhs).intValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() < ((Integer)rhs).intValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() <= ((Integer)rhs).intValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() > ((Integer)rhs).intValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() >= ((Integer)rhs).intValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/FloatLongOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Float and rhs of Long.
+ */
+public class FloatLongOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() + ((Long)rhs).longValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() - ((Long)rhs).longValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() * ((Long)rhs).longValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() / ((Long)rhs).longValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() % ((Long)rhs).longValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() == ((Long)rhs).longValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() < ((Long)rhs).longValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() <= ((Long)rhs).longValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() > ((Long)rhs).longValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() >= ((Long)rhs).longValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/FloatOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,33 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.UnOps;
+
+/**
+ * Implements unary operations for Float.
+ */
+public class FloatOps implements UnOps
+{
+ public Object plus (Object arg) {
+ return +((Float)arg).floatValue();
+ }
+ public Object minus (Object arg) {
+ return -((Float)arg).floatValue();
+ }
+ public Object increment (Object arg) {
+ float tmp = ((Float)arg).floatValue();
+ return ++tmp;
+ }
+ public Object decrement (Object arg) {
+ float tmp = ((Float)arg).floatValue();
+ return --tmp;
+ }
+ public Object bitComp (Object arg) {
+ throw new IllegalArgumentException("Bitwise complement illegal on
float");
+ }
+ public Object logicalComp (Object arg) {
+ throw new IllegalArgumentException("Logical complement illegal on
float");
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/FloatShortOps.java Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of Float and rhs of Short.
+ */
+public class FloatShortOps implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() + ((Short)rhs).shortValue();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() - ((Short)rhs).shortValue();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() * ((Short)rhs).shortValue();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() / ((Short)rhs).shortValue();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() % ((Short)rhs).shortValue();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() == ((Short)rhs).shortValue();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() < ((Short)rhs).shortValue();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() <= ((Short)rhs).shortValue();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() > ((Short)rhs).shortValue();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return ((Float)lhs).floatValue() >= ((Short)rhs).shortValue();
+ }
+}
=======================================
--- /dev/null
+++ /src/main/java/org/ductilej/runtime/ops/FloatingBinOps.tmpl Sat Nov 27
12:15:19 2010
@@ -0,0 +1,64 @@
+//
+// $Id$
+
+package org.ductilej.runtime.ops;
+
+import org.ductilej.runtime.BinOps;
+
+/**
+ * Implements binary operations for lhs of {LEFT} and rhs of {RIGHT}.
+ */
+public class {LEFT}{RIGHT}Ops implements BinOps
+{
+ public Object plus (Object lhs, Object rhs) {
+ return (({LEFT})lhs).{left}Value() + (({RIGHT})rhs).{right}Value();
+ }
+ public Object minus (Object lhs, Object rhs) {
+ return (({LEFT})lhs).{left}Value() - (({RIGHT})rhs).{right}Value();
+ }
+ public Object multiply (Object lhs, Object rhs) {
+ return (({LEFT})lhs).{left}Value() * (({RIGHT})rhs).{right}Value();
+ }
+ public Object divide (Object lhs, Object rhs) {
+ return (({LEFT})lhs).{left}Value() / (({RIGHT})rhs).{right}Value();
+ }
+ public Object remainder (Object lhs, Object rhs) {
+ return (({LEFT})lhs).{left}Value() % (({RIGHT})rhs).{right}Value();
+ }
+
+ public Object bitOr (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-or LEFT and RIGHT");
+ }
+ public Object bitAnd (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-and LEFT and RIGHT");
+ }
+ public Object bitXor (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot bitwise-xor LEFT and RIGHT");
+ }
+
+ public Object leftShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot left-shift LEFT and RIGHT");
+ }
+ public Object rightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot right-shift LEFT and RIGHT");
+ }
+ public Object unsignedRightShift (Object lhs, Object rhs) {
+ throw new RuntimeException("Cannot unsigned right-shift LEFT and
RIGHT");
+ }
+
+ public boolean equalTo (Object lhs, Object rhs) {
+ return (({LEFT})lhs).{left}Value() ==
(({RIGHT})rhs).{right}Value();
+ }
+ public boolean lessThan (Object lhs, Object rhs) {
+ return (({LEFT})lhs).{left}Value() < (({RIGHT})rhs).{right}Value();
+ }
+ public boolean lessThanEq (Object lhs, Object rhs) {
+ return (({LEFT})lhs).{left}Value() <=
(({RIGHT})rhs).{right}Value();
+ }
+ public boolean greaterThan (Object lhs, Object rhs) {
+ return (({LEFT})lhs).{left}Value() > (({RIGHT})rhs).{right}Value();
+ }
+ public boolean greaterThanEq (Object lhs, Object rhs) {
+ return (({LEFT})lhs).{left}Value() >=
(({RIGHT})rhs).{right}Value();
+ }
+}
=======================================
***Additional files exist in this changeset.***