summaryrefslogtreecommitdiff
path: root/tests/examplefiles/test.fan
diff options
context:
space:
mode:
authorIvan Inozemtsev <ivan.inozemtsev@xored.com>2012-02-05 16:44:21 +0700
committerIvan Inozemtsev <ivan.inozemtsev@xored.com>2012-02-05 16:44:21 +0700
commit7d9fd398089c674c839f8e095dee022b087cf19f (patch)
tree87d5b5cdfb4530f97ddd94f0a918b174fc99335c /tests/examplefiles/test.fan
parent5bec10613bea7da737b1549f08a1b943ab8d484f (diff)
downloadpygments-7d9fd398089c674c839f8e095dee022b087cf19f.tar.gz
added example file for fantom lexer
Diffstat (limited to 'tests/examplefiles/test.fan')
-rwxr-xr-xtests/examplefiles/test.fan818
1 files changed, 818 insertions, 0 deletions
diff --git a/tests/examplefiles/test.fan b/tests/examplefiles/test.fan
new file mode 100755
index 00000000..00e80b60
--- /dev/null
+++ b/tests/examplefiles/test.fan
@@ -0,0 +1,818 @@
+//
+// Copyright (c) 2008, Brian Frank and Andy Frank
+// Licensed under the Academic Free License version 3.0
+//
+// History:
+// 17 Nov 08 Brian Frank Creation
+//
+
+using compiler
+
+**
+** JavaBridge is the compiler plugin for bringing Java
+** classes into the Fantom type system.
+**
+class JavaBridge : CBridge
+{
+
+//////////////////////////////////////////////////////////////////////////
+// Constructor
+//////////////////////////////////////////////////////////////////////////
+
+ **
+ ** Construct a JavaBridge for current environment
+ **
+ new make(Compiler c, ClassPath cp := ClassPath.makeForCurrent)
+ : super(c)
+ {
+ this.cp = cp
+ }
+
+//////////////////////////////////////////////////////////////////////////
+// Namespace
+//////////////////////////////////////////////////////////////////////////
+
+ **
+ ** Map a FFI "podName" to a Java package.
+ **
+ override CPod resolvePod(Str name, Loc? loc)
+ {
+ // the empty package is used to represent primitives
+ if (name == "") return primitives
+
+ // look for package name in classpatch
+ classes := cp.classes[name]
+ if (classes == null)
+ throw CompilerErr("Java package '$name' not found", loc)
+
+ // map package to JavaPod
+ return JavaPod(this, name, classes)
+ }
+
+ **
+ ** Map class meta-data and Java members to Fantom slots
+ ** for the specified JavaType.
+ **
+ virtual Void loadType(JavaType type, Str:CSlot slots)
+ {
+ JavaReflect.loadType(type, slots)
+ }
+
+//////////////////////////////////////////////////////////////////////////
+// Call Resolution
+//////////////////////////////////////////////////////////////////////////
+
+ **
+ ** Resolve a construction call to a Java constructor.
+ **
+ override Expr resolveConstruction(CallExpr call)
+ {
+ // if the last argument is an it-block, then we know
+ // right away that we will not be passing it thru to Java,
+ // so strip it off to be appended as call to Obj.with
+ itBlock := call.args.last as ClosureExpr
+ if (itBlock != null && itBlock.isItBlock)
+ call.args.removeAt(-1)
+ else
+ itBlock = null
+
+ // if this is an interop array like IntArray/int[] use make
+ // factory otherwise look for Java constructor called <init>
+ JavaType base := call.target.ctype
+ if (base.isInteropArray)
+ call.method = base.method("make")
+ else
+ call.method = base.method("<init>")
+
+ // call resolution to deal with overloading
+ call = resolveCall(call)
+
+ // we need to create an implicit target for the Java runtime
+ // to perform the new opcode to ensure it is on the stack
+ // before the args (we don't do this for interop Array classes)
+ if (!base.isInteropArray)
+ {
+ loc := call.loc
+ call.target = CallExpr.makeWithMethod(loc, null, base.newMethod) { synthetic=true }
+ }
+
+ // if we stripped an it-block argument,
+ // add it as trailing call to Obj.with
+ if (itBlock != null) return itBlock.toWith(call)
+ return call
+ }
+
+ **
+ ** Resolve a construction chain call where a Fantom constructor
+ ** calls the super-class constructor. Type check the arguments
+ ** and insert any conversions needed.
+ **
+ override Expr resolveConstructorChain(CallExpr call)
+ {
+ // we don't allow chaining to a this ctor for Java FFI
+ if (call.target.id !== ExprId.superExpr)
+ throw err("Must use super constructor call in Java FFI", call.loc)
+
+ // route to a superclass constructor
+ JavaType base := call.target.ctype.deref
+ call.method = base.method("<init>")
+
+ // call resolution to deal with overloading
+ return resolveCall(call)
+ }
+
+ **
+ ** Given a dot operator slot access on the given foreign
+ ** base type, determine the appopriate slot to use based on
+ ** whether parens were used
+ ** base.name => noParens = true
+ ** base.name() => noParens = false
+ **
+ ** In Java a given name could be bound to both a field and
+ ** a method. In this case we only resolve the field if
+ ** no parens are used. We also handle the special case of
+ ** Java annotations here because their element methods are
+ ** also mapped as Fantom fields (instance based mixin field).
+ **
+ override CSlot? resolveSlotAccess(CType base, Str name, Bool noParens)
+ {
+ // first try to resolve as a field
+ field := base.field(name)
+ if (field != null)
+ {
+ // if no () we used and this isn't an annotation field
+ if (noParens && (field.isStatic || !base.isMixin))
+ return field
+
+ // if we did find a field, then make sure we use that
+ // field's parent type to resolve a method (becuase the
+ // base type might be a sub-class of a Java type in which
+ // case it is unware of field/method overloads)
+ return field.parent.method(name)
+ }
+
+ // lookup method
+ return base.method(name)
+ }
+
+ **
+ ** Resolve a method call: try to find the best match
+ ** and apply any coercions needed.
+ **
+ override CallExpr resolveCall(CallExpr call)
+ {
+ // try to match against all the overloaded methods
+ matches := CallMatch[,]
+ CMethod? m := call.method
+ while (m != null)
+ {
+ match := matchCall(call, m)
+ if (match != null) matches.add(match)
+ m = m is JavaMethod ? ((JavaMethod)m).next : null
+ }
+
+ // if we have exactly one match use then use that one
+ if (matches.size == 1) return matches[0].apply(call)
+
+ // if we have multiple matches; resolve to
+ // most specific match according to JLS rules
+ // TODO: this does not correct resolve when using Fantom implicit casting
+ if (matches.size > 1)
+ {
+ best := resolveMostSpecific(matches)
+ if (best != null) return best.apply(call)
+ }
+
+ // zero or multiple ambiguous matches is a compiler error
+ s := StrBuf()
+ s.add(matches.isEmpty ? "Invalid args " : "Ambiguous call ")
+ s.add(call.name).add("(")
+ s.add(call.args.join(", ") |Expr arg->Str| { return arg.toTypeStr })
+ s.add(")")
+ throw err(s.toStr, call.loc)
+ }
+
+ **
+ ** Check if the call matches the specified overload method.
+ ** If so return method and coerced args otherwise return null.
+ **
+ internal CallMatch? matchCall(CallExpr call, CMethod m)
+ {
+ // first check if have matching numbers of args and params
+ args := call.args
+ if (m.params.size < args.size) return null
+
+ // check if each argument is ok or can be coerced
+ isErr := false
+ newArgs := args.dup
+ m.params.each |CParam p, Int i|
+ {
+ if (i >= args.size)
+ {
+ // param has a default value, then that is ok
+ if (!p.hasDefault) isErr = true
+ }
+ else
+ {
+ // ensure arg fits parameter type (or auto-cast)
+ newArgs[i] = coerce(args[i], p.paramType) |->| { isErr = true }
+ }
+ }
+ if (isErr) return null
+ return CallMatch { it.method = m; it.args = newArgs }
+ }
+
+ **
+ ** Given a list of overloaed methods find the most specific method
+ ** according to Java Language Specification 15.11.2.2. The "informal
+ ** intuition" rule is that a method is more specific than another
+ ** if the first could be could be passed onto the second one.
+ **
+ internal static CallMatch? resolveMostSpecific(CallMatch[] matches)
+ {
+ CallMatch? best := matches[0]
+ for (i:=1; i<matches.size; ++i)
+ {
+ x := matches[i]
+ if (isMoreSpecific(best, x)) { continue }
+ if (isMoreSpecific(x, best)) { best = x; continue }
+ return null
+ }
+ return best
+ }
+
+ **
+ ** Is 'a' more specific than 'b' such that 'a' could be used
+ ** passed to 'b' without a compile time error.
+ **
+ internal static Bool isMoreSpecific(CallMatch a, CallMatch b)
+ {
+ return a.method.params.all |CParam ap, Int i->Bool|
+ {
+ bp := b.method.params[i]
+ return ap.paramType.fits(bp.paramType)
+ }
+ }
+
+//////////////////////////////////////////////////////////////////////////
+// Overrides
+//////////////////////////////////////////////////////////////////////////
+
+ **
+ ** Called during Inherit step when a Fantom slot overrides a FFI slot.
+ ** Log and throw compiler error if there is a problem.
+ **
+ override Void checkOverride(TypeDef t, CSlot base, SlotDef def)
+ {
+ // we don't allow Fantom to override Java methods with multiple
+ // overloaded versions since the Fantom type system can't actually
+ // override all the overloaded versions
+ jslot := base as JavaSlot
+ if (jslot?.next != null)
+ throw err("Cannot override Java overloaded method: '$jslot.name'", def.loc)
+
+ // route to method override checking
+ if (base is JavaMethod && def is MethodDef)
+ checkMethodOverride(t, base, def)
+ }
+
+ **
+ ** Called on method/method overrides in the checkOverride callback.
+ **
+ private Void checkMethodOverride(TypeDef t, JavaMethod base, MethodDef def)
+ {
+ // bail early if we know things aren't going to work out
+ if (base.params.size != def.params.size) return
+
+ // if the return type is primitive or Java array and the
+ // Fantom declaration matches how it is inferred into the Fan
+ // type system, then just change the return type - the compiler
+ // will impliclty do all the return coercions
+ if (isOverrideInferredType(base.returnType, def.returnType))
+ {
+ def.ret = def.inheritedRet = base.returnType
+ }
+
+ // if any of the parameters is a primitive or Java array
+ // and the Fantom declaration matches how it is inferred into
+ // the Fantom type type, then change the parameter type to
+ // the Java override type and make the Fantom type a local
+ // variable:
+ // Java: void foo(int a) { ... }
+ // Fantom: Void foo(Int a) { ... }
+ // Result: Void foo(int a_$J) { Int a := a_$J; ... }
+ //
+ base.params.eachr |CParam bp, Int i|
+ {
+ dp := def.paramDefs[i]
+ if (!isOverrideInferredType(bp.paramType, dp.paramType)) return
+
+ // add local variable: Int bar := bar_$J
+ local := LocalDefStmt(def.loc)
+ local.ctype = dp.paramType
+ local.name = dp.name
+ local.init = UnknownVarExpr(def.loc, null, dp.name + "_\$J")
+ def.code.stmts.insert(0, local)
+
+ // rename parameter Int bar -> int bar_$J
+ dp.name = dp.name + "_\$J"
+ dp.paramType = bp.paramType
+ }
+ }
+
+ **
+ ** When overriding a Java method check if the base type is
+ ** is a Java primitive or array and the override definition is
+ ** matches how the Java type is inferred in the Fantom type system.
+ ** If we have a match return true and we'll swizzle things in
+ ** checkMethodOverride.
+ **
+ static private Bool isOverrideInferredType(CType base, CType def)
+ {
+ // check if base class slot is a JavaType
+ java := base.toNonNullable as JavaType
+ if (java != null)
+ {
+ // allow primitives is it matches the inferred type
+ if (java.isPrimitive) return java.inferredAs == def
+
+ // allow arrays if mapped as Foo[] -> Foo?[]?
+ if (java.isArray) return java.inferredAs == def.toNonNullable && def.isNullable
+ }
+ return false
+ }
+
+//////////////////////////////////////////////////////////////////////////
+// CheckErrors
+//////////////////////////////////////////////////////////////////////////
+
+ **
+ ** Called during CheckErrors step for a type which extends
+ ** a FFI class or implements any FFI mixins.
+ **
+ override Void checkType(TypeDef def)
+ {
+ // can't subclass a primitive array like ByteArray/byte[]
+ if (def.base.deref is JavaType && def.base.deref->isInteropArray)
+ {
+ err("Cannot subclass from Java interop array: $def.base", def.loc)
+ return
+ }
+
+ // we don't allow deep inheritance of Java classes because
+ // the Fantom constructor and Java constructor model don't match
+ // up past one level of inheritance
+ // NOTE: that that when we remove this restriction we need to
+ // test how field initialization works because instance$init
+ // is almost certain to break with the current emit design
+ javaBase := def.base
+ while (javaBase != null && !javaBase.isForeign) javaBase = javaBase.base
+ if (javaBase != null && javaBase !== def.base)
+ {
+ err("Cannot subclass Java class more than one level: $javaBase", def.loc)
+ return
+ }
+
+ // ensure that when we map Fantom constructors to Java
+ // constructors that we don't have duplicate signatures
+ ctors := def.ctorDefs
+ ctors.each |MethodDef a, Int i|
+ {
+ ctors.each |MethodDef b, Int j|
+ {
+ if (i > j && areParamsSame(a, b))
+ err("Duplicate Java FFI constructor signatures: '$b.name' and '$a.name'", a.loc)
+ }
+ }
+ }
+
+ **
+ ** Do the two methods have the exact same parameter types.
+ **
+ static Bool areParamsSame(CMethod a, CMethod b)
+ {
+ if (a.params.size != b.params.size) return false
+ for (i:=0; i<a.params.size; ++i)
+ {
+ if (a.params[i].paramType != b.params[i].paramType)
+ return false
+ }
+ return true
+ }
+
+//////////////////////////////////////////////////////////////////////////
+// Coercion
+//////////////////////////////////////////////////////////////////////////
+
+ **
+ ** Return if we can make the actual type fit the expected
+ ** type, potentially using a coercion.
+ **
+ Bool fits(CType actual, CType expected)
+ {
+ // use dummy expression and route to coerce code
+ dummy := UnknownVarExpr(Loc("dummy"), null, "dummy") { ctype = actual }
+ fits := true
+ coerce(dummy, expected) |->| { fits=false }
+ return fits
+ }
+
+ **
+ ** Coerce expression to expected type. If not a type match
+ ** then run the onErr function.
+ **
+ override Expr coerce(Expr expr, CType expected, |->| onErr)
+ {
+ // handle easy case
+ actual := expr.ctype
+ expected = expected.deref
+ if (actual == expected) return expr
+
+ // handle null literal
+ if (expr.id === ExprId.nullLiteral && expected.isNullable)
+ return expr
+
+ // handle Fantom to Java primitives
+ if (expected.pod == primitives)
+ return coerceToPrimitive(expr, expected, onErr)
+
+ // handle Java primitives to Fan
+ if (actual.pod == primitives)
+ return coerceFromPrimitive(expr, expected, onErr)
+
+ // handle Java array to Fantom list
+ if (actual.name[0] == '[')
+ return coerceFromArray(expr, expected, onErr)
+
+ // handle Fantom list to Java array
+ if (expected.name[0] == '[')
+ return coerceToArray(expr, expected, onErr)
+
+ // handle sys::Func -> Java interface
+ if (actual is FuncType && expected.isMixin && expected.toNonNullable is JavaType)
+ return coerceFuncToInterface(expr, expected.toNonNullable, onErr)
+
+ // handle special classes and interfaces for built-in Fantom
+ // classes which actually map directly to Java built-in types
+ if (actual.isBool && boolTypes.contains(expected.toNonNullable.signature)) return box(expr)
+ if (actual.isInt && intTypes.contains(expected.toNonNullable.signature)) return box(expr)
+ if (actual.isFloat && floatTypes.contains(expected.toNonNullable.signature)) return box(expr)
+ if (actual.isDecimal && decimalTypes.contains(expected.toNonNullable.signature)) return expr
+ if (actual.isStr && strTypes.contains(expected.toNonNullable.signature)) return expr
+
+ // use normal Fantom coercion behavior
+ return super.coerce(expr, expected, onErr)
+ }
+
+ **
+ ** Ensure value type is boxed.
+ **
+ private Expr box(Expr expr)
+ {
+ if (expr.ctype.isVal)
+ return TypeCheckExpr.coerce(expr, expr.ctype.toNullable)
+ else
+ return expr
+ }
+
+ **
+ ** Coerce a fan expression to a Java primitive (other
+ ** than the ones we support natively)
+ **
+ Expr coerceToPrimitive(Expr expr, JavaType expected, |->| onErr)
+ {
+ actual := expr.ctype
+
+ // sys::Int (long) -> int, short, byte
+ if (actual.isInt && expected.isPrimitiveIntLike)
+ return TypeCheckExpr.coerce(expr, expected)
+
+ // sys::Float (double) -> float
+ if (actual.isFloat && expected.isPrimitiveFloat)
+ return TypeCheckExpr.coerce(expr, expected)
+
+ // no coercion - type error
+ onErr()
+ return expr
+ }
+
+ **
+ ** Coerce a Java primitive to a Fantom type.
+ **
+ Expr coerceFromPrimitive(Expr expr, CType expected, |->| onErr)
+ {
+ actual := (JavaType)expr.ctype
+
+ // int, short, byte -> sys::Int (long)
+ if (actual.isPrimitiveIntLike)
+ {
+ if (expected.isInt || expected.isObj)
+ return TypeCheckExpr.coerce(expr, expected)
+ }
+
+ // float -> sys::Float (float)
+ if (actual.isPrimitiveFloat)
+ {
+ if (expected.isFloat || expected.isObj)
+ return TypeCheckExpr.coerce(expr, expected)
+ }
+
+ // no coercion - type error
+ onErr()
+ return expr
+ }
+
+ **
+ ** Coerce a Java array to a Fantom list.
+ **
+ Expr coerceFromArray(Expr expr, CType expected, |->| onErr)
+ {
+ actual := (JavaType)expr.ctype.toNonNullable
+
+ // if expected is array type
+ if (expected is JavaType && ((JavaType)expected).isArray)
+ if (actual.arrayOf.fits(((JavaType)expected).arrayOf)) return expr
+
+ // if expected is Obj
+ if (expected.isObj) return arrayToList(expr, actual.inferredArrayOf)
+
+ // if expected is list type
+ if (expected.toNonNullable is ListType)
+ {
+ expectedOf := ((ListType)expected.toNonNullable).v
+ if (actual.inferredArrayOf.fits(expectedOf)) return arrayToList(expr, expectedOf)
+ }
+
+ // no coercion available
+ onErr()
+ return expr
+ }
+
+ **
+ ** Generate List.make(of, expr) where expr is Object[]
+ **
+ private Expr arrayToList(Expr expr, CType of)
+ {
+ loc := expr.loc
+ ofExpr := LiteralExpr(loc, ExprId.typeLiteral, ns.typeType, of)
+ call := CallExpr.makeWithMethod(loc, null, listMakeFromArray, [ofExpr, expr])
+ call.synthetic = true
+ return call
+ }
+
+ **
+ ** Coerce a Fantom list to Java array.
+ **
+ Expr coerceToArray(Expr expr, CType expected, |->| onErr)
+ {
+ loc := expr.loc
+ expectedOf := ((JavaType)expected.toNonNullable).inferredArrayOf
+ actual := expr.ctype
+
+ // if actual is list type
+ if (actual.toNonNullable is ListType)
+ {
+ actualOf := ((ListType)actual.toNonNullable).v
+ if (actualOf.fits(expectedOf))
+ {
+ // (Foo[])list.asArray(cls)
+ clsLiteral := CallExpr.makeWithMethod(loc, null, JavaType.classLiteral(this, expectedOf))
+ asArray := CallExpr.makeWithMethod(loc, expr, listAsArray, [clsLiteral])
+ return TypeCheckExpr.coerce(asArray, expected)
+ }
+ }
+
+ // no coercion available
+ onErr()
+ return expr
+ }
+
+ **
+ ** Attempt to coerce a parameterized sys::Func expr to a Java
+ ** interface if the interface supports exactly one matching method.
+ **
+ Expr coerceFuncToInterface(Expr expr, JavaType expected, |->| onErr)
+ {
+ // check if we have exactly one abstract method in the expected type
+ loc := expr.loc
+ abstracts := expected.methods.findAll |CMethod m->Bool| { return m.isAbstract }
+ if (abstracts.size != 1) { onErr(); return expr }
+ method := abstracts.first
+
+ // check if we have a match
+ FuncType funcType := (FuncType)expr.ctype
+ if (!isFuncToInterfaceMatch(funcType, method)) { onErr(); return expr }
+
+ // check if we've already generated a wrapper for this combo
+ key := "${funcType.signature}+${method.qname}"
+ ctor := funcWrappers[key]
+ if (ctor == null)
+ {
+ ctor = generateFuncToInterfaceWrapper(expr.loc, funcType, expected, method)
+ funcWrappers[key] = ctor
+ }
+
+ // replace expr with FuncWrapperX(expr)
+ call := CallExpr.makeWithMethod(loc, null, ctor, [expr])
+ call.synthetic = true
+ return call
+ }
+
+ **
+ ** Return if the specified function type can be used to implement
+ ** the specified interface method.
+ **
+ Bool isFuncToInterfaceMatch(FuncType funcType, CMethod method)
+ {
+ // sanity check to map to callX method - can't handle more than 8 args
+ if (method.params.size > 8) return false
+
+ // check if method is match for function; first check is that
+ // method must supply all the arguments required by the function
+ if (funcType.params.size > method.params.size) return false
+
+ // check that func return type fits method return
+ retOk := method.returnType.isVoid || fits(funcType.ret, method.returnType)
+ if (!retOk) return false
+
+ // check all the method parameters fit the function parameters
+ paramsOk := funcType.params.all |CType f, Int i->Bool| { return fits(f, method.params[i].paramType) }
+ if (!paramsOk) return false
+
+ return true
+ }
+
+ **
+ ** Generate the wrapper which implements the specified expected interface
+ ** and overrides the specified method which calls the function.
+ **
+ CMethod generateFuncToInterfaceWrapper(Loc loc, FuncType funcType, CType expected, CMethod method)
+ {
+ // Fantom: func typed as |Str|
+ // Java: interface Foo { void bar(String) }
+ // Result: FuncWrapperX(func)
+ //
+ // class FuncWrapperX : Foo
+ // {
+ // new make(Func f) { _func = f }
+ // override Void bar(Str a) { _func.call(a) }
+ // Func _func
+ // }
+
+ // generate FuncWrapper class
+ name := "FuncWrapper" + funcWrappers.size
+ cls := TypeDef(ns, loc, compiler.types[0].unit, name, FConst.Internal + FConst.Synthetic)
+ cls.base = ns.objType
+ cls.mixins = [expected]
+ addTypeDef(cls)
+
+ // generate FuncWrapper._func field
+ field := FieldDef(loc, cls)
+ ((SlotDef)field).name = "_func"
+ ((DefNode)field).flags = FConst.Private + FConst.Storage + FConst.Synthetic
+ field.fieldType = funcType
+ cls.addSlot(field)
+
+ // generate FuncWrapper.make constructor
+ ctor := MethodDef(loc, cls, "make", FConst.Internal + FConst.Ctor + FConst.Synthetic)
+ ctor.ret = ns.voidType
+ ctor.paramDefs = [ParamDef(loc, funcType, "f")]
+ ctor.code = Block.make(loc)
+ ctor.code.stmts.add(BinaryExpr.makeAssign(
+ FieldExpr(loc, ThisExpr(loc), field),
+ UnknownVarExpr(loc, null, "f")).toStmt)
+ ctor.code.stmts.add(ReturnStmt.make(loc))
+ cls.addSlot(ctor)
+
+ // generate FuncWrapper override of abstract method
+ over := MethodDef(loc, cls, method.name, FConst.Public + FConst.Override + FConst.Synthetic)
+ over.ret = method.returnType
+ over.paramDefs = ParamDef[,]
+ over.code = Block.make(loc)
+ callArity := "call"
+ call := CallExpr.makeWithMethod(loc, FieldExpr(loc, ThisExpr(loc), field), funcType.method(callArity))
+ method.params.each |CParam param, Int i|
+ {
+ paramName := "p$i"
+ over.params.add(ParamDef(loc, param.paramType, paramName))
+ if (i < funcType.params.size)
+ call.args.add(UnknownVarExpr(loc, null, paramName))
+ }
+ if (method.returnType.isVoid)
+ over.code.stmts.add(call.toStmt).add(ReturnStmt(loc))
+ else
+ over.code.stmts.add(ReturnStmt(loc, call))
+ cls.addSlot(over)
+
+ // return the ctor which we use for coercion
+ return ctor
+ }
+
+//////////////////////////////////////////////////////////////////////////
+// Reflection
+//////////////////////////////////////////////////////////////////////////
+
+ **
+ ** Get a CMethod representation for 'List.make(Type, Object[])'
+ **
+ once CMethod listMakeFromArray()
+ {
+ return JavaMethod(
+ this.ns.listType,
+ "make",
+ FConst.Public + FConst.Static,
+ this.ns.listType.toNullable,
+ [
+ JavaParam("of", this.ns.typeType),
+ JavaParam("array", objectArrayType)
+ ])
+ }
+
+ **
+ ** Get a CMethod representation for 'Object[] List.asArray()'
+ **
+ once CMethod listAsArray()
+ {
+ return JavaMethod(
+ this.ns.listType,
+ "asArray",
+ FConst.Public,
+ objectArrayType,
+ [JavaParam("cls", classType)])
+ }
+
+ **
+ ** Get a CType representation for 'java.lang.Class'
+ **
+ once JavaType classType()
+ {
+ return ns.resolveType("[java]java.lang::Class")
+ }
+
+ **
+ ** Get a CType representation for 'java.lang.Object[]'
+ **
+ once JavaType objectArrayType()
+ {
+ return ns.resolveType("[java]java.lang::[Object")
+ }
+
+//////////////////////////////////////////////////////////////////////////
+// Fields
+//////////////////////////////////////////////////////////////////////////
+
+ const static Str[] boolTypes := Str[
+ "[java]java.io::Serializable",
+ "[java]java.lang::Comparable",
+ ]
+
+ const static Str[] intTypes := Str[
+ "[java]java.lang::Number",
+ "[java]java.io::Serializable",
+ "[java]java.lang::Comparable",
+ ]
+
+ const static Str[] floatTypes := Str[
+ "[java]java.lang::Number",
+ "[java]java.io::Serializable",
+ "[java]java.lang::Comparable",
+ ]
+
+ const static Str[] decimalTypes := Str[
+ "[java]java.lang::Number",
+ "[java]java.io::Serializable",
+ "[java]java.lang::Comparable",
+ ]
+
+ const static Str[] strTypes := Str[
+ "[java]java.io::Serializable",
+ "[java]java.lang::CharSequence",
+ "[java]java.lang::Comparable",
+ ]
+
+ JavaPrimitives primitives := JavaPrimitives(this)
+ ClassPath cp
+
+ private Str:CMethod funcWrappers := Str:CMethod[:] // funcType+method:ctor
+
+}
+
+**************************************************************************
+** CallMatch
+**************************************************************************
+
+internal class CallMatch
+{
+ CallExpr apply(CallExpr call)
+ {
+ call.args = args
+ call.method = method
+ call.ctype = method.isCtor ? method.parent : method.returnType
+ return call
+ }
+
+ override Str toStr() { return method.signature }
+
+ CMethod? method // matched method
+ Expr[]? args // coerced arguments
+} \ No newline at end of file