internal static object Compile(TextReader rdr, string sourceDirectory, string sourceName, string relativePath)
{
if (CompilePathVar.deref() == null)
throw new InvalidOperationException("*compile-path* not set");
object eofVal = new object();
object form;
//string sourcePath = sourceDirectory == null ? sourceName : sourceDirectory + "\\" + sourceName;
string sourcePath = relativePath;
LineNumberingTextReader lntr = rdr as LineNumberingTextReader ?? new LineNumberingTextReader(rdr);
GenContext context = GenContext.CreateWithExternalAssembly(relativePath, ".dll", true);
GenContext evalContext = GenContext.CreateWithInternalAssembly("EvalForCompile", false);
Var.pushThreadBindings(RT.map(
SourcePathVar, sourcePath,
SourceVar, sourceName,
MethodVar, null,
LocalEnvVar, null,
LoopLocalsVar, null,
NextLocalNumVar, 0,
RT.CurrentNSVar, RT.CurrentNSVar.deref(),
//LINE_BEFORE, lntr.LineNumber,
//LINE_AFTER, lntr.LineNumber,
DocumentInfoVar, Expression.SymbolDocument(sourceName), // I hope this is enough
ConstantsVar, PersistentVector.EMPTY,
ConstantIdsVar, new IdentityHashMap(),
KeywordsVar, PersistentHashMap.EMPTY,
VarsVar, PersistentHashMap.EMPTY,
RT.UncheckedMathVar, RT.UncheckedMathVar.deref(),
RT.WarnOnReflectionVar, RT.WarnOnReflectionVar.deref(),
RT.DataReadersVar, RT.DataReadersVar.deref(),
//KEYWORD_CALLSITES, PersistentVector.EMPTY, // jvm doesn't do this, don't know why
//VAR_CALLSITES, EmptyVarCallSites(), // jvm doesn't do this, don't know why
//PROTOCOL_CALLSITES, PersistentVector.EMPTY, // jvm doesn't do this, don't know why
CompilerContextVar, context
));
try
{
FnExpr objx = new FnExpr(null);
objx.InternalName = sourcePath.Replace(Path.PathSeparator, '/').Substring(0, sourcePath.LastIndexOf('.')) + "__init";
TypeBuilder exprTB = context.AssemblyGen.DefinePublicType("__REPL__", typeof(object), true);
//List<string> names = new List<string>();
List<Expr> exprs = new List<Expr>();
int i = 0;
while ((form = LispReader.read(lntr, false, eofVal, false)) != eofVal)
{
//Java version: LINE_AFTER.set(lntr.LineNumber);
Compile1(context, evalContext, exprTB, form, exprs, ref i);
//Java version: LINE_BEFORE.set(lntr.LineNumber);
}
exprTB.CreateType();
// Need to put the loader init in its own type because we can't generate calls on the MethodBuilders
// until after their types have been closed.
TypeBuilder initTB = context.AssemblyGen.DefinePublicType("__Init__", typeof(object), true);
Expression pushNSExpr = Expression.Call(null, Method_Compiler_PushNS);
Expression popExpr = Expression.Call(null, Method_Var_popThreadBindings);
BodyExpr bodyExpr = new BodyExpr(PersistentVector.create1(exprs));
FnMethod method = new FnMethod(objx, null, bodyExpr);
objx.AddMethod(method);
objx.Keywords = (IPersistentMap)KeywordsVar.deref();
objx.Vars = (IPersistentMap)VarsVar.deref();
objx.Constants = (PersistentVector)ConstantsVar.deref();
//objx.KeywordCallsites = (IPersistentVector)KEYWORD_CALLSITES.deref();
//objx.ProtocolCallsites = (IPersistentVector)PROTOCOL_CALLSITES.deref();
//objx.VarCallsites = (IPersistentSet)VAR_CALLSITES.deref();
objx.KeywordCallsites = PersistentVector.EMPTY;
objx.ProtocolCallsites = PersistentVector.EMPTY;
objx.VarCallsites = (IPersistentSet)EmptyVarCallSites();
objx.Compile(typeof(AFunction), null, PersistentVector.EMPTY, false, context);
Expression fnNew = objx.GenCode(RHC.Expression,objx,context);
Expression fnInvoke = Expression.Call(fnNew, fnNew.Type.GetMethod("invoke", System.Type.EmptyTypes));
Expression tryCatch = Expression.TryCatchFinally(fnInvoke, popExpr);
Expression body = Expression.Block(pushNSExpr, tryCatch);
// create initializer call
MethodBuilder mbInit = initTB.DefineMethod("Initialize", MethodAttributes.Public | MethodAttributes.Static);
LambdaExpression initFn = Expression.Lambda(body);
//initFn.CompileToMethod(mbInit, DebugInfoGenerator.CreatePdbGenerator());
initFn.CompileToMethod(mbInit, context.IsDebuggable);
initTB.CreateType();
context.SaveAssembly();
}
catch (LispReader.ReaderException e)
{
throw new CompilerException(sourcePath, e.Line, e.InnerException);
}
finally
{
Var.popThreadBindings();
}
return null;
}