public static Expr Parse(ParserContext pcon, ISeq form, string name)
{
ISeq origForm = form;
FnExpr fn = new FnExpr(Compiler.TagOf(form));
fn._src = form;
if (((IMeta)form.first()).meta() != null)
{
fn._onceOnly = RT.booleanCast(RT.get(RT.meta(form.first()), KW_ONCE));
}
fn.ComputeNames(form, name);
// Java: fn.objtype = Type.getObjectType(fn.internalName) -- makes no sense for us, this is ASM only.
List<string> prims = new List<string>();
try
{
Var.pushThreadBindings(RT.map(
Compiler.CONSTANTS, PersistentVector.EMPTY,
Compiler.CONSTANT_IDS, new IdentityHashMap(),
Compiler.KEYWORDS, PersistentHashMap.EMPTY,
Compiler.VARS, PersistentHashMap.EMPTY,
Compiler.KEYWORD_CALLSITES,PersistentVector.EMPTY,
Compiler.PROTOCOL_CALLSITES,PersistentVector.EMPTY,
Compiler.VAR_CALLSITES,Compiler.EmptyVarCallSites(),
Compiler.NO_RECUR,null));
//arglist might be preceded by symbol naming this fn
if (RT.second(form) is Symbol)
{
Symbol nm = (Symbol)RT.second(form);
fn._thisName = nm.Name;
fn.IsStatic = false; // RT.booleanCast(RT.get(nm.meta(), Compiler.STATIC_KEY));
form = RT.cons(Compiler.FN, RT.next(RT.next(form)));
}
// Normalize body
//now (fn [args] body...) or (fn ([args] body...) ([args2] body2...) ...)
//turn former into latter
if (RT.second(form) is IPersistentVector)
form = RT.list(Compiler.FN, RT.next(form));
SortedDictionary<int, FnMethod> methods = new SortedDictionary<int, FnMethod>();
FnMethod variadicMethod = null;
for (ISeq s = RT.next(form); s != null; s = RT.next(s))
{
FnMethod f = FnMethod.Parse(fn, (ISeq)RT.first(s),fn.IsStatic);
if (f.IsVariadic)
{
if (variadicMethod == null)
variadicMethod = f;
else
throw new Exception("Can't have more than 1 variadic overload");
}
else if (!methods.ContainsKey(f.RequiredArity))
methods[f.RequiredArity] = f;
else
throw new Exception("Can't have 2 overloads with the same arity.");
if (f.Prim != null)
prims.Add(f.Prim);
}
if (variadicMethod != null && methods.Count > 0 && methods.Keys.Max() >= variadicMethod.NumParams)
throw new Exception("Can't have fixed arity methods with more params than the variadic method.");
if ( fn.IsStatic && fn.Closes.count() > 0 )
throw new ArgumentException("static fns can't be closures");
IPersistentCollection allMethods = null;
foreach (FnMethod method in methods.Values)
allMethods = RT.conj(allMethods, method);
if (variadicMethod != null)
allMethods = RT.conj(allMethods, variadicMethod);
fn._methods = allMethods;
fn._variadicMethod = variadicMethod;
fn.Keywords = (IPersistentMap)Compiler.KEYWORDS.deref();
fn.Vars = (IPersistentMap)Compiler.VARS.deref();
fn.Constants = (PersistentVector)Compiler.CONSTANTS.deref();
fn.KeywordCallsites = (IPersistentVector)Compiler.KEYWORD_CALLSITES.deref();
fn.ProtocolCallsites = (IPersistentVector)Compiler.PROTOCOL_CALLSITES.deref();
fn.VarCallsites = (IPersistentSet)Compiler.VAR_CALLSITES.deref();
fn._constantsID = RT.nextID();
}
finally
{
Var.popThreadBindings();
}
IPersistentMap fmeta = RT.meta(origForm);
if (fmeta != null)
fmeta = fmeta.without(RT.LINE_KEY).without(RT.FILE_KEY);
fn._hasMeta = RT.count(fmeta) > 0;
if (Compiler.IsCompiling || prims.Count > 0)
{
GenContext context = Compiler.COMPILER_CONTEXT.get() as GenContext ?? Compiler.EvalContext;
GenContext genC = context.WithNewDynInitHelper(fn.InternalName + "__dynInitHelper_" + RT.nextID().ToString());
IPersistentVector primTypes = PersistentVector.EMPTY;
foreach (string typename in prims)
primTypes = primTypes.cons(Type.GetType(typename));
fn.Compile(
fn.IsVariadic ? typeof(RestFn) : typeof(AFunction),
null,
primTypes,
fn.OnceOnly,
genC);
}
else
{
fn.CompiledType = fn.GetPrecompiledType();
fn.FnMode = FnMode.Light;
}
if (fn.SupportsMeta)
return new MetaExpr(fn, MapExpr.Parse(pcon.EvEx(),fmeta));
else
return fn;
}