private Parse ( |
||
objx | ||
form | ISeq | |
thisTag | Symbol | |
overrideables | Dictionary |
|
explicits | Dictionary |
|
Результат |
public static NewInstanceMethod Parse(ObjExpr objx, ISeq form, Symbol thisTag, Dictionary<IPersistentVector, IList<MethodInfo>> overrideables, Dictionary<IPersistentVector, IList<MethodInfo>> explicits)
{
// (methodname [this-name args*] body...)
// this-name might be nil
NewInstanceMethod method = new NewInstanceMethod(objx, (ObjMethod)Compiler.MethodVar.deref());
Symbol dotName = (Symbol)RT.first(form);
Symbol name;
string methodName;
int idx = dotName.Name.LastIndexOf(".");
if (idx >= 0)
{
// we have an explicit interface implementation
string dotNameStr = dotName.Name;
string interfaceName = dotNameStr.Substring(0, idx);
method.ExplicitInterface = RT.classForName(interfaceName);
if (method.ExplicitInterface == null)
throw new ParseException(String.Format("Unable to find interface {0} for explicit method implemntation: {1}", interfaceName, dotNameStr));
methodName = dotNameStr.Substring(idx + 1);
name = (Symbol)Symbol.intern(null, Compiler.munge(dotName.Name)).withMeta(RT.meta(dotName));
}
else
{
name = (Symbol)Symbol.intern(null, Compiler.munge(dotName.Name)).withMeta(RT.meta(dotName));
methodName = name.Name;
}
IPersistentVector parms = (IPersistentVector)RT.second(form);
if (parms.count() == 0 || !(parms.nth(0) is Symbol))
throw new ParseException("Must supply at least one argument for 'this' in: " + dotName);
Symbol thisName = (Symbol)parms.nth(0);
parms = RT.subvec(parms, 1, parms.count());
ISeq body = RT.next(RT.next(form));
try
{
method.SpanMap = (IPersistentMap)Compiler.SourceSpanVar.deref();
// register as the current method and set up a new env frame
// PathNode pnade = new PathNode(PATHTYPE.PATH, (PathNode) CLEAR_PATH.get());
Var.pushThreadBindings(
RT.mapUniqueKeys(
Compiler.MethodVar, method,
Compiler.LocalEnvVar, Compiler.LocalEnvVar.deref(),
Compiler.LoopLocalsVar, null,
Compiler.NextLocalNumVar, 0
// CLEAR_PATH, pnode,
// CLEAR_ROOT, pnode,
// CLEAR_SITES, PersistentHashMap.EMPTY
));
// register 'this' as local 0
//method._thisBinding = Compiler.RegisterLocalThis(((thisName == null) ? dummyThis : thisName), thisTag, null);
Compiler.RegisterLocalThis(((thisName == null) ? dummyThis : thisName), thisTag, null);
IPersistentVector argLocals = PersistentVector.EMPTY;
method._retType = Compiler.TagType(Compiler.TagOf(name));
method._argTypes = new Type[parms.count()];
bool hinted = Compiler.TagOf(name) != null;
Type[] pTypes = new Type[parms.count()];
Symbol[] pSyms = new Symbol[parms.count()];
bool[] pRefs = new bool[parms.count()];
for (int i = 0; i < parms.count(); i++)
{
// Param should be symbol or (by-ref symbol)
Symbol p;
bool isByRef = false;
object pobj = parms.nth(i);
if (pobj is Symbol)
p = (Symbol)pobj;
else if (pobj is ISeq)
{
ISeq pseq = (ISeq)pobj;
object first = RT.first(pseq);
object second = RT.second(pseq);
if (!(first is Symbol && ((Symbol)first).Equals(HostExpr.ByRefSym)))
throw new ParseException("First element in parameter pair must be by-ref");
if (!(second is Symbol))
throw new ParseException("Params must be Symbols");
isByRef = true;
p = (Symbol)second;
hinted = true;
}
else
throw new ParseException("Params must be Symbols or of the form (by-ref Symbol)");
object tag = Compiler.TagOf(p);
if (tag != null)
hinted = true;
if (p.Namespace != null)
p = Symbol.intern(p.Name);
Type pType = Compiler.TagType(tag);
if (isByRef)
pType = pType.MakeByRefType();
pTypes[i] = pType;
pSyms[i] = p;
pRefs[i] = isByRef;
}
Dictionary<IPersistentVector, IList<MethodInfo>> matches =
method.IsExplicit
? FindMethodsWithNameAndArity(method.ExplicitInterface, methodName, parms.count(), overrideables, explicits)
: FindMethodsWithNameAndArity(methodName, parms.count(), overrideables);
IPersistentVector mk = MSig(methodName, pTypes, method._retType);
IList<MethodInfo> ms = null;
if (matches.Count > 0 )
{
// multiple matches
if (matches.Count > 1)
{
// must be hinted and match one method
if (!hinted)
throw new ParseException("Must hint overloaded method: " + name.Name);
if (! matches.TryGetValue(mk,out ms) )
throw new ParseException("Can't find matching overloaded method: " + name.Name);
method._minfos = ms;
}
else // one match
{
// if hinted, validate match,
if (hinted)
{
if (!matches.TryGetValue(mk, out ms))
throw new ParseException("Can't find matching method: " + name.Name + ", leave off hints for auto match.");
method._minfos = ms;
//if (m.ReturnType != method._retType)
// throw new ArgumentException(String.Format("Mismatched return type: {0}, expected {1}, had: {2}",
// name.Name, m.ReturnType.Name, method._retType.Name));
}
else // adopt found method sig
{
using (var e = matches.GetEnumerator() )
{
e.MoveNext();
mk = e.Current.Key;
ms = e.Current.Value;
}
MethodInfo m = ms[0];
method._retType = m.ReturnType;
pTypes = Compiler.GetTypes(m.GetParameters());
method._minfos = ms;
}
}
}
else
throw new ParseException("Can't define method not in interfaces: " + name.Name);
if (method.IsExplicit)
method.ExplicitMethodInfo = ms[0];
// validate unique name + arity among additional methods
for (int i = 0; i < parms.count(); i++)
{
LocalBinding lb = Compiler.RegisterLocal(pSyms[i], null, new MethodParamExpr(pTypes[i]), pTypes[i], true, pRefs[i]);
argLocals = argLocals.assocN(i, lb);
method._argTypes[i] = pTypes[i];
}
Compiler.LoopLocalsVar.set(argLocals);
method._name = name.Name;
method.MethodMeta = GenInterface.ExtractAttributes(RT.meta(name));
method.Parms = parms;
method.ArgLocals = argLocals;
method.Body = (new BodyExpr.Parser()).Parse(new ParserContext(RHC.Return), body);
return method;
}
finally
{
Var.popThreadBindings();
}
}
internal static ObjExpr Build( IPersistentVector interfaceSyms, IPersistentVector fieldSyms, Symbol thisSym, string tagName, Symbol className, Symbol typeTag, ISeq methodForms, Object frm) { NewInstanceExpr ret = new NewInstanceExpr(null); ret._src = frm; ret._name = className.ToString(); ret._classMeta = GenInterface.ExtractAttributes(RT.meta(className)); ret.InternalName = ret._name; // ret.Name.Replace('.', '/'); // Java: ret.objtype = Type.getObjectType(ret.internalName); if (thisSym != null) { ret._thisName = thisSym.Name; } if (fieldSyms != null) { IPersistentMap fmap = PersistentHashMap.EMPTY; object[] closesvec = new object[2 * fieldSyms.count()]; for (int i = 0; i < fieldSyms.count(); i++) { Symbol sym = (Symbol)fieldSyms.nth(i); LocalBinding lb = new LocalBinding(-1, sym, null, new MethodParamExpr(Compiler.TagType(Compiler.TagOf(sym))), false, false, false); fmap = fmap.assoc(sym, lb); closesvec[i * 2] = lb; closesvec[i * 2 + 1] = lb; } // Java TODO: inject __meta et al into closes - when? // use array map to preserve ctor order ret.Closes = new PersistentArrayMap(closesvec); ret.Fields = fmap; for (int i = fieldSyms.count() - 1; i >= 0 && (((Symbol)fieldSyms.nth(i)).Name.Equals("__meta") || ((Symbol)fieldSyms.nth(i)).Name.Equals("__extmap")); --i) { ret._altCtorDrops++; } } // Java TODO: set up volatiles //ret._volatiles = PersistentHashSet.create(RT.seq(RT.get(ret._optionsMap, volatileKey))); IPersistentVector interfaces = PersistentVector.EMPTY; for (ISeq s = RT.seq(interfaceSyms); s != null; s = s.next()) { Type t = (Type)Compiler.Resolve((Symbol)s.first()); if (!t.IsInterface) { throw new ParseException("only interfaces are supported, had: " + t.Name); } interfaces = interfaces.cons(t); } Type superClass = typeof(Object); Dictionary <IPersistentVector, List <MethodInfo> > overrideables; GatherMethods(superClass, RT.seq(interfaces), out overrideables); ret._methodMap = overrideables; GenContext context = Compiler.IsCompiling ? Compiler.CompilerContextVar.get() as GenContext : (ret.IsDefType ? GenContext.CreateWithExternalAssembly("deftype" + RT.nextID().ToString(), ".dll", true) : (Compiler.CompilerContextVar.get() as GenContext ?? Compiler.EvalContext)); GenContext genC = context.WithNewDynInitHelper(ret.InternalName + "__dynInitHelper_" + RT.nextID().ToString()); Type stub = CompileStub(genC, superClass, ret, SeqToTypeArray(interfaces), frm); Symbol thisTag = Symbol.intern(null, stub.FullName); //Symbol stubTag = Symbol.intern(null,stub.FullName); //Symbol thisTag = Symbol.intern(null, tagName); try { Var.pushThreadBindings( RT.mapUniqueKeys( Compiler.ConstantsVar, PersistentVector.EMPTY, Compiler.ConstantIdsVar, new IdentityHashMap(), Compiler.KeywordsVar, PersistentHashMap.EMPTY, Compiler.VarsVar, PersistentHashMap.EMPTY, Compiler.KeywordCallsitesVar, PersistentVector.EMPTY, Compiler.ProtocolCallsitesVar, PersistentVector.EMPTY, Compiler.VarCallsitesVar, Compiler.EmptyVarCallSites(), Compiler.NoRecurVar, null, Compiler.CompilerContextVar, genC )); if (ret.IsDefType) { Var.pushThreadBindings( RT.mapUniqueKeys( Compiler.MethodVar, null, Compiler.LocalEnvVar, ret.Fields, Compiler.CompileStubSymVar, Symbol.intern(null, tagName), Compiler.CompileStubClassVar, stub )); ret._hintedFields = RT.subvec(fieldSyms, 0, fieldSyms.count() - ret._altCtorDrops); } // now (methodname [args] body)* ret.SpanMap = (IPersistentMap)Compiler.SourceSpanVar.deref(); IPersistentCollection methods = null; for (ISeq s = methodForms; s != null; s = RT.next(s)) { NewInstanceMethod m = NewInstanceMethod.Parse(ret, (ISeq)RT.first(s), thisTag, overrideables); methods = RT.conj(methods, m); } ret._methods = methods; ret.Keywords = (IPersistentMap)Compiler.KeywordsVar.deref(); ret.Vars = (IPersistentMap)Compiler.VarsVar.deref(); ret.Constants = (PersistentVector)Compiler.ConstantsVar.deref(); ret._constantsID = RT.nextID(); ret.KeywordCallsites = (IPersistentVector)Compiler.KeywordCallsitesVar.deref(); ret.ProtocolCallsites = (IPersistentVector)Compiler.ProtocolCallsitesVar.deref(); ret.VarCallsites = (IPersistentSet)Compiler.VarCallsitesVar.deref(); } finally { if (ret.IsDefType) { Var.popThreadBindings(); } Var.popThreadBindings(); } // TOD: Really, the first stub here should be 'superclass' but can't handle hostexprs nested in method bodies -- reify method compilation takes place before this sucker is compiled, so can't replace the call. // Might be able to flag stub classes and not try to convert, leading to a dynsite. //if (RT.CompileDLR) ret.Compile(stub, stub, interfaces, false, genC); //else // ret.CompileNoDlr(stub, stub, interfaces, false, genC); Compiler.RegisterDuplicateType(ret.CompiledType); return(ret); }