public MethodCompiler(TypeDefinitionCompiler parent, JST.NameSupply outerNameSupply, CST.MethodDef methodDef, MethodCompilationMode mode) { env = parent.Env; this.parent = parent; methEnv = parent.TyconEnv.AddSelfTypeBoundArguments().AddMethod(methodDef).AddSelfMethodBoundArguments(); messageCtxt = CST.MessageContextBuilders.Env(methEnv); this.mode = mode; this.outerNameSupply = outerNameSupply; var common = default(JST.NameSupply); switch (mode) { case MethodCompilationMode.SelfContained: common = outerNameSupply; // Will be bound by function passed to root's BindMethod rootId = common.GenSym(); assemblyId = common.GenSym(); typeDefinitionId = common.GenSym(); break; case MethodCompilationMode.DirectBind: common = outerNameSupply.Fork(); // Already bound rootId = parent.RootId; assemblyId = parent.AssemblyId; typeDefinitionId = parent.TypeDefinitionId; break; default: throw new ArgumentOutOfRangeException("mode"); } nameSupply = common.Fork(); simpNameSupply = common.Fork(); }
public BBLoop(BasicBlock head, BasicBlock tail, IMSet<BasicBlock> body, JST.Identifier label) { Head = head; Tail = tail; Body = body; Label = label; var headEscapes = false; var headbranchbb = head as BranchBasicBlock; foreach (var t in head.Targets) { if (!body.Contains(t)) headEscapes = true; } var tailEscapes = false; var tailbranchbb = tail as BranchBasicBlock; foreach (var t in tail.Targets) { if (!body.Contains(t)) tailEscapes = true; } if (!headEscapes && tailEscapes && tailbranchbb != null) { if (tailbranchbb.Target.Equals(head)) Flavor = LoopFlavor.DoWhile; else if (tailbranchbb.Fallthrough.Equals(head)) Flavor = LoopFlavor.FlippedDoWhile; else throw new InvalidOperationException("invalid loop"); } else if (headEscapes && !tailEscapes && headbranchbb != null) { if (body.Contains(headbranchbb.Target)) Flavor = LoopFlavor.WhileDo; else if (body.Contains(headbranchbb.Fallthrough)) Flavor = LoopFlavor.FlippedWhileDo; else throw new InvalidOperationException("invalid loop"); } else if (!headEscapes && !tailEscapes) Flavor = LoopFlavor.Loop; else if (headEscapes && tailEscapes && headbranchbb != null && tailbranchbb != null) { // Could encode as do-while with a break at start, or while-do with a break at end. if (body.Contains(headbranchbb.Target)) Flavor = LoopFlavor.WhileDo; else if (body.Contains(headbranchbb.Fallthrough)) Flavor = LoopFlavor.FlippedWhileDo; else throw new InvalidOperationException("invalid loop"); } else Flavor = LoopFlavor.Unknown; }
public SimplifierContext (CompilationEnvironment compEnv, JST.NameSupply nameSupply, ISimplifierDatabase database, CSTWriter trace) { CompEnv = compEnv; NameSupply = nameSupply; subst = new Map<JST.Identifier, Expression>(); statements = null; contextEffects = JST.Effects.Bottom; Database = database; Trace = trace; }
protected SimplifierContext (CompilationEnvironment compEnv, JST.NameSupply nameSupply, Map<JST.Identifier, Expression> subst, Seq<Statement> statements, JST.Effects contextEffects, ISimplifierDatabase database, CSTWriter trace) { CompEnv = compEnv; NameSupply = nameSupply; this.subst = subst; this.statements = statements; this.contextEffects = contextEffects; Database = database; Trace = trace; }
public static CSTMethod Translate(MethodEnvironment methEnv, JST.NameSupply nameSupply, CSTWriter trace) { // Infer machine states for each control point var machineStateInference = new MachineStateInference(methEnv, trace); machineStateInference.Infer(); if (trace != null) trace.Trace ("After machine state inference", w => { methEnv.Method.AppendDefinition(w); w.EndLine(); }); // Translate to basic-blocks which use structural control flow where possible var controlFlowRecovery = new ControlFlowRecovery(methEnv, nameSupply.GenSym, -1, trace); var root = controlFlowRecovery.Root(); if (trace != null) trace.Trace ("After control flow recovery", w => { root.AppendAll(w); w.EndLine(); }); var initState = root.Targets[0].Block.BeforeState; var compEnv = methEnv.AddVariables(nameSupply, i => initState.ArgLocalIsAlive(ArgLocal.Local, i)); // Translate to intermediate statements/expressions/cells language var translator = new Translator (compEnv, nameSupply, controlFlowRecovery.NextInstructionId, trace); var body = translator.Translate(root); var res = new CSTMethod(compEnv, body); if (trace != null) trace.Trace("After translation to intermediate representation", res.Append); return res; }
public JST.Identifier FreshenArgument(JST.Identifier id, TypeRef type) { var newid = NameSupply.GenSym(); var cell = new VariableCell(newid); Bind(id, cell.Read()); CompEnv.AddVariable(newid, ArgLocal.Local, true, true, type); return newid; }
private JST.Statement WithLineCounts(JST.Statement statement, Func<int> nextLine, int currDepth, Set<JST.Identifier> lineCountIds) { if (statement.Flavor == JST.StatementFlavor.Try) { var trys = (JST.TryStatement)statement; if (trys.Catch != null) { var tryBody = WithLineCounts(trys.Body, nextLine, currDepth + 1, lineCountIds); var catchBody = new Seq<JST.Statement>(); var saveid = new JST.Identifier(Constants.DebugCurrentLine.Value + "_" + currDepth); lineCountIds.Add(saveid); catchBody.Add(JST.Statement.Assignment(saveid.ToE(), Constants.DebugCurrentLine.ToE())); foreach (var s in WithLineCounts(trys.Catch.Body, nextLine, currDepth + 1, lineCountIds).Body) catchBody.Add(s); var catchClause = new JST.CatchClause(trys.Catch.Loc, trys.Catch.Name, new JST.Statements(catchBody)); var finallyClause = default(JST.FinallyClause); if (trys.Finally != null) finallyClause = new JST.FinallyClause (trys.Finally.Loc, WithLineCounts(trys.Finally.Body, nextLine, currDepth + 1, lineCountIds)); return new JST.TryStatement(trys.Loc, tryBody, catchClause, finallyClause); } // else: fall-through } // else: fall-through return statement.CloneWithSubStatementss (statement.SubStatementss.Select(ss => WithLineCounts(ss, nextLine, currDepth, lineCountIds)).ToSeq()); }
private bool IsValue(JST.Expression expr) { var path = JST.Expression.ExplodePath(expr); if (path == null || path.Count == 0) return false; var id = path[0].ToIdentifier(); if (id == null) return false; return id.Equals(rootId) || id.Equals(assemblyId); }
private void CheckScriptArity(MessageContext ctxt, CCI.Method methodDefn, JST.Expression script, int n) { var funcScript = script as JST.FunctionExpression; if (funcScript != null) { if (funcScript.Parameters.Count != n) { env.Log(new InvalidInteropMessage(RewriterMsgContext.Method(ctxt, methodDefn), "invalid function arity")); throw new DefinitionException(); } } }
public ImportMethodInfo ImportInfo(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn) { if (!IsImported(ctxt, methodDefn)) return null; if (gensym != null) CheckParameterAndReturnTypesAreImportableExportable(ctxt, methodDefn); var methodArity = Arity(methodDefn); var script = interopTypes.GetValue(ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheScriptProperty); if (methodDefn is CCI.InstanceInitializer) { // XREF1171 // Constructor if (script == null) { switch ( interopTypes.GetValue (ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheCreationProperty)) { case Creation.Constructor: script = PrefixName(ctxt, methodDefn, null, false); break; case Creation.Object: if (methodArity > 0) { env.Log(new InvalidInteropMessage (RewriterMsgContext.Method(ctxt, methodDefn), "imported constructors for object literals cannot have arguments")); throw new DefinitionException(); } script = Constants.Object.ToE(); break; case Creation.Array: script = Constants.Array.ToE(); break; default: throw new ArgumentOutOfRangeException(); } return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, true); } else if (script is JST.FunctionExpression) return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false); else { script = PrefixName(ctxt, methodDefn, script, false); return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, true); } } else { if (methodDefn.DeclaringMember != null) { var isOnMethod = interopTypes.HasAttribute(methodDefn, env.ImportAttributeType, false); var localScript = isOnMethod ? interopTypes.GetValue(ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheScriptProperty, false) : default(JST.Expression); var prop = methodDefn.DeclaringMember as CCI.Property; if (prop != null) { // XREF1187 if (methodDefn == prop.Getter) { // Getter if (isOnMethod) { script = PrefixName (ctxt, methodDefn, GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "get", localScript), false); return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false); } else if (script != null && script is JST.FunctionExpression) { env.Log(new InvalidInteropMessage (RewriterMsgContext.Method(ctxt, methodDefn), "property import script cannot be a function")); throw new DefinitionException(); } else { var function = default(JST.FunctionExpression); if (gensym != null) { var parameters = new Seq<JST.Identifier>(); var body = new Seq<JST.Statement>(); for (var i = 0; i < methodArity; i++) parameters.Add(gensym()); if (script == null && methodArity == 2 && !methodDefn.IsStatic) body.Add (new JST.ReturnStatement (new JST.IndexExpression (parameters[0].ToE(), parameters[1].ToE()))); else { script = PrefixName (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false); if (methodDefn.IsStatic && methodArity == 0) body.Add(new JST.ReturnStatement(script)); else if (!methodDefn.IsStatic && methodArity == 1) body.Add (new JST.ReturnStatement (JST.Expression.Dot (parameters[0].ToE(), JST.Expression.ExplodePath(script)))); else { env.Log(new InvalidInteropMessage (RewriterMsgContext.Method(ctxt, methodDefn), "additional getter parameters not supported for default getters")); throw new DefinitionException(); } } function = new JST.FunctionExpression(parameters, new JST.Statements(body)); } return new ImportMethodInfo { MethodDefn = methodDefn, Script = function }; } } else if (methodDefn == prop.Setter) { // Setter if (isOnMethod) { script = PrefixName (ctxt, methodDefn, GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "set", localScript), false); return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false); } else if (script != null && script is JST.FunctionExpression) { env.Log(new InvalidInteropMessage (RewriterMsgContext.Method(ctxt, methodDefn), "property import script cannot be a function")); throw new DefinitionException(); } else { var function = default(JST.FunctionExpression); if (gensym != null) { var parameters = new Seq<JST.Identifier>(); var body = new Seq<JST.Statement>(); for (var i = 0; i < methodArity; i++) parameters.Add(gensym()); if (script == null && methodArity == 3 && !methodDefn.IsStatic) body.Add (JST.Statement.IndexAssignment (parameters[0].ToE(), parameters[1].ToE(), parameters[2].ToE())); else { script = PrefixName (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false); if (methodDefn.IsStatic && methodArity == 1) body.Add (JST.Statement.Assignment(script, parameters[0].ToE())); else if (!methodDefn.IsStatic && methodArity == 2) body.Add (JST.Statement.Assignment (JST.Expression.Dot (parameters[0].ToE(), JST.Expression.ExplodePath(script)), parameters[1].ToE())); else { env.Log(new InvalidInteropMessage (RewriterMsgContext.Method(ctxt, methodDefn), "additional setter parameters not supported for default setters")); throw new DefinitionException(); } } function = new JST.FunctionExpression(parameters, new JST.Statements(body)); } return new ImportMethodInfo { MethodDefn = methodDefn, Script = function }; } } else throw new InvalidOperationException(); } else { var evnt = methodDefn.DeclaringMember as CCI.Event; if (evnt != null) { // XREF1201 if (methodDefn == evnt.HandlerAdder) { // Adder if (isOnMethod) { script = PrefixName (ctxt, methodDefn, GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "add", localScript), false); return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false); } else if (script != null && script is JST.FunctionExpression) { env.Log(new InvalidInteropMessage (RewriterMsgContext.Method(ctxt, methodDefn), "event import script cannot be a function")); throw new DefinitionException(); } else { var function = default(JST.FunctionExpression); if (gensym != null) { var parameters = new Seq<JST.Identifier>(); var body = new Seq<JST.Statement>(); for (var i = 0; i < methodArity; i++) parameters.Add(gensym()); script = PrefixName (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false); if (methodDefn.IsStatic) body.Add (JST.Statement.Assignment(script, parameters[0].ToE())); else body.Add (JST.Statement.Assignment (JST.Expression.Dot (parameters[0].ToE(), JST.Expression.ExplodePath(script)), parameters[1].ToE())); function = new JST.FunctionExpression(parameters, new JST.Statements(body)); } return new ImportMethodInfo { MethodDefn = methodDefn, Script = function }; } } else if (methodDefn == evnt.HandlerRemover) { // Remover if (isOnMethod) { script = PrefixName (ctxt, methodDefn, GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "remove", localScript), false); return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false); } else if (script != null && script is JST.FunctionExpression) { env.Log(new InvalidInteropMessage (RewriterMsgContext.Method(ctxt, methodDefn), "event import script cannot be a function")); throw new DefinitionException(); } else { var function = default(JST.FunctionExpression); if (gensym != null) { var parameters = new Seq<JST.Identifier>(); var body = new Seq<JST.Statement>(); for (var i = 0; i < methodArity; i++) parameters.Add(gensym()); script = PrefixName (ctxt, methodDefn, RecasePropertyEvent(ctxt, methodDefn, script), false); if (methodDefn.IsStatic) body.Add (JST.Statement.Assignment(script, parameters[0].ToE())); else body.Add (JST.Statement.Assignment (JST.Expression.Dot (parameters[0].ToE(), JST.Expression.ExplodePath(script)), parameters[1].ToE())); function = new JST.FunctionExpression(parameters, new JST.Statements(body)); } return new ImportMethodInfo { MethodDefn = methodDefn, Script = function }; } } else throw new InvalidOperationException(); } else throw new InvalidOperationException(); } } else { // XREF1153 // Normal method script = PrefixName(ctxt, methodDefn, RecaseMember(ctxt, methodDefn, script), false); return FinalImportScript(ctxt, gensym, rootId, methodDefn, script, false); } } }
private JST.Expression RecasePropertyEvent(MessageContext ctxt, CCI.Method method, JST.Expression script) { if (method.DeclaringMember == null) throw new ArgumentException("not a getter/setter/adder/remover method"); if (script != null) return script; var name = Recase (method.DeclaringMember.Name.Name, interopTypes.GetValue (ctxt, method, env.NamingAttributeType, interopTypes.TheMemberNameCasingProperty)); return new JST.Identifier(JST.Lexemes.StringToIdentifier(name)).ToE(); }
// Return the exported name for a getter/setter/adder/remover method based on the property/event name private JST.Expression GetterSetterAdderRemoverNameFromPropertyEvent(MessageContext ctxt, CCI.Method method, string prefix, JST.Expression script) { if (method.DeclaringMember == null) throw new ArgumentException("not a getter/setter/adder/remover method"); if (script != null && script is JST.FunctionExpression) throw new InvalidOperationException("not a path expression"); var names = default(ISeq<JST.PropertyName>); if (script == null) // Take the actual property/event name as a starting point names = JST.Expression.ExplodePath(RecasePropertyEvent(ctxt, method, null)); else // Take the user supplied property/event name as a starting point names = JST.Expression.ExplodePath(script); // Turn the property/event name into a getter/setter/adder/remover name var str = ""; if ( !interopTypes.GetValue (ctxt, method, env.NamingAttributeType, interopTypes.TheRemoveAccessorPrefixProperty)) { str += Recase (prefix, interopTypes.GetValue (ctxt, method, env.NamingAttributeType, interopTypes.ThePrefixNameCasingProperty)); if ( !interopTypes.GetValue (ctxt, method, env.NamingAttributeType, interopTypes.TheRemoveAccessorUnderscoreProperty)) str += "_"; } str += names[names.Count - 1].Value; names[names.Count - 1] = new JST.PropertyName(str); return JST.Expression.Path(names); }
public ExportMethodInfo ExportInfo(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn) { if (!IsExported(ctxt, methodDefn)) return null; if (TypeArity(methodDefn) > 0) { env.Log(new InvalidInteropMessage(RewriterMsgContext.Member(ctxt, methodDefn), "polymorphic methods cannot be exported")); throw new DefinitionException(); } if (TypeArity(methodDefn.DeclaringType) > 0 && (methodDefn is CCI.InstanceInitializer || methodDefn.IsStatic)) { env.Log(new InvalidInteropMessage(RewriterMsgContext.Member(ctxt, methodDefn), "non-instance methods of higher-kinded types cannot be exported")); throw new DefinitionException(); } if (gensym != null) CheckParameterAndReturnTypesAreImportableExportable(ctxt, methodDefn); var script = interopTypes.GetValue (ctxt, methodDefn, env.ExportAttributeType, interopTypes.TheScriptProperty); if (methodDefn is CCI.InstanceInitializer) { // XREF1181 // Constructors if (TypeArity(methodDefn) > 0) throw new InvalidOperationException("invalid constructor"); } else if (methodDefn.DeclaringMember != null) { var isOnMethod = interopTypes.HasAttribute(methodDefn, env.ExportAttributeType, false); var localScript = isOnMethod ? interopTypes.GetValue(ctxt, methodDefn, env.ExportAttributeType, interopTypes.TheScriptProperty, false) : default(JST.Expression); var prop = methodDefn.DeclaringMember as CCI.Property; if (prop != null) { // XREF1193 if (methodDefn == prop.Getter) // Getter script = isOnMethod ? GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "get", localScript) : GetterSetterAdderRemoverNameFromPropertyEvent(ctxt, methodDefn, "get", script); else if (methodDefn == prop.Setter) // Setter script = isOnMethod ? GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "set", localScript) : GetterSetterAdderRemoverNameFromPropertyEvent(ctxt, methodDefn, "set", script); else throw new InvalidOperationException(); } else { var evnt = methodDefn.DeclaringMember as CCI.Event; if (evnt != null) { // XREF1213 if (methodDefn == evnt.HandlerAdder) // Adder script = isOnMethod ? GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "add", localScript) : GetterSetterAdderRemoverNameFromPropertyEvent(ctxt, methodDefn, "add", script); else if (methodDefn == evnt.HandlerRemover) // Remover script = isOnMethod ? GetterSetterAdderRemoverNameFromMethod(ctxt, methodDefn, "remove", localScript) : GetterSetterAdderRemoverNameFromPropertyEvent(ctxt, methodDefn, "remove", script); else throw new InvalidOperationException(); } else throw new InvalidOperationException(); } } else { // XREF1163 // Normal methods script = RecaseMember(ctxt, methodDefn, script); } return FinalExportInfo(ctxt, gensym, rootId, methodDefn, PrefixName(ctxt, methodDefn, script, true)); }
// ---------------------------------------------------------------------- // Entry point from TypeCompiler // ---------------------------------------------------------------------- public void Emit(ISeq<JST.Statement> body, JST.Expression target) { if (env.BreakOnBreak && env.AttributeHelper.MethodHasAttribute(methEnv.Assembly, methEnv.Type, methEnv.Method, env.AttributeHelper.BreakAttributeRef, false, false)) System.Diagnostics.Debugger.Break(); var methodName = CST.CSTWriter.WithAppend(env.Global, CST.WriterStyle.Debug, methEnv.MethodRef.Append); var methodSlot = env.GlobalMapping.ResolveMethodDefToSlot(methEnv.Assembly, methEnv.Type, methEnv.Method); var method = Method(methodName); switch (mode) { case MethodCompilationMode.SelfContained: { if (target != null) throw new InvalidOperationException("not expecting target in self-contained mode"); var assmName = CST.CSTWriter.WithAppend (env.Global, CST.WriterStyle.Uniform, methEnv.Assembly.Name.Append); var typeSlot = env.GlobalMapping.ResolveTypeDefToSlot(methEnv.Assembly, methEnv.Type); var func = new JST.FunctionExpression (new Seq<JST.Identifier> { rootId, assemblyId, typeDefinitionId }, new JST.Statements(new JST.ReturnStatement(method))); var methodLoader = new Seq<JST.Statement>(); if (env.DebugMode) methodLoader.Add(new JST.CommentStatement(methodName)); methodLoader.Add (JST.Statement.DotCall (new JST.Identifier(env.Root).ToE(), Constants.RootBindMethod, new JST.StringLiteral(assmName), new JST.StringLiteral(typeSlot), new JST.BooleanLiteral(env.InteropManager.IsStatic(methEnv.Assembly, methEnv.Type, methEnv.Method)), new JST.StringLiteral(methodSlot), func)); var methodProgram = new JST.Program(new JST.Statements(methodLoader)); var methodFileName = Path.Combine (env.OutputDirectory, Path.Combine (JST.Lexemes.StringToFileName(assmName), Path.Combine(typeSlot, Path.Combine(methodSlot, Constants.MethodFileName)))); methodProgram.ToFile(methodFileName, env.PrettyPrint); env.Log(new GeneratedJavaScriptFile("method '" + methEnv.MethodRef + "'", methodFileName)); break; } case MethodCompilationMode.DirectBind: { if (target == null) throw new InvalidOperationException("expecting target in self-contained mode"); if (env.DebugMode) body.Add(new JST.CommentStatement(methodName)); body.Add (JST.Statement.Assignment(JST.Expression.Dot(target, new JST.Identifier(methodSlot)), method)); break; } default: throw new ArgumentOutOfRangeException(); } }
public void IncludeEffects(JST.Effects effects) { contextEffects = contextEffects.Lub(effects); }
private JST.Expression TranslateExpression(MethodCompilerEnvironment methCompEnv, ISeq<JST.Statement> optBody, JST.Expression optLvalue, bool ignoreResult, CST.Expression expr) { switch (expr.Flavor) { case CST.ExpressionFlavor.Null: return new JST.NullExpression(); case CST.ExpressionFlavor.TypeHandle: { // The type structure var the = (CST.TypeHandleConstantExpression)expr; return methCompEnv.ResolveType(the.RuntimeType); } case CST.ExpressionFlavor.FieldHandle: { // A System.Reflection.FieldInfo instance, via exported constructor var fhe = (CST.FieldHandleConstantExpression)expr; var fieldEnv = fhe.RuntimeField.Enter(methCompEnv); var slot = env.GlobalMapping.ResolveFieldDefToSlot (fieldEnv.Assembly, fieldEnv.Type, fieldEnv.Field); var fieldDefType = methCompEnv.ResolveType(fhe.RuntimeField.DefiningType); var fieldType = methCompEnv.ResolveType(fieldEnv.SubstituteType(fieldEnv.Field.FieldType)); var init = default(JST.Expression); var rawInit = fieldEnv.Field.Init as CST.RawFieldInit; if (rawInit != null) init = new JST.ArrayLiteral (rawInit.Data.Select(b => (JST.Expression)new JST.NumericLiteral(b)).ToSeq()); else init = new JST.NullExpression(); return JST.Expression.DotCall (rootId.ToE(), Constants.RootReflectionFieldInfo, new JST.StringLiteral(slot), fieldDefType, new JST.BooleanLiteral(fieldEnv.Field.IsStatic), new JST.BooleanLiteral(!fieldEnv.Field.IsStatic), new JST.StringLiteral(fieldEnv.Field.Name), new JST.NullExpression(), fieldType, init); } case CST.ExpressionFlavor.MethodHandle: { // A System.Reflection.MethodInfo instance, via exported constructor var mhe = (CST.MethodHandleConstantExpression)expr; var runtimeMethEnv = mhe.RuntimeMethod.Enter(methCompEnv); var slot = env.GlobalMapping.ResolveMethodDefToSlot (runtimeMethEnv.Assembly, runtimeMethEnv.Type, runtimeMethEnv.Method); var methodDef = runtimeMethEnv.Method; var methodDefType = methCompEnv.ResolveType(mhe.RuntimeMethod.DefiningType); var paramTypes = methodDef.ValueParameters.Where((t, i) => i > 0 || methodDef.IsStatic).Select (t => methCompEnv.ResolveType(runtimeMethEnv.SubstituteType(t.Type))).ToSeq(); var result = methodDef.Result == null ? null : methCompEnv.ResolveType(runtimeMethEnv.SubstituteType(methodDef.Result.Type)); var isStatic = env.InteropManager.IsStatic (runtimeMethEnv.Assembly, runtimeMethEnv.Type, runtimeMethEnv.Method); return JST.Expression.DotCall (rootId.ToE(), Constants.RootReflectionMethodInfo, new JST.StringLiteral(slot), methodDefType, new JST.BooleanLiteral(isStatic), new JST.BooleanLiteral(!isStatic), new JST.StringLiteral(methodDef.Name), new JST.NullExpression(), new JST.BooleanLiteral(runtimeMethEnv.Method.IsVirtualOrAbstract), new JST.ArrayLiteral(paramTypes), new JST.BooleanLiteral(true), result); } case CST.ExpressionFlavor.CodePointer: { // Produces a <codePtr> structure, which is only 'observable' by delegate constructors. // (We can't just produce the function itself because of issues with method slot updating // and delegate structural equality) var cpe = (CST.CodePointerExpression)expr; // If object is non-null then we assume the same object is passed to delegate constructor var isVirtual = cpe.Object != null; var bindings = new OrdMap<JST.Identifier, JST.Expression>(); if (cpe.Method.MethodTypeArguments.Count > 0) { var methodBoundTypeArgs = cpe.Method.MethodTypeArguments.Select(t => methCompEnv.ResolveType(t)).ToSeq(); bindings.Add(Constants.CodePtrArguments, new JST.ArrayLiteral(methodBoundTypeArgs)); } bindings.Add (Constants.CodePtrType, isVirtual ? new JST.NullExpression() : methCompEnv.ResolveType(cpe.Method.DefiningType)); bindings.Add (Constants.CodePtrArity, new JST.NumericLiteral(cpe.Method.ValueParameters.Count - (cpe.Method.IsStatic ? 0 : 1))); bindings.Add (Constants.CodePtrSlot, env.JSTHelpers.MethodSlotName(methCompEnv, cpe.Method, isVirtual)); return new JST.ObjectLiteral(bindings); } case CST.ExpressionFlavor.Int32: { var ie = (CST.Int32ConstantExpression)expr; return new JST.NumericLiteral(ie.Value); } case CST.ExpressionFlavor.Int64: { var ie = (CST.Int64ConstantExpression)expr; var n = (double)ie.Value; var o = (long)n; if (o != ie.Value) env.Log (new LossOfPrecisionMessage(CST.MessageContextBuilders.Expression(messageCtxt, expr), "int64 literal")); return new JST.NumericLiteral(n); } case CST.ExpressionFlavor.Single: { var se = (CST.SingleConstantExpression)expr; return new JST.NumericLiteral(se.Value); } case CST.ExpressionFlavor.Double: { var de = (CST.DoubleConstantExpression)expr; return new JST.NumericLiteral(de.Value); } case CST.ExpressionFlavor.String: { var se = (CST.StringConstantExpression)expr; return methCompEnv.ResolveString(se.Value); } case CST.ExpressionFlavor.Unary: { var ue = (CST.UnaryExpression)expr; if (ue.WithOverflow) env.Log (new LossOfPrecisionMessage (CST.MessageContextBuilders.Expression(messageCtxt, expr), "overflow detection")); if (ue.IsUnsigned) env.Log (new LossOfPrecisionMessage (CST.MessageContextBuilders.Expression(messageCtxt, expr), "unsigned arithmetic")); switch (ue.Op) { case CST.UnaryOp.CheckFinite: { var ve = TranslateExpression(methCompEnv, optBody, null, false, ue.Value); return JST.Expression.DotCall(rootId.ToE(), Constants.RootCheckFinite, ve); } case CST.UnaryOp.Length: { var ve = TranslateExpression(methCompEnv, optBody, null, false, ue.Value); return JST.Expression.Dot(ve, Constants.length); } case CST.UnaryOp.Neg: { var ve = TranslateExpression(methCompEnv, optBody, null, false, ue.Value); return new JST.UnaryExpression(JST.UnaryOp.UnaryMinus, ve); } case CST.UnaryOp.BitNot: { var ve = TranslateExpression(methCompEnv, optBody, null, false, ue.Value); return new JST.UnaryExpression(JST.UnaryOp.BitwiseNot, ve); } case CST.UnaryOp.LogNot: { var ve = TranslateConditionalExpression(methCompEnv, optBody, ue.Value); return new JST.UnaryExpression(JST.UnaryOp.LogicalNot, ve); } case CST.UnaryOp.IsZero: { var ve = TranslateConditionalExpression(methCompEnv, optBody, ue.Value); return new JST.UnaryExpression(JST.UnaryOp.LogicalNot, ve); } case CST.UnaryOp.IsNonZero: { var ve = TranslateConditionalExpression(methCompEnv, optBody, ue.Value); return ve; } case CST.UnaryOp.IsNull: { var ve = TranslateConditionalExpression(methCompEnv, optBody, ue.Value); return new JST.UnaryExpression(JST.UnaryOp.LogicalNot, ve); } case CST.UnaryOp.IsNonNull: { var ve = TranslateConditionalExpression(methCompEnv, optBody, ue.Value); // Must force result to be a boolean return new JST.UnaryExpression(JST.UnaryOp.LogicalNot, new JST.UnaryExpression(JST.UnaryOp.LogicalNot, ve)); } default: throw new ArgumentOutOfRangeException(); } } case CST.ExpressionFlavor.Binary: { var be = (CST.BinaryExpression)expr; if (be.WithOverflow) env.Log (new LossOfPrecisionMessage (CST.MessageContextBuilders.Expression(messageCtxt, expr), "overflow detection")); if (be.IsUnsigned && be.Op != CST.BinaryOp.Shr) env.Log (new LossOfPrecisionMessage (CST.MessageContextBuilders.Expression(messageCtxt, expr), "unsigned arithmetic")); if (be.Op == CST.BinaryOp.LogAnd) { var le = TranslateConditionalExpression(methCompEnv, optBody, be.LeftValue); // NOTE: Not safe to hoist side-effects into body since rhs may not be evaluated var re = TranslateConditionalExpression(methCompEnv, null, be.RightValue); return new JST.BinaryExpression(le, JST.BinaryOp.LogicalAND, re); } else if (be.Op == CST.BinaryOp.LogOr) { var le = TranslateConditionalExpression(methCompEnv, optBody, be.LeftValue); // NOTE: Not safe to hoist side-effects into body since rhs may not be evaluated var re = TranslateConditionalExpression(methCompEnv, null, be.RightValue); return new JST.BinaryExpression(le, JST.BinaryOp.LogicalOR, re); } else { var le = TranslateExpression(methCompEnv, optBody, null, false, be.LeftValue); var re = TranslateExpression(methCompEnv, optBody, null, false, be.RightValue); switch (be.Op) { case CST.BinaryOp.Eq: return new JST.BinaryExpression(le, JST.BinaryOp.Equals, re); case CST.BinaryOp.Ne: return new JST.BinaryExpression(le, JST.BinaryOp.NotEquals, re); case CST.BinaryOp.Lt: return new JST.BinaryExpression(le, JST.BinaryOp.LessThan, re); case CST.BinaryOp.Le: return new JST.BinaryExpression(le, JST.BinaryOp.LessThanOrEqual, re); case CST.BinaryOp.Gt: return new JST.BinaryExpression(le, JST.BinaryOp.GreaterThan, re); case CST.BinaryOp.Ge: return new JST.BinaryExpression(le, JST.BinaryOp.GreaterThanOrEqual, re); case CST.BinaryOp.Add: return new JST.BinaryExpression(le, JST.BinaryOp.Plus, re); case CST.BinaryOp.Sub: return new JST.BinaryExpression(le, JST.BinaryOp.Minus, re); case CST.BinaryOp.Mul: return new JST.BinaryExpression(le, JST.BinaryOp.Times, re); case CST.BinaryOp.Div: { var de = new JST.BinaryExpression(le, JST.BinaryOp.Div, re); if (be.Type(methCompEnv).Style(methCompEnv) is CST.IntegerTypeStyle) return new JST.BinaryExpression (de, JST.BinaryOp.LeftShift, new JST.NumericLiteral(0)); else return de; } case CST.BinaryOp.Rem: return new JST.BinaryExpression(le, JST.BinaryOp.Mod, re); case CST.BinaryOp.LogAnd: case CST.BinaryOp.LogOr: throw new InvalidOperationException(); case CST.BinaryOp.BitAnd: return new JST.BinaryExpression(le, JST.BinaryOp.BitwiseAND, re); case CST.BinaryOp.BitOr: return new JST.BinaryExpression(le, JST.BinaryOp.BitwiseOR, re); case CST.BinaryOp.BitXor: return new JST.BinaryExpression(le, JST.BinaryOp.BitwiseXOR, re); case CST.BinaryOp.Shl: return new JST.BinaryExpression(le, JST.BinaryOp.LeftShift, re); case CST.BinaryOp.Shr: if (be.IsUnsigned) return new JST.BinaryExpression(le, JST.BinaryOp.UnsignedRightShift, re); else return new JST.BinaryExpression(le, JST.BinaryOp.RightShift, re); default: throw new ArgumentOutOfRangeException(); } } } case CST.ExpressionFlavor.Convert: { var ce = (CST.ConvertExpression)expr; var ve = TranslateExpression(methCompEnv, optBody, null, false, ce.Value); var sourceStyle = ce.Value.Type(methCompEnv).Style(methCompEnv); var resultStyle = ce.ResultType.Style(methCompEnv); env.Log(new LossOfPrecisionMessage(CST.MessageContextBuilders.Expression(messageCtxt, expr), "conversion")); if (resultStyle is CST.Int32TypeStyle && sourceStyle is CST.FloatTypeStyle) return new JST.BinaryExpression(ve, JST.BinaryOp.LeftShift, new JST.NumericLiteral(0)); else return ve; } case CST.ExpressionFlavor.Read: { var re = (CST.ReadExpression)expr; if (re.Address.Flavor == CST.ExpressionFlavor.AddressOf) { var aoe = (CST.AddressOfExpression)re.Address; return TranslateCellReadWrite(methCompEnv, optBody, false, aoe.Cell, null); } else { var ptre = TranslateExpression(methCompEnv, optBody, null, false, re.Address); return JST.Expression.DotCall(ptre, Constants.PointerRead); } } case CST.ExpressionFlavor.Write: { var we = (CST.WriteExpression)expr; if (we.Address.Flavor == CST.ExpressionFlavor.AddressOf) { var aoe = (CST.AddressOfExpression)we.Address; return TranslateCellReadWrite (methCompEnv, optBody, ignoreResult, aoe.Cell, lvalue => TranslateExpression(methCompEnv, optBody, lvalue, false, we.Value)); } else { var ptre = TranslateExpression(methCompEnv, optBody, null, false, we.Address); var ve = TranslateExpression(methCompEnv, optBody, null, false, we.Value); return JST.Expression.DotCall(ptre, Constants.PointerWrite, ve); } } case CST.ExpressionFlavor.AddressOf: { var ao = (CST.AddressOfExpression)expr; return TranslateCellAsPointer(methCompEnv, optBody, ao.Cell); } case CST.ExpressionFlavor.ConditionalDeref: { var cde = (CST.ConditionalDerefExpression)expr; var obj = TranslateExpression(methCompEnv, optBody, null, false, cde.Address); return env.JSTHelpers.ConditionalDerefExpressionForType(methCompEnv, cde.ConstrainedType, obj); } case CST.ExpressionFlavor.Call: { var ce = (CST.CallExpression)expr; return TranslateCall(methCompEnv, optBody, ce.CallFlavor, ce.Method, ce.Arguments); } case CST.ExpressionFlavor.NewObject: { var noe = (CST.NewObjectExpression)expr; var args = noe.Arguments.Select(e => TranslateExpression(methCompEnv, optBody, null, false, e)).ToSeq(); // Construction will try to build object directly into optLvalue, if any return env.JSTHelpers.ConstructorExpression (methCompEnv, nameSupply, optBody, optLvalue, noe.Method, args); } case CST.ExpressionFlavor.NewArray: { var nae = (CST.NewArrayExpression)expr; var len = TranslateExpression(methCompEnv, optBody, null, false, nae.Length); var elemType = methCompEnv.ResolveType(nae.ElementType); return JST.Expression.DotCall(rootId.ToE(), Constants.RootNewArray, elemType, len); } case CST.ExpressionFlavor.NewBox: { var nbe = (CST.NewBoxExpression)expr; var value = TranslateExpression(methCompEnv, optBody, null, false, nbe.Value); return env.JSTHelpers.BoxExpressionForType(methCompEnv, nbe.ValueType, value); } case CST.ExpressionFlavor.Cast: { var ce = (CST.CastExpression)expr; var value = TranslateExpression(methCompEnv, optBody, null, false, ce.Value); var resultType = methCompEnv.ResolveType(ce.ResultType); return JST.Expression.DotCall(rootId.ToE(), Constants.RootCastClass, resultType, value); } case CST.ExpressionFlavor.Clone: { var ce = (CST.CloneExpression)expr; var ve = TranslateExpression(methCompEnv, optBody, null, false, ce.Value); return env.JSTHelpers.CloneExpressionForType(methCompEnv, ce.ResultType, ve); } case CST.ExpressionFlavor.IsInst: { var iie = (CST.IsInstExpression)expr; var value = TranslateExpression(methCompEnv, optBody, null, false, iie.Value); var testType = methCompEnv.ResolveType(iie.TestType); return JST.Expression.DotCall(rootId.ToE(), Constants.RootIsInst, value, testType); } case CST.ExpressionFlavor.IfThenElse: { var itee = (CST.IfThenElseExpression)expr; var cond = TranslateConditionalExpression(methCompEnv, optBody, itee.Condition); // NOTE: Not safe to hoist side-effects into body var then = TranslateExpression(methCompEnv, null, null, false, itee.Then); var els = TranslateExpression(methCompEnv, null, null, false, itee.Else); return new JST.ConditionalExpression(cond, then, els); } case CST.ExpressionFlavor.ImportExport: { var iee = (CST.ImportExportExpression)expr; var ve = TranslateExpression(methCompEnv, optBody, null, false, iee.Value); if (iee.IsImport) return env.JSTHelpers.ImportExpressionForType(methCompEnv, iee.ManagedType, ve); else return env.JSTHelpers.ExportExpressionForType(methCompEnv, iee.ManagedType, ve); } case CST.ExpressionFlavor.CallImportedPseudo: { var cie = (CST.CallImportedExpression)expr; var calleeMemEnv = cie.Method.Enter(methCompEnv); var localBody = optBody ?? new Seq<JST.Statement>(); var args = cie.Arguments.Select(e => TranslateExpression(methCompEnv, optBody, null, false, e)).ToSeq(); var call = env.InteropManager.AppendImport (nameSupply, rootId, calleeMemEnv.Assembly, calleeMemEnv.Type, calleeMemEnv.Method, localBody, args); if (optBody == null && localBody.Count > 0) return new JST.StatementsPseudoExpression(new JST.Statements(localBody), call); else return call; } case CST.ExpressionFlavor.StatementsPseudo: { // Statements are in same scope as surrounding context var se = (CST.StatementsPseudoExpression)expr; var body = TranslateStatements(methCompEnv, se.Body); var value = se.Value == null ? null : TranslateExpression(methCompEnv, body, null, false, se.Value); return new JST.StatementsPseudoExpression(new JST.Statements(body), value); } case CST.ExpressionFlavor.InitialStatePseudo: return new JST.ObjectLiteral (new OrdMap<JST.Identifier, JST.Expression> { { Constants.StatePC, new JST.NumericLiteral(0) }, { Constants.StateTryStack, new JST.ArrayLiteral() }, { Constants.StateContStack, new JST.ArrayLiteral() } }); default: throw new ArgumentOutOfRangeException(); } }
// // Both the CLR and JavaScript allow almost any value or object to be tested for 'true'. // // CLR Object JavaScript Object CLR brtrue? JavaScript true? // ----------------- ----------------- ----------------- ----------------- // - undefined - false // null null false false // - false - false // - true - true // 0 (== false) 0 false false // 1 (== true) 1 true true // [] [] true true // [1] [1] true true // "" "" true false <------- SPECIAL CASE // "a" "a" true true // new Object() new Object() true true // // Hence for anything which could be a string at runtime, we must implement 'is true' by // (<exp> || <exp> === "") // private JST.Expression StringIsTrue(JST.Expression e) { return new JST.BinaryExpression(e, JST.BinaryOp.LogicalOR, new JST.BinaryExpression(e, JST.BinaryOp.StrictEquals, new JST.StringLiteral(""))); }
private void EnsurePathExists(ISeq<JST.Statement> statements, JST.Expression script, bool isStatic) { var path = JST.Expression.ExplodePath(script); for (var i = isStatic ? 0 : 1; i < path.Count - 1; i++) { var prefixPath = new Seq<JST.PropertyName>(); for (var j = 0; j <= i; j++) prefixPath.Add(path[j]); var prefix = JST.Expression.Path(prefixPath); if (i == 0) { var exId = new JST.Identifier("e"); #if !JSCRIPT_IS_CORRECT statements.Add(JST.Statement.Var(exId)); #endif statements.Add (new JST.TryStatement (new JST.Statements(new JST.ExpressionStatement(prefix)), new JST.CatchClause(exId, new JST.Statements(JST.Statement.Assignment(prefix, new JST.ObjectLiteral()))))); } else if (!path[i].Value.Equals(Constants.prototype.Value, StringComparison.Ordinal)) statements.Add (new JST.IfStatement (JST.Expression.IsNull(prefix), new JST.Statements(JST.Statement.Assignment(prefix, new JST.ObjectLiteral())))); } }
public void BindArgument(JST.Identifier id, Expression argument) { Bind(id, argument); }
private JST.Expression RecaseMember(MessageContext ctxt, CCI.Member member, JST.Expression script) { if (script != null) return script; var name = Recase(member.Name.Name, interopTypes.GetValue(ctxt, member, env.NamingAttributeType, interopTypes.TheMemberNameCasingProperty)); return new JST.Identifier(JST.Lexemes.StringToIdentifier(name)).ToE(); }
protected void Bind(JST.Identifier id, Expression e) { if (subst.ContainsKey(id)) subst[id] = e; else subst.Add(id, e); }
// Return the name for a getter/setter/adder/remover method based on the user-supplied method name or underlying method name private JST.Expression GetterSetterAdderRemoverNameFromMethod(MessageContext ctxt, CCI.Method method, string prefix, JST.Expression script) { if (method.DeclaringMember == null) throw new ArgumentException("not a getter/setter/adder/remover method"); if (script != null) return script; var name = method.Name.Name; if (name.StartsWith(prefix + "_", StringComparison.OrdinalIgnoreCase)) name = name.Substring(prefix.Length + 1); var str = ""; if (!interopTypes.GetValue(ctxt, method, env.NamingAttributeType, interopTypes.TheRemoveAccessorPrefixProperty)) { str += Recase(prefix, interopTypes.GetValue(ctxt, method, env.NamingAttributeType, interopTypes.ThePrefixNameCasingProperty)); if (!interopTypes.GetValue(ctxt, method, env.NamingAttributeType, interopTypes.TheRemoveAccessorUnderscoreProperty)) str += "_"; } str += Recase(name, interopTypes.GetValue(ctxt, method, env.NamingAttributeType, interopTypes.TheMemberNameCasingProperty)); return new JST.Identifier(JST.Lexemes.StringToIdentifier(str)).ToE(); }
public Expression ApplyReadFrom(JST.Identifier id) { var e = default(Expression); if (subst.TryGetValue(id, out e)) return e; else return new VariableCell(id).Read(); }
// Imports: // - instance methods: no qualification // - static methods & constructors: add qualification // Exports: // - instance methods, not prototype bound: no qualification // - instance methods, prototype bound: add qualification and 'prototype' // - static methods & constructors: add qualification private JST.Expression PrefixName(MessageContext ctxt, CCI.Member member, JST.Expression script, bool isExport) { if (script != null && script is JST.FunctionExpression) return script; var isNonInstance = member.IsStatic || member is CCI.InstanceInitializer; var qual = interopTypes.GetValue (ctxt, member, env.NamingAttributeType, interopTypes.TheQualificationProperty); var isProto = isExport && interopTypes.GetValue (ctxt, member, env.ExportAttributeType, interopTypes.TheBindToPrototypeProperty); var path = new Seq<JST.PropertyName>(); if (script == null && member is CCI.InstanceInitializer && qual == Qualification.None) qual = Qualification.Type; if (!isExport && !isNonInstance && qual != Qualification.None) qual = Qualification.None; if (isExport && !isNonInstance && !isProto && qual != Qualification.None) qual = Qualification.None; if (isExport && !isNonInstance && isProto && qual == Qualification.None) qual = Qualification.Type; if (isNonInstance) { var global = interopTypes.GetValue (ctxt, member, env.NamingAttributeType, interopTypes.TheGlobalObjectProperty); if (global != null) { if (global is JST.FunctionExpression) { env.Log(new InvalidInteropMessage (RewriterMsgContext.Member(ctxt, member), "global object expression cannot be a function")); throw new DefinitionException(); } foreach (var p in JST.Expression.ExplodePath(global)) path.Add(p); } } if (qual == Qualification.Full) { var nsCasing = interopTypes.GetValue (ctxt, member, env.NamingAttributeType, interopTypes.TheNamespaceCasingProperty); foreach (var name in member.DeclaringType.Namespace.Name.Split('.')) { if (string.IsNullOrEmpty(name)) { env.Log(new InvalidInteropMessage (RewriterMsgContext.Member(ctxt, member), "member's namespace cannot be represented in JavaScript")); throw new DefinitionException(); } path.Add(new JST.PropertyName(Recase(name, nsCasing))); } } if (qual == Qualification.Full || qual == Qualification.Type) { var type = member.DeclaringType; var i = path.Count; do { var tnCasing = interopTypes.GetValue (ctxt, type, env.NamingAttributeType, interopTypes.TheTypeNameCasingProperty); path.Insert(i, new JST.PropertyName(Recase(type.Name.Name, tnCasing))); type = type.DeclaringType; } while (type != null); } if (isProto) path.Add(new JST.PropertyName(Constants.prototype)); if (script != null) { foreach (var p in JST.Expression.ExplodePath(script)) path.Add(p); } return JST.Expression.Path(path); }
public Cell ApplyCell(JST.Identifier id) { var e = default(Expression); if (subst.TryGetValue(id, out e)) { var r = e as ReadExpression; if (r != null) { var cell = r.Address.IsAddressOfCell; if (cell != null) return cell; // else: fall-through } // else: fall-through } // else: fall-through return new VariableCell(id); }
// Take acccount of // - PassRootAsArgument // - PassInstanceAsArgument // - InlineParamsArray private ImportMethodInfo FinalImportScript(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn, JST.Expression script, bool isNew) { if (script == null) throw new InvalidOperationException("expecting default script value"); var lastArgIsParamsArray = LastArgIsParamsArray(ctxt, methodDefn) && interopTypes.GetValue(ctxt, methodDefn, env.ImportAttributeType, interopTypes.TheInlineParamsArrayProperty); var methodArity = Arity(methodDefn); var isInstanceMethod = !(methodDefn.IsStatic || methodDefn is CCI.InstanceInitializer); var scriptExpectsRoot = interopTypes.GetValue (ctxt, methodDefn, env.ImportAttributeType, interopTypes.ThePassRootAsArgumentProperty); var instanceIsThis = isInstanceMethod && !interopTypes.GetValue (ctxt, methodDefn, env.ImportAttributeType, interopTypes.ThePassInstanceAsArgumentProperty); var expectedScriptArity = methodArity - (lastArgIsParamsArray ? 1 : 0) + (scriptExpectsRoot ? 1 : 0) - (instanceIsThis ? 1 : 0); CheckScriptArity(ctxt, methodDefn, script, expectedScriptArity); var function = default(JST.FunctionExpression); if (gensym != null) { var parameters = new Seq<JST.Identifier>(); var body = new Seq<JST.Statement>(); var callArgs = new Seq<JST.Expression>(); if (lastArgIsParamsArray) { var argsId = gensym(); body.Add(JST.Statement.Var(argsId, new JST.ArrayLiteral())); if (scriptExpectsRoot) body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, rootId.ToE())); if (!isInstanceMethod) callArgs.Add(new JST.NullExpression()); for (var i = 0; i < methodArity; i++) { var id = gensym(); parameters.Add(id); if (isInstanceMethod && i == 0) { if (instanceIsThis) callArgs.Add(id.ToE()); else { callArgs.Add(new JST.NullExpression()); body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, id.ToE())); } } else if (i == methodArity - 1) { var iId = gensym(); body.Add (new JST.IfStatement (JST.Expression.IsNotNull(id.ToE()), new JST.Statements (new JST.ForStatement (new JST.ForVarLoopClause (iId, new JST.NumericLiteral(0), new JST.BinaryExpression (iId.ToE(), JST.BinaryOp.LessThan, JST.Expression.Dot(id.ToE(), Constants.length)), new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement)), new JST.Statements (JST.Statement.DotCall (argsId.ToE(), Constants.push, new JST.IndexExpression(id.ToE(), iId.ToE()))))))); } else body.Add(JST.Statement.DotCall(argsId.ToE(), Constants.push, id.ToE())); } if (script is JST.FunctionExpression) { var funcId = gensym(); body.Add(JST.Statement.Var(funcId, script)); script = JST.Expression.Dot(funcId.ToE(), Constants.apply); } else script = JST.Expression.Dot(script, Constants.apply); callArgs.Add(argsId.ToE()); } else { if (scriptExpectsRoot) callArgs.Add(rootId.ToE()); for (var i = 0; i < methodArity; i++) { var id = gensym(); parameters.Add(id); if (i == 0 && instanceIsThis) { if (script is JST.FunctionExpression) { callArgs.Insert(0, id.ToE()); var funcId = gensym(); body.Add(JST.Statement.Var(funcId, script)); script = JST.Expression.Dot(funcId.ToE(), Constants.call); } else script = JST.Expression.Dot(id.ToE(), JST.Expression.ExplodePath(script)); } else callArgs.Add(id.ToE()); } } var exp = (JST.Expression)new JST.CallExpression(script, callArgs); if (isNew) exp = new JST.NewExpression(exp); if (ReturnType(methodDefn) == null) body.Add(new JST.ExpressionStatement(exp)); else body.Add(new JST.ReturnStatement(exp)); function = new JST.FunctionExpression(parameters, new JST.Statements(body)); } return new ImportMethodInfo { MethodDefn = methodDefn, Script = function }; }
public JST.Identifier ApplyId(JST.Identifier id) { var e = default(Expression); if (subst.TryGetValue(id, out e)) { var r = e as ReadExpression; if (r != null) { var cell = r.Address.IsAddressOfCell; if (cell != null) { var id2 = cell.IsVariable; if (id2 != null) return id2; // else: fall-through } // else: fall-through } // else: fall-through } // else: fall-through return id; }
// Take account of: // - BindToPrototype // - PassRootAsArgument // - PassInstanceAsArgument // - InlineParamsArray private ExportMethodInfo FinalExportInfo(MessageContext ctxt, Func<JST.Identifier> gensym, JST.Identifier rootId, CCI.Method methodDefn, JST.Expression script) { if (script == null) throw new InvalidOperationException("expecting default script value"); var isInstance = !methodDefn.IsStatic && !(methodDefn is CCI.InstanceInitializer); if (isInstance) { var declType = methodDefn.DeclaringType; if (declType.IsValueType) { env.Log(new InvalidInteropMessage (RewriterMsgContext.Method(ctxt, methodDefn), "cannot export instance methods from value types")); throw new DefinitionException(); } } var lastArgIsParamsArray = LastArgIsParamsArray(ctxt, methodDefn) && interopTypes.GetValue (ctxt, methodDefn, env.ExportAttributeType, interopTypes.TheInlineParamsArrayProperty); var isPassRoot = interopTypes.GetValue (ctxt, methodDefn, env.ExportAttributeType, interopTypes.ThePassRootAsArgumentProperty); var isProto = interopTypes.GetValue (ctxt, methodDefn, env.ExportAttributeType, interopTypes.TheBindToPrototypeProperty); var isPassInstance = interopTypes.GetValue (ctxt, methodDefn, env.ExportAttributeType, interopTypes.ThePassInstanceAsArgumentProperty); var bindToInstance = isInstance && !isProto; var captureThis = isInstance && !isPassInstance; var expectedScriptArity = (isPassRoot ? 1 : 0) + (bindToInstance ? 1 : 0) + 1; CheckScriptArity(ctxt, methodDefn, script, expectedScriptArity); var function = default(JST.FunctionExpression); if (gensym != null) { var parameters = new Seq<JST.Identifier>(); var body = new Seq<JST.Statement>(); var callArgs = new Seq<JST.Expression>(); if (isPassRoot) callArgs.Add(rootId.ToE()); var instArgId = default(JST.Identifier); if (bindToInstance) { instArgId = gensym(); parameters.Add(instArgId); callArgs.Add(instArgId.ToE()); } var funcArgId = gensym(); parameters.Add(funcArgId); if (captureThis || lastArgIsParamsArray) { var innerParameters = new Seq<JST.Identifier>(); var innerBody = new Seq<JST.Statement>(); var innerArgs = new Seq<JST.Expression>(); var methodArity = Arity(methodDefn); for (var i = 0; i < methodArity; i++) { if (i == 0 && captureThis) innerArgs.Add(new JST.ThisExpression()); else if (i == methodArity - 1 && lastArgIsParamsArray) { var iId = gensym(); var arrId = gensym(); innerBody.Add(JST.Statement.Var(arrId, new JST.ArrayLiteral())); innerBody.Add (new JST.ForStatement (new JST.ForVarLoopClause (iId, new JST.NumericLiteral(methodArity - 1), new JST.BinaryExpression (iId.ToE(), JST.BinaryOp.LessThan, JST.Expression.Dot(Constants.arguments.ToE(), Constants.length)), new JST.UnaryExpression(iId.ToE(), JST.UnaryOp.PostIncrement)), new JST.Statements(JST.Statement.DotCall (arrId.ToE(), Constants.push, new JST.IndexExpression(Constants.arguments.ToE(), iId.ToE()))))); innerArgs.Add(arrId.ToE()); } else { var innerArgId = gensym(); innerParameters.Add(innerArgId); innerArgs.Add(innerArgId.ToE()); } } if (ReturnType(methodDefn) == null) { innerBody.Add(JST.Statement.Call(funcArgId.ToE(), innerArgs)); innerBody.Add(new JST.ReturnStatement()); } else innerBody.Add(new JST.ReturnStatement(new JST.CallExpression(funcArgId.ToE(), innerArgs))); var innerFunction = new JST.FunctionExpression(innerParameters, new JST.Statements(innerBody)); callArgs.Add(innerFunction); } else callArgs.Add(funcArgId.ToE()); if (script is JST.FunctionExpression) body.Add(new JST.ExpressionStatement(new JST.CallExpression(script, callArgs))); else { var i = 0; if (bindToInstance) script = JST.Expression.Dot(callArgs[i++], JST.Expression.ExplodePath(script)); EnsurePathExists(body, script, !bindToInstance); body.Add(JST.Statement.Assignment(script, callArgs[i])); } function = new JST.FunctionExpression(parameters, new JST.Statements(body)); } return new ExportMethodInfo { MethodDefn = methodDefn, Script = function, BindToInstance = bindToInstance }; }
// ---------------------------------------------------------------------- // Driver // ---------------------------------------------------------------------- private JST.Statements WithLineCounts(JST.Statements statements, Func<int> nextLine, int currDepth, Set<JST.Identifier> lineCountIds) { var res = new Seq<JST.Statement>(); foreach (var s in statements.Body) { if (s.Flavor != JST.StatementFlavor.Comment) res.Add (JST.Statement.IdAssignment(Constants.DebugCurrentLine, new JST.NumericLiteral(nextLine()))); res.Add(WithLineCounts(s, nextLine, currDepth, lineCountIds)); } return new JST.Statements(res); }