protected virtual IEnumerable <string> GetBottomDefineMethods() { return(GetDefineMethods(InitPosition.Bottom, (method, rrMethod) => { var prevLevel = Emitter.Level; var prevInitialLevel = Emitter.InitialLevel; PushWriter("{0}"); ResetLocals(); var prevMap = BuildLocalsMap(); var prevNamesMap = BuildLocalsNamesMap(); Emitter.NoBraceBlock = method.Body; Emitter.InitPosition = InitPosition.Bottom; ((Emitter)Emitter).InitialLevel = Emitter.InitialLevel > 1 ? Emitter.InitialLevel - 1 : 0; Emitter.ResetLevel(); method.Body.AcceptVisitor(Emitter); Emitter.InitPosition = null; ((Emitter)Emitter).InitialLevel = prevInitialLevel; Emitter.ResetLevel(prevLevel); ClearLocalsMap(prevMap); ClearLocalsNamesMap(prevNamesMap); return PopWriter(true); })); }
protected virtual IEnumerable <string> GetBeforeDefineMethods() { return(GetDefineMethods(InitPosition.Before, (method, rrMethod) => { var level = Emitter.Level; PushWriter(JS.Types.H5.INIT + "(function () {0});"); ResetLocals(); var prevMap = BuildLocalsMap(); var prevNamesMap = BuildLocalsNamesMap(); Emitter.InitPosition = InitPosition.Before; Emitter.ResetLevel(); method.Body.AcceptVisitor(Emitter); Emitter.InitPosition = null; Emitter.ResetLevel(level); ClearLocalsMap(prevMap); ClearLocalsNamesMap(prevNamesMap); return PopWriter(true); })); }
public StringBuilder NewWriter() { Emitter.Output = new StringBuilder(); Emitter.IsNewLine = false; Emitter.ResetLevel(); Emitter.Comma = false; return(Emitter.Output); }
public bool RestoreWriter(IWriterInfo writer) { if (Emitter.Output != writer.Output) { Emitter.Output = writer.Output; Emitter.IsNewLine = writer.IsNewLine; Emitter.ResetLevel(writer.Level); Emitter.Comma = writer.Comma; return(true); } return(false); }
protected virtual bool WriteObject(string objectName, List <TypeConfigItem> members, string format, string interfaceFormat) { bool hasProperties = HasProperties(objectName, members); int pos = 0; IWriterInfo writer = null; bool beginBlock = false; if (hasProperties && objectName != null && !IsObjectLiteral) { beginBlock = true; pos = Emitter.Output.Length; writer = SaveWriter(); EnsureComma(); Write(objectName); WriteColon(); BeginBlock(); } bool isProperty = JS.Fields.PROPERTIES == objectName; bool isField = JS.Fields.FIELDS == objectName; int count = 0; foreach (var member in members) { object constValue = null; bool isPrimitive = false; bool write = false; bool writeScript = false; if (member.Initializer is PrimitiveExpression primitiveExpr) { //isPrimitive = true; constValue = primitiveExpr.Value; ResolveResult rr = null; if (member.VarInitializer != null) { rr = Emitter.Resolver.ResolveNode(member.VarInitializer); } else { rr = Emitter.Resolver.ResolveNode(member.Entity); } if (rr != null && rr.Type.Kind == TypeKind.Enum) { constValue = Helpers.GetEnumValue(Emitter, rr.Type, constValue); writeScript = true; } } if (constValue is RawValue) { constValue = constValue.ToString(); write = true; writeScript = false; } var isNull = member.Initializer.IsNull || member.Initializer is NullReferenceExpression || member.Initializer.Parent == null; if (!isNull && !isPrimitive) { var constrr = Emitter.Resolver.ResolveNode(member.Initializer); if (constrr != null && constrr.IsCompileTimeConstant) { //isPrimitive = true; constValue = constrr.ConstantValue; var expectedType = Emitter.Resolver.Resolver.GetExpectedType(member.Initializer); if (!expectedType.Equals(constrr.Type) && expectedType.Kind != TypeKind.Dynamic) { try { constValue = Convert.ChangeType(constValue, ReflectionHelper.GetTypeCode(expectedType)); } catch (Exception) { Logger.ZLogWarning("FieldBlock: Convert.ChangeType is failed. Value type: {0}, Target type: {1}", constrr.Type.FullName, expectedType.FullName); } } if (constrr.Type.Kind == TypeKind.Enum) { constValue = Helpers.GetEnumValue(Emitter, constrr.Type, constrr.ConstantValue); } writeScript = true; } } var isNullable = false; if (isPrimitive && constValue is AstType) { var itype = Emitter.Resolver.ResolveNode((AstType)constValue); if (NullableType.IsNullable(itype.Type)) { isNullable = true; } } string tpl = null; IMember templateMember = null; MemberResolveResult init_rr = null; if (isField && member.VarInitializer != null) { init_rr = Emitter.Resolver.ResolveNode(member.VarInitializer) as MemberResolveResult; tpl = init_rr != null?Emitter.GetInline(init_rr.Member) : null; if (tpl != null) { templateMember = init_rr.Member; } } bool isAutoProperty = false; if (isProperty) { var member_rr = Emitter.Resolver.ResolveNode(member.Entity) as MemberResolveResult; var property = (IProperty)member_rr.Member; isAutoProperty = Helpers.IsAutoProperty(property); } bool written = false; if (!isNull && (!isPrimitive || constValue is AstType || tpl != null) && !(isProperty && !IsObjectLiteral && !isAutoProperty)) { string value = null; bool needContinue = false; string defValue = ""; if (!isPrimitive) { var oldWriter = SaveWriter(); NewWriter(); member.Initializer.AcceptVisitor(Emitter); value = Emitter.Output.ToString(); RestoreWriter(oldWriter); ResolveResult rr = null; AstType astType = null; if (member.VarInitializer != null) { rr = Emitter.Resolver.ResolveNode(member.VarInitializer); } else { astType = member.Entity.ReturnType; rr = Emitter.Resolver.ResolveNode(member.Entity); } constValue = Inspector.GetDefaultFieldValue(rr.Type, astType); if (rr.Type.Kind == TypeKind.Enum) { constValue = Helpers.GetEnumValue(Emitter, rr.Type, constValue); } isNullable = NullableType.IsNullable(rr.Type); needContinue = constValue is IType; writeScript = true; /*if (needContinue && !(member.Initializer is ObjectCreateExpression)) * { * defValue = " || " + Inspector.GetStructDefaultValue((IType)constValue, this.Emitter); * }*/ } else if (constValue is AstType) { value = isNullable ? "null" : Inspector.GetStructDefaultValue((AstType)constValue, Emitter); constValue = value; write = true; needContinue = !isProperty && !isNullable; } var name = member.GetName(Emitter); bool isValidIdentifier = Helpers.IsValidIdentifier(name); if (isProperty && isPrimitive) { constValue = "null"; if (IsObjectLiteral) { written = true; if (isValidIdentifier) { Write(string.Format("this.{0} = {1};", name, value)); } else { Write(string.Format("this[{0}] = {1};", ToJavaScript(name, Emitter), value)); } WriteNewLine(); } else { Injectors.Add(string.Format(name.StartsWith("\"") || !isValidIdentifier ? "this[{0}] = {1};" : "this.{0} = {1};", isValidIdentifier ? name : ToJavaScript(name, Emitter), value)); } } else { if (IsObjectLiteral) { written = true; if (isValidIdentifier) { Write(string.Format("this.{0} = {1};", name, value + defValue)); } else { Write(string.Format("this[{0}] = {1};", ToJavaScript(name, Emitter), value + defValue)); } WriteNewLine(); } else if (tpl != null) { if (!tpl.Contains("{0}")) { tpl = tpl + " = {0};"; } string v = null; if (!isNull && (!isPrimitive || constValue is AstType)) { v = value + defValue; } else { if (write) { v = constValue != null?constValue.ToString() : ""; } else if (writeScript) { v = ToJavaScript(constValue, Emitter); } else { var oldWriter = SaveWriter(); NewWriter(); member.Initializer.AcceptVisitor(Emitter); v = Emitter.Output.ToString(); RestoreWriter(oldWriter); } } tpl = Helpers.ConvertTokens(Emitter, tpl, templateMember); tpl = tpl.Replace("{this}", "this").Replace("{0}", v); if (!tpl.EndsWith(";")) { tpl += ";"; } Injectors.Add(tpl); } else { bool isDefaultInstance = Emitter.Resolver.ResolveNode(member.Initializer) is CSharpInvocationResolveResult rr && rr.Member.SymbolKind == SymbolKind.Constructor && rr.Arguments.Count == 0 && rr.InitializerStatements.Count == 0 && rr.Type.Kind == TypeKind.Struct; if (!isDefaultInstance) { if (isField && !isValidIdentifier) { Injectors.Add(string.Format("this[{0}] = {1};", name.StartsWith("\"") ? name : ToJavaScript(name, Emitter), value + defValue)); } else { Injectors.Add(string.Format(name.StartsWith("\"") ? interfaceFormat : format, name, value + defValue)); } } } } } count++; if (written) { continue; } bool withoutTypeParams = true; MemberResolveResult m_rr = null; if (member.Entity != null) { m_rr = Emitter.Resolver.ResolveNode(member.Entity) as MemberResolveResult; if (m_rr != null) { withoutTypeParams = OverloadsCollection.ExcludeTypeParameterForDefinition(m_rr); } } var mname = member.GetName(Emitter, withoutTypeParams); if (TypeInfo.IsEnum && m_rr != null) { mname = Emitter.GetEntityName(m_rr.Member); } bool isValid = Helpers.IsValidIdentifier(mname); if (!isValid) { if (IsObjectLiteral) { mname = "[" + ToJavaScript(mname, Emitter) + "]"; } else { mname = ToJavaScript(mname, Emitter); } } if (IsObjectLiteral) { WriteThis(); if (isValid) { WriteDot(); } Write(mname); Write(" = "); } else { EnsureComma(); XmlToJsDoc.EmitComment(this, member.Entity, null, member.Entity is FieldDeclaration ? member.VarInitializer : null); Write(mname); WriteColon(); } bool close = false; if (isProperty && !IsObjectLiteral && !isAutoProperty) { var oldTempVars = Emitter.TempVariables; BeginBlock(); new VisitorPropertyBlock(Emitter, (PropertyDeclaration)member.Entity).Emit(); WriteNewLine(); EndBlock(); Emitter.Comma = true; Emitter.TempVariables = oldTempVars; continue; } if (constValue is AstType || constValue is IType) { Write("null"); if (!isNullable) { var name = member.GetName(Emitter); bool isValidIdentifier = Helpers.IsValidIdentifier(name); var value = constValue is AstType?Inspector.GetStructDefaultValue((AstType)constValue, Emitter) : Inspector.GetStructDefaultValue((IType)constValue, Emitter); if (!isValidIdentifier) { Injectors.Insert(BeginCounter++, string.Format("this[{0}] = {1};", name.StartsWith("\"") ? name : ToJavaScript(name, Emitter), value)); } else { Injectors.Insert(BeginCounter++, string.Format(name.StartsWith("\"") ? interfaceFormat : format, name, value)); } } } else if (write) { Write(constValue); } else if (writeScript) { WriteScript(constValue); } else { member.Initializer.AcceptVisitor(Emitter); } if (close) { Write(" }"); } if (IsObjectLiteral) { WriteSemiColon(true); } Emitter.Comma = true; } if (count > 0 && objectName != null && !IsObjectLiteral) { WriteNewLine(); EndBlock(); } else if (beginBlock) { Emitter.IsNewLine = writer.IsNewLine; Emitter.ResetLevel(writer.Level); Emitter.Comma = writer.Comma; Emitter.Output.Length = pos; } return(count > 0); }
public virtual void ResetLevel(int level) { Emitter.ResetLevel(level); }
public virtual void Outdent() { Emitter.ResetLevel(Emitter.Level - 1); }
public virtual void Indent() { Emitter.ResetLevel(Emitter.Level + 1); }
protected void EmitGeneratorBlock() { BeginBlock(); var args = Parameters; if (!IsEnumeratorReturn) { WriteReturn(true); Write("new "); if (ReturnType.IsParameterized) { Write("(H5.GeneratorEnumerable$1(" + H5Types.ToJsName(ReturnType.TypeArguments[0], Emitter) + "))"); } else { Write("H5.GeneratorEnumerable"); } WriteOpenParentheses(); Write(JS.Funcs.H5_BIND + "(this, "); WriteFunction(); if (args.Count > 0) { WriteOpenParentheses(); for (int i = 0; i < args.Count; i++) { Write(args[i]); if (i < args.Count - 1) { Write(", "); } } WriteCloseParentheses(); } else { WriteOpenCloseParentheses(true); } WriteSpace(); BeginBlock(); } WriteVar(true); Write(JS.Vars.ASYNC_STEP + " = 0"); Emitter.Comma = true; Indent(); // This is required to add async variables into Emitter.AsyncVariables and emit them prior to body IWriterInfo writerInfo = SaveWriter(); StringBuilder body = NewWriter(); Emitter.ResetLevel(writerInfo.Level - 1); EmitGeneratorBody(); RestoreWriter(writerInfo); foreach (var localVar in Emitter.AsyncVariables) { EnsureComma(true); Write(localVar); Emitter.Comma = true; } Emitter.Comma = false; WriteSemiColon(); Outdent(); WriteNewLine(); WriteNewLine(); WriteVar(true); Write(JS.Vars.ENUMERATOR + " = new "); if (ReturnType.IsParameterized) { Write("(" + JS.Types.H5.Generator.NAME_GENERIC + "(" + H5Types.ToJsName(ReturnType.TypeArguments[0], Emitter) + "))"); } else { Write(JS.Types.H5.Generator.NAME); } WriteOpenParentheses(); Write(JS.Funcs.H5_BIND + "(this, "); WriteFunction(); WriteOpenCloseParentheses(true); Write(body); WriteCloseParentheses(); EmitFinallyHandler(); WriteCloseParentheses(); WriteSemiColon(); WriteNewLine(); WriteReturn(true); Write(JS.Vars.ENUMERATOR); WriteSemiColon(); WriteNewLine(); if (!IsEnumeratorReturn) { EndBlock(); if (args.Count > 0) { Write(", arguments"); } WriteCloseParentheses(); WriteCloseParentheses(); WriteSemiColon(); WriteNewLine(); } EndBlock(); }
protected virtual void EmitLambda(IEnumerable <ParameterDeclaration> parameters, AstNode body, AstNode context) { var rr = Emitter.Resolver.ResolveNode(context); var oldLifting = Emitter.ForbidLifting; Emitter.ForbidLifting = false; var noLiftingRule = Emitter.Rules.Lambda == LambdaRule.Plain; CaptureAnalyzer analyzer = null; if (!noLiftingRule) { analyzer = new CaptureAnalyzer(Emitter); analyzer.Analyze(Body, Parameters.Select(p => p.Name)); } var oldLevel = Emitter.Level; if (!noLiftingRule && analyzer.UsedVariables.Count == 0) { Emitter.ResetLevel(); Indent(); } IAsyncBlock asyncBlock = null; PushLocals(); if (IsAsync) { if (context is LambdaExpression) { asyncBlock = new AsyncBlock(Emitter, (LambdaExpression)context); } else { asyncBlock = new AsyncBlock(Emitter, (AnonymousMethodExpression)context); } asyncBlock.InitAsyncBlock(); } else if (YieldBlock.HasYield(body)) { IsAsync = true; if (context is LambdaExpression) { asyncBlock = new GeneratorBlock(Emitter, (LambdaExpression)context); } else { asyncBlock = new GeneratorBlock(Emitter, (AnonymousMethodExpression)context); } asyncBlock.InitAsyncBlock(); } var prevMap = BuildLocalsMap(); var prevNamesMap = BuildLocalsNamesMap(); AddLocals(parameters, body); bool block = body is BlockStatement; Write(""); var savedThisCount = Emitter.ThisRefCounter; var capturedVariables = GetCapturedLoopVariablesNames(); var hasCapturedVariables = capturedVariables != null && capturedVariables.Length > 0; if (hasCapturedVariables) { Write("(function ($me, "); Write(string.Join(", ", capturedVariables) + ") "); BeginBlock(); Write("return "); } var savedPos = Emitter.Output.Length; WriteFunction(); EmitMethodParameters(parameters, null, context); WriteSpace(); int pos = 0; if (!block && !IsAsync) { BeginBlock(); pos = Emitter.Output.Length; } bool isSimpleLambda = body.Parent is LambdaExpression && !block && !IsAsync; if (isSimpleLambda) { ConvertParamsToReferences(parameters); if (!(rr is LambdaResolveResult lrr) || lrr.ReturnType.Kind != TypeKind.Void) { WriteReturn(true); } } if (IsAsync) { asyncBlock.Emit(true); } else { body.AcceptVisitor(Emitter); } if (isSimpleLambda) { WriteSemiColon(); } if (!block && !IsAsync) { WriteNewLine(); EndBlock(); } if (!block && !IsAsync) { EmitTempVars(pos); } if (!noLiftingRule && analyzer.UsedVariables.Count == 0) { if (!Emitter.ForbidLifting) { var name = "f" + (Emitter.NamedFunctions.Count + 1); var code = Emitter.Output.ToString().Substring(savedPos); var codeForComare = RemoveTokens(code); var pair = Emitter.NamedFunctions.FirstOrDefault(p => { if (Emitter.AssemblyInfo.SourceMap.Enabled) { return(RemoveTokens(p.Value) == codeForComare); } return(p.Value == code); }); if (pair.Key != null && pair.Value != null) { name = pair.Key; } else { Emitter.NamedFunctions.Add(name, code); } Emitter.Output.Remove(savedPos, Emitter.Output.Length - savedPos); Emitter.Output.Insert(savedPos, JS.Vars.D_ + "." + H5Types.ToJsName(Emitter.TypeInfo.Type, Emitter, true) + "." + name); } Emitter.ResetLevel(oldLevel); } Emitter.ForbidLifting = oldLifting; var methodDeclaration = Body.GetParent <MethodDeclaration>(); var thisCaptured = Emitter.ThisRefCounter > savedThisCount || IsAsync && methodDeclaration != null && !methodDeclaration.HasModifier(Modifiers.Static); if (thisCaptured) { Emitter.Output.Insert(savedPos, JS.Funcs.H5_BIND + (hasCapturedVariables ? "($me, " : "(this, ")); WriteCloseParentheses(); } if (hasCapturedVariables) { WriteSemiColon(true); EndBlock(); Write(")("); Write("this, "); Write(string.Join(", ", capturedVariables)); Write(")"); } PopLocals(); ClearLocalsMap(prevMap); ClearLocalsNamesMap(prevNamesMap); }
protected void EmitAsyncBody() { BeginBlock(); var asyncTryVisitor = new AsyncTryVisitor(); Node.AcceptChildren(asyncTryVisitor); var needTry = asyncTryVisitor.Found || IsTaskReturn; Emitter.AsyncVariables.Add(JS.Vars.ASYNC_JUMP); if (needTry) { if (IsTaskReturn) { Emitter.AsyncVariables.Add(JS.Vars.ASYNC_TCS + " = new " + JS.Types.TASK_COMPLETION_SOURCE + "()"); } Emitter.AsyncVariables.Add(JS.Vars.ASYNC_RETURN_VALUE); Write("try"); WriteSpace(); BeginBlock(); } Write("for (;;) "); BeginBlock(); WriteIndent(); int checkerPos = Emitter.Output.Length; WriteNewLine(); Write("switch (" + JS.Vars.ASYNC_STEP + ") "); BeginBlock(); Step = 0; var writer = SaveWriter(); AddAsyncStep(); if (Body.Parent is LambdaExpression && Body is Expression && IsTaskReturn && ReturnType.FullName == "System.Threading.Tasks.Task" && ReturnType.TypeParameterCount > 0) { new ReturnBlock(Emitter, (Expression)Body).Emit(); } else { var level = Emitter.InitialLevel; ((Emitter)Emitter).InitialLevel = 0; Emitter.ResetLevel(); Body.AcceptVisitor(Emitter); ((Emitter)Emitter).InitialLevel = level; } RestoreWriter(writer); InjectSteps(); WriteNewLine(); EndBlock(); InjectStepsChecker(checkerPos); WriteNewLine(); EndBlock(); if (needTry) { if (!Emitter.Locals.ContainsKey(JS.Vars.ASYNC_E)) { AddLocal(JS.Vars.ASYNC_E, null, AstType.Null); } WriteNewLine(); EndBlock(); Write(" catch(" + JS.Vars.ASYNC_E1 + ") "); BeginBlock(); Write(JS.Vars.ASYNC_E + " = " + JS.Types.System.Exception.CREATE + "(" + JS.Vars.ASYNC_E1 + ");"); WriteNewLine(); InjectCatchHandlers(); WriteNewLine(); EndBlock(); } WriteNewLine(); EndBlock(); }
protected virtual void EmitMethods(Dictionary <string, List <MethodDeclaration> > methods, Dictionary <string, List <EntityDeclaration> > properties, Dictionary <OperatorType, List <OperatorDeclaration> > operators) { int pos = Emitter.Output.Length; var writerInfo = SaveWriter(); string globalTarget = H5Types.GetGlobalTarget(TypeInfo.Type.GetDefinition(), TypeInfo.TypeDeclaration); if (globalTarget == null) { EnsureComma(); Write(JS.Fields.METHODS); WriteColon(); BeginBlock(); } int checkPos = Emitter.Output.Length; var names = new List <string>(properties.Keys); foreach (var name in names) { var props = properties[name]; foreach (var prop in props) { if (prop is PropertyDeclaration) { Emitter.VisitPropertyDeclaration((PropertyDeclaration)prop); } else if (prop is CustomEventDeclaration) { Emitter.VisitCustomEventDeclaration((CustomEventDeclaration)prop); } else if (prop is IndexerDeclaration) { Emitter.VisitIndexerDeclaration((IndexerDeclaration)prop); } } } names = new List <string>(methods.Keys); foreach (var name in names) { EmitMethodsGroup(methods[name]); } if (operators != null) { var ops = new List <OperatorType>(operators.Keys); foreach (var op in ops) { EmitOperatorGroup(operators[op]); } } if (TypeInfo.ClassType == ClassType.Struct) { if (!StaticBlock) { EmitStructMethods(); } else { string structName = H5Types.ToJsName(TypeInfo.Type, Emitter); if (TypeInfo.Type.TypeArguments.Count > 0 && !Helpers.IsIgnoreGeneric(TypeInfo.Type, Emitter)) { structName = "(" + structName + ")"; } EnsureComma(); Write(JS.Funcs.GETDEFAULTVALUE + ": function () { return new " + structName + "(); }"); Emitter.Comma = true; } } else if (StaticBlock) { var ctor = TypeInfo.Type.GetConstructors().FirstOrDefault(c => c.Parameters.Count == 0 && Emitter.GetInline(c) != null); if (ctor != null) { var code = Emitter.GetInline(ctor); EnsureComma(); Write(JS.Funcs.GETDEFAULTVALUE + ": function () "); BeginBlock(); Write("return "); var argsInfo = new ArgumentsInfo(Emitter, ctor); new InlineArgumentsBlock(Emitter, argsInfo, code).Emit(); Write(";"); WriteNewLine(); EndBlock(); Emitter.Comma = true; } } if (globalTarget == null) { if (checkPos == Emitter.Output.Length) { Emitter.IsNewLine = writerInfo.IsNewLine; Emitter.ResetLevel(writerInfo.Level); Emitter.Comma = writerInfo.Comma; Emitter.Output.Length = pos; } else { WriteNewLine(); EndBlock(); } } }