Пример #1
0
        private string CompileMethodCall(IMethod m, string[] a)
        {
            string inlineCode = this._emitter.GetInline(m);
            var    argsInfo   = new ArgumentsInfo(this._emitter, a);
            var    block      = new InlineArgumentsBlock(this._emitter, argsInfo, inlineCode, m);
            var    oldWriter  = this._block.SaveWriter();
            var    sb         = this._block.NewWriter();

            block.Emit();
            string result = sb.ToString();

            this._block.RestoreWriter(oldWriter);

            return(result);
        }
Пример #2
0
        protected void VisitInvocationExpression()
        {
            InvocationExpression invocationExpression = this.InvocationExpression;
            int pos = this.Emitter.Output.Length;

            if (this.Emitter.IsForbiddenInvocation(invocationExpression))
            {
                throw new EmitterException(invocationExpression, "This method cannot be invoked directly");
            }

            var oldValue = this.Emitter.ReplaceAwaiterByVar;
            var oldAsyncExpressionHandling = this.Emitter.AsyncExpressionHandling;

            if (this.Emitter.IsAsync && !this.Emitter.AsyncExpressionHandling)
            {
                this.WriteAwaiters(invocationExpression);
                this.Emitter.ReplaceAwaiterByVar     = true;
                this.Emitter.AsyncExpressionHandling = true;
            }

            Tuple <bool, bool, string> inlineInfo = this.Emitter.GetInlineCode(invocationExpression);
            var argsInfo = new ArgumentsInfo(this.Emitter, invocationExpression);

            var argsExpressions = argsInfo.ArgumentsExpressions;
            var paramsArg       = argsInfo.ParamsExpression;

            var targetResolve    = this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter);
            var csharpInvocation = targetResolve as CSharpInvocationResolveResult;
            MemberReferenceExpression targetMember = invocationExpression.Target as MemberReferenceExpression;
            bool isObjectLiteral = csharpInvocation != null && csharpInvocation.Member.DeclaringTypeDefinition != null?this.Emitter.Validator.IsObjectLiteral(csharpInvocation.Member.DeclaringTypeDefinition) : false;

            var interceptor = this.Emitter.Plugins.OnInvocation(this, this.InvocationExpression, targetResolve as InvocationResolveResult);

            if (interceptor.Cancel)
            {
                this.Emitter.SkipSemiColon           = true;
                this.Emitter.ReplaceAwaiterByVar     = oldValue;
                this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
                return;
            }

            if (!string.IsNullOrEmpty(interceptor.Replacement))
            {
                this.Write(interceptor.Replacement);
                this.Emitter.ReplaceAwaiterByVar     = oldValue;
                this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
                return;
            }

            if (inlineInfo != null)
            {
                bool   isStaticMethod = inlineInfo.Item1;
                bool   isInlineMethod = inlineInfo.Item2;
                string inlineScript   = inlineInfo.Item3;

                if (isInlineMethod)
                {
                    if (invocationExpression.Arguments.Count > 0)
                    {
                        var code             = invocationExpression.Arguments.First();
                        var inlineExpression = code as PrimitiveExpression;

                        if (inlineExpression == null)
                        {
                            throw new EmitterException(invocationExpression, "Only primitive expression can be inlined");
                        }

                        string value = inlineExpression.Value.ToString().Trim();

                        if (value.Length > 0)
                        {
                            value = InlineArgumentsBlock.ReplaceInlineArgs(this, inlineExpression.Value.ToString(), invocationExpression.Arguments.Skip(1).ToArray());
                            this.Write(value);

                            value = value.Trim();
                            if (value[value.Length - 1] == ';' || value.EndsWith("*/", StringComparison.InvariantCulture) || value.StartsWith("//"))
                            {
                                this.Emitter.EnableSemicolon = false;
                                this.WriteNewLine();
                            }
                        }
                        else
                        {
                            // Empty string, emit nothing.
                            this.Emitter.EnableSemicolon = false;
                        }

                        this.Emitter.ReplaceAwaiterByVar     = oldValue;
                        this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                        return;
                    }
                }
                else
                {
                    MemberReferenceExpression targetMemberRef = invocationExpression.Target as MemberReferenceExpression;
                    bool isBase = targetMemberRef != null && targetMemberRef.Target is BaseReferenceExpression;

                    if (!String.IsNullOrEmpty(inlineScript) && (isBase || invocationExpression.Target is IdentifierExpression))
                    {
                        argsInfo.ThisArgument = "this";
                        bool noThis = !inlineScript.Contains("{this}");

                        if (inlineScript.StartsWith("<self>"))
                        {
                            noThis       = false;
                            inlineScript = inlineScript.Substring(6);
                        }

                        if (!isStaticMethod && noThis)
                        {
                            this.WriteThis();
                            this.WriteDot();
                        }

                        new InlineArgumentsBlock(this.Emitter, argsInfo, inlineScript).Emit();
                        this.Emitter.ReplaceAwaiterByVar     = oldValue;
                        this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                        return;
                    }
                }
            }

            if (targetMember != null || isObjectLiteral)
            {
                var member = targetMember != null?this.Emitter.Resolver.ResolveNode(targetMember.Target, this.Emitter) : null;

                if (targetResolve != null)
                {
                    InvocationResolveResult invocationResult;
                    bool isExtensionMethodInvocation = false;
                    if (csharpInvocation != null)
                    {
                        if (member != null && member.Type.Kind == TypeKind.Delegate && (/*csharpInvocation.Member.Name == "Invoke" || */ csharpInvocation.Member.Name == "BeginInvoke" || csharpInvocation.Member.Name == "EndInvoke") && !csharpInvocation.IsExtensionMethodInvocation)
                        {
                            throw new EmitterException(invocationExpression, "Delegate's 'Invoke' methods are not supported. Please use direct delegate invoke.");
                        }

                        if (csharpInvocation.IsExtensionMethodInvocation)
                        {
                            invocationResult            = csharpInvocation;
                            isExtensionMethodInvocation = true;
                            var resolvedMethod = invocationResult.Member as IMethod;
                            if (resolvedMethod != null && resolvedMethod.IsExtensionMethod)
                            {
                                string inline   = this.Emitter.GetInline(resolvedMethod);
                                bool   isNative = this.IsNativeMethod(resolvedMethod);

                                if (string.IsNullOrWhiteSpace(inline) && isNative)
                                {
                                    invocationResult = null;
                                }
                            }
                        }
                        else
                        {
                            invocationResult = null;
                        }

                        if (this.IsEmptyPartialInvoking(csharpInvocation.Member as IMethod) || IsConditionallyRemoved(invocationExpression, csharpInvocation.Member))
                        {
                            this.Emitter.SkipSemiColon           = true;
                            this.Emitter.ReplaceAwaiterByVar     = oldValue;
                            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                            return;
                        }
                    }
                    else
                    {
                        invocationResult = targetResolve as InvocationResolveResult;

                        if (invocationResult != null && (this.IsEmptyPartialInvoking(invocationResult.Member as IMethod) || IsConditionallyRemoved(invocationExpression, invocationResult.Member)))
                        {
                            this.Emitter.SkipSemiColon           = true;
                            this.Emitter.ReplaceAwaiterByVar     = oldValue;
                            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                            return;
                        }
                    }

                    if (invocationResult == null)
                    {
                        invocationResult = this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter) as InvocationResolveResult;
                    }

                    if (invocationResult != null)
                    {
                        var resolvedMethod = invocationResult.Member as IMethod;

                        if (resolvedMethod != null && (resolvedMethod.IsExtensionMethod || isObjectLiteral))
                        {
                            string inline   = this.Emitter.GetInline(resolvedMethod);
                            bool   isNative = this.IsNativeMethod(resolvedMethod);

                            if (isExtensionMethodInvocation || isObjectLiteral)
                            {
                                if (!string.IsNullOrWhiteSpace(inline))
                                {
                                    this.Write("");
                                    StringBuilder savedBuilder = this.Emitter.Output;
                                    this.Emitter.Output = new StringBuilder();
                                    this.WriteThisExtension(invocationExpression.Target);
                                    argsInfo.ThisArgument = this.Emitter.Output.ToString();
                                    this.Emitter.Output   = savedBuilder;
                                    new InlineArgumentsBlock(this.Emitter, argsInfo, inline).Emit();
                                }
                                else if (!isNative)
                                {
                                    var    overloads = OverloadsCollection.Create(this.Emitter, resolvedMethod);
                                    string name      = BridgeTypes.ToJsName(resolvedMethod.DeclaringType, this.Emitter) + ".";

                                    if (isObjectLiteral && !resolvedMethod.IsStatic)
                                    {
                                        name += JS.Fields.PROTOTYPE + "." + overloads.GetOverloadName() + ".";
                                        name += JS.Funcs.CALL;
                                    }
                                    else
                                    {
                                        name += overloads.GetOverloadName();
                                    }

                                    var isIgnoreClass = resolvedMethod.DeclaringTypeDefinition != null && this.Emitter.Validator.IsIgnoreType(resolvedMethod.DeclaringTypeDefinition);

                                    this.Write(name);
                                    int openPos = this.Emitter.Output.Length;
                                    this.WriteOpenParentheses();

                                    this.Emitter.Comma = false;

                                    if (!isIgnoreClass && !Helpers.IsIgnoreGeneric(resolvedMethod, this.Emitter) && argsInfo.HasTypeArguments)
                                    {
                                        new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                                    }

                                    this.EnsureComma(false);

                                    if (!isObjectLiteral || !resolvedMethod.IsStatic)
                                    {
                                        this.WriteThisExtension(invocationExpression.Target);

                                        if (invocationExpression.Arguments.Count > 0)
                                        {
                                            this.WriteComma();
                                        }
                                    }

                                    new ExpressionListBlock(this.Emitter, argsExpressions, paramsArg, invocationExpression, openPos).Emit();

                                    this.WriteCloseParentheses();
                                }

                                if (!string.IsNullOrWhiteSpace(inline) || !isNative)
                                {
                                    this.Emitter.ReplaceAwaiterByVar     = oldValue;
                                    this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                                    return;
                                }
                            }
                            else if (isNative)
                            {
                                if (!string.IsNullOrWhiteSpace(inline))
                                {
                                    this.Write("");
                                    StringBuilder savedBuilder = this.Emitter.Output;
                                    this.Emitter.Output = new StringBuilder();
                                    this.WriteThisExtension(invocationExpression.Target);
                                    argsInfo.ThisArgument = this.Emitter.Output.ToString();
                                    this.Emitter.Output   = savedBuilder;
                                    new InlineArgumentsBlock(this.Emitter, argsInfo, inline).Emit();
                                }
                                else
                                {
                                    argsExpressions.First().AcceptVisitor(this.Emitter);
                                    this.WriteDot();
                                    string name = this.Emitter.GetEntityName(resolvedMethod);
                                    this.Write(name);
                                    int openPos = this.Emitter.Output.Length;
                                    this.WriteOpenParentheses();
                                    new ExpressionListBlock(this.Emitter, argsExpressions.Skip(1), paramsArg, invocationExpression, openPos).Emit();
                                    this.WriteCloseParentheses();
                                }

                                this.Emitter.ReplaceAwaiterByVar     = oldValue;
                                this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                                return;
                            }
                        }
                    }
                }
            }

            var proto = false;

            if (targetMember != null && targetMember.Target is BaseReferenceExpression)
            {
                var rr = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter) as MemberResolveResult;

                if (rr != null)
                {
                    proto = rr.IsVirtualCall;

                    /*var method = rr.Member as IMethod;
                     * if (method != null && method.IsVirtual)
                     * {
                     *  proto = true;
                     * }
                     * else
                     * {
                     *  var prop = rr.Member as IProperty;
                     *
                     *  if (prop != null && prop.IsVirtual)
                     *  {
                     *      proto = true;
                     *  }
                     * }*/
                }
            }

            if (proto)
            {
                var baseType = this.Emitter.GetBaseMethodOwnerTypeDefinition(targetMember.MemberName, targetMember.TypeArguments.Count);

                bool isIgnore = this.Emitter.Validator.IsIgnoreType(baseType);

                if (isIgnore)
                {
                    //throw (System.Exception)this.Emitter.CreateException(targetMember.Target, "Cannot call base method, because parent class code is ignored");
                }

                bool needComma = false;

                var resolveResult = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter);

                string name = null;

                if (this.Emitter.TypeInfo.GetBaseTypes(this.Emitter).Any())
                {
                    name = BridgeTypes.ToJsName(this.Emitter.TypeInfo.GetBaseClass(this.Emitter), this.Emitter);
                }
                else
                {
                    name = BridgeTypes.ToJsName(baseType, this.Emitter);
                }

                string baseMethod;
                bool   isIgnoreGeneric = false;
                if (resolveResult is InvocationResolveResult)
                {
                    InvocationResolveResult invocationResult = (InvocationResolveResult)resolveResult;
                    baseMethod      = OverloadsCollection.Create(this.Emitter, invocationResult.Member).GetOverloadName();
                    isIgnoreGeneric = Helpers.IsIgnoreGeneric(invocationResult.Member, this.Emitter);
                }
                else if (resolveResult is MemberResolveResult)
                {
                    MemberResolveResult memberResult = (MemberResolveResult)resolveResult;
                    baseMethod      = OverloadsCollection.Create(this.Emitter, memberResult.Member).GetOverloadName();
                    isIgnoreGeneric = Helpers.IsIgnoreGeneric(memberResult.Member, this.Emitter);
                }
                else
                {
                    baseMethod = targetMember.MemberName;
                    baseMethod = this.Emitter.AssemblyInfo.PreserveMemberCase ? baseMethod : Object.Net.Utilities.StringUtils.ToLowerCamelCase(baseMethod);
                }

                this.Write(name, "." + JS.Fields.PROTOTYPE + ".", baseMethod);

                this.WriteCall();
                this.WriteOpenParentheses();
                this.WriteThis();
                this.Emitter.Comma = true;
                if (!isIgnore && !isIgnoreGeneric && argsInfo.HasTypeArguments)
                {
                    new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                }

                needComma = false;

                foreach (var arg in argsExpressions)
                {
                    if (arg == null)
                    {
                        continue;
                    }

                    this.EnsureComma(false);

                    if (needComma)
                    {
                        this.WriteComma();
                    }

                    needComma = true;
                    arg.AcceptVisitor(this.Emitter);
                }
                this.Emitter.Comma = false;
                this.WriteCloseParentheses();
            }
            else
            {
                var dynamicResolveResult = this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter) as DynamicInvocationResolveResult;

                if (dynamicResolveResult != null)
                {
                    var group = dynamicResolveResult.Target as MethodGroupResolveResult;

                    if (group != null && group.Methods.Count() > 1)
                    {
                        throw new EmitterException(invocationExpression, "Cannot compile this dynamic invocation because there are two or more method overloads with the same parameter count. To work around this limitation, assign the dynamic value to a non-dynamic variable before use or call a method with different parameter count");
                    }
                }

                var     targetResolveResult     = this.Emitter.Resolver.ResolveNode(invocationExpression.Target, this.Emitter);
                var     invocationResolveResult = targetResolveResult as MemberResolveResult;
                IMethod method = null;

                if (invocationResolveResult != null)
                {
                    method = invocationResolveResult.Member as IMethod;
                }

                if (this.IsEmptyPartialInvoking(method) || IsConditionallyRemoved(invocationExpression, method))
                {
                    this.Emitter.SkipSemiColon           = true;
                    this.Emitter.ReplaceAwaiterByVar     = oldValue;
                    this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
                    return;
                }

                bool isIgnore = method != null && method.DeclaringTypeDefinition != null && this.Emitter.Validator.IsIgnoreType(method.DeclaringTypeDefinition);

                bool needExpand = false;
                if (method != null)
                {
                    string paramsName = null;

                    var paramsParam = method.Parameters.FirstOrDefault(p => p.IsParams);
                    if (paramsParam != null)
                    {
                        paramsName = paramsParam.Name;
                    }

                    if (paramsName != null)
                    {
                        if (csharpInvocation != null && !csharpInvocation.IsExpandedForm)
                        {
                            needExpand = true;
                        }
                    }
                }

                int count = this.Emitter.Writers.Count;
                invocationExpression.Target.AcceptVisitor(this.Emitter);

                if (this.Emitter.Writers.Count > count)
                {
                    var writer = this.Emitter.Writers.Pop();

                    if (method != null && method.IsExtensionMethod)
                    {
                        StringBuilder savedBuilder = this.Emitter.Output;
                        this.Emitter.Output = new StringBuilder();
                        this.WriteThisExtension(invocationExpression.Target);
                        argsInfo.ThisArgument = this.Emitter.Output.ToString();
                        this.Emitter.Output   = savedBuilder;
                    }
                    else if (writer.ThisArg != null)
                    {
                        argsInfo.ThisArgument = writer.ThisArg;
                    }

                    new InlineArgumentsBlock(this.Emitter, argsInfo, writer.InlineCode)
                    {
                        IgnoreRange = writer.IgnoreRange
                    }.Emit();
                    var result = this.Emitter.Output.ToString();
                    this.Emitter.Output    = writer.Output;
                    this.Emitter.IsNewLine = writer.IsNewLine;
                    this.Write(result);

                    if (writer.Callback != null)
                    {
                        writer.Callback.Invoke();
                    }
                }
                else
                {
                    if (needExpand && isIgnore)
                    {
                        this.Write("." + JS.Funcs.APPLY);
                    }
                    int openPos = this.Emitter.Output.Length;
                    this.WriteOpenParentheses();

                    bool isIgnoreGeneric  = false;
                    var  invocationResult = targetResolve as InvocationResolveResult;

                    if (invocationResult != null)
                    {
                        isIgnoreGeneric = Helpers.IsIgnoreGeneric(invocationResult.Member, this.Emitter);
                    }

                    if (needExpand && isIgnore)
                    {
                        StringBuilder savedBuilder = this.Emitter.Output;
                        this.Emitter.Output = new StringBuilder();
                        this.WriteThisExtension(invocationExpression.Target);
                        var thisArg = this.Emitter.Output.ToString();
                        this.Emitter.Output = savedBuilder;

                        this.Write(thisArg);

                        this.Emitter.Comma = true;

                        if (!isIgnore && !isIgnoreGeneric && argsInfo.HasTypeArguments)
                        {
                            new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                        }

                        this.EnsureComma(false);

                        if (argsExpressions.Length > 1)
                        {
                            this.WriteOpenBracket();
                            new ExpressionListBlock(this.Emitter, argsExpressions.Take(argsExpressions.Length - 1).ToArray(), paramsArg, invocationExpression, openPos).Emit();
                            this.WriteCloseBracket();
                            this.Write(".concat(");
                            new ExpressionListBlock(this.Emitter, new Expression[] { argsExpressions[argsExpressions.Length - 1] }, paramsArg, invocationExpression, openPos).Emit();
                            this.Write(")");
                        }
                        else
                        {
                            new ExpressionListBlock(this.Emitter, argsExpressions, paramsArg, invocationExpression, -1).Emit();
                        }
                    }
                    else
                    {
                        this.Emitter.Comma = false;
                        if (!isIgnore && !isIgnoreGeneric && argsInfo.HasTypeArguments)
                        {
                            new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                        }

                        if (invocationExpression.Arguments.Count > 0)
                        {
                            this.EnsureComma(false);
                        }

                        new ExpressionListBlock(this.Emitter, argsExpressions, paramsArg, invocationExpression, openPos).Emit();
                    }

                    this.WriteCloseParentheses();
                }
            }

            Helpers.CheckValueTypeClone(this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter), invocationExpression, this, pos);

            this.Emitter.ReplaceAwaiterByVar     = oldValue;
            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
        }
Пример #3
0
        private static JObject ConstructConstructorInfo(IMethod constructor, IEmitter emitter, bool includeDeclaringType, bool isGenericSpecialization, SyntaxTree tree)
        {
            var properties = MetadataUtils.GetCommonMemberInfoProperties(constructor, emitter, includeDeclaringType, isGenericSpecialization, tree);

            if (Helpers.IsNonScriptable(constructor))
            {
                return(null);
            }

            properties.Add("t", (int)MemberTypes.Constructor);
            if (constructor.Parameters.Count > 0)
            {
                properties.Add("p", new JArray(constructor.Parameters.Select(p => new JRaw(MetadataUtils.GetTypeName(p.Type, emitter, isGenericSpecialization)))));
            }

            var parametersInfo = constructor.Parameters.Select(p => MetadataUtils.ConstructParameterInfo(p, emitter, false, false, tree)).ToList();

            if (parametersInfo.Count > 0)
            {
                properties.Add("pi", new JArray(parametersInfo));
            }

            var        inline     = emitter.GetInline(constructor);
            var        typeDef    = constructor.DeclaringTypeDefinition;
            IAttribute customCtor = null;

            if (typeDef != null)
            {
                customCtor = emitter.Validator.GetAttribute(typeDef.Attributes, Translator.Bridge_ASSEMBLY + ".ConstructorAttribute");
            }

            if (string.IsNullOrEmpty(inline) && customCtor == null)
            {
                string sname;
                if (constructor.IsStatic || constructor.DeclaringType.Kind == TypeKind.Anonymous)
                {
                    sname = JS.Funcs.CONSTRUCTOR;
                }
                else
                {
                    sname = OverloadsCollection.Create(emitter, constructor).GetOverloadName();
                }

                properties.Add("sn", sname);
            }

            if (constructor.IsStatic)
            {
                properties.Add("sm", true);
            }

            if (string.IsNullOrEmpty(inline) && constructor.Attributes.Any(a => a.AttributeType.FullName == "Bridge.ExpandParamsAttribute"))
            {
                properties.Add("exp", true);
            }

            if (!string.IsNullOrEmpty(inline))
            {
                var block     = new InlineArgumentsBlock(emitter, new ArgumentsInfo(emitter, constructor), inline, constructor);
                var oldWriter = block.SaveWriter();
                block.NewWriter();
                block.EmitFunctionReference(true);
                var str = emitter.Output.ToString();
                block.RestoreWriter(oldWriter);

                properties.Add("def", new JRaw(str));
            }
            else if (customCtor != null)
            {
                inline = customCtor.PositionalArguments[0].ConstantValue.ToString();
                if (Regex.Match(inline, @"\s*\{\s*\}\s*").Success)
                {
                    var names = constructor.Parameters.Select(p => p.Name);

                    StringBuilder sb = new StringBuilder("function (" + string.Join(", ", names.ToArray()) + ") { return {");

                    bool needComma = false;
                    foreach (var name in names)
                    {
                        if (needComma)
                        {
                            sb.Append(", ");
                        }

                        needComma = true;

                        sb.Append(name + ": " + name);
                    }
                    sb.Append("};}");
                    properties.Add("def", new JRaw(sb.ToString()));
                }
                else
                {
                    var block     = new InlineArgumentsBlock(emitter, new ArgumentsInfo(emitter, constructor), inline, constructor);
                    var oldWriter = block.SaveWriter();
                    block.NewWriter();
                    block.EmitFunctionReference(true);
                    var str = emitter.Output.ToString();
                    block.RestoreWriter(oldWriter);

                    properties.Add("def", new JRaw(str));
                }
            }

            return(properties);
        }
Пример #4
0
        public static JObject ConstructMemberInfo(IMember m, IEmitter emitter, bool includeDeclaringType, bool isGenericSpecialization, SyntaxTree tree)
        {
            if (m is IMethod && ((IMethod)m).IsConstructor)
            {
                return(MetadataUtils.ConstructConstructorInfo((IMethod)m, emitter, includeDeclaringType, isGenericSpecialization, tree));
            }

            var properties = MetadataUtils.GetCommonMemberInfoProperties(m, emitter, includeDeclaringType, isGenericSpecialization, tree);

            if (m.IsStatic)
            {
                properties.Add("is", true);
            }

            if (m is IMethod)
            {
                var method = (IMethod)m;
                var inline = emitter.GetInline(method);

                if (string.IsNullOrEmpty(inline) && method.Attributes.Any(a => a.AttributeType.FullName == "Bridge.ExpandParamsAttribute"))
                {
                    properties.Add("exp", true);
                }

                properties.Add("t", (int)MemberTypes.Method);

                var parametersInfo = method.Parameters.Select(p => MetadataUtils.ConstructParameterInfo(p, emitter, false, false, tree)).ToList();
                if (parametersInfo.Count > 0)
                {
                    properties.Add("pi", new JArray(parametersInfo));
                }

                if (!string.IsNullOrEmpty(inline))
                {
                    if (inline.StartsWith("<self>"))
                    {
                        inline = inline.Substring(6);
                    }

                    var block     = new InlineArgumentsBlock(emitter, new ArgumentsInfo(emitter, method), inline, method);
                    var oldWriter = block.SaveWriter();
                    block.NewWriter();
                    block.EmitFunctionReference(true);
                    var str = emitter.Output.ToString();

                    block.RestoreWriter(oldWriter);
                    properties.Add("tpc", method.TypeParameters.Count);
                    properties.Add("def", new JRaw(str));
                }
                else
                {
                    if (MetadataUtils.IsJsGeneric(method, emitter))
                    {
                        properties.Add("tpc", method.TypeParameters.Count);
                        properties.Add("tprm", new JArray(method.TypeParameters.Select(tp => tp.Name).ToArray()));
                    }

                    string sname;
                    if (method.IsAccessor)
                    {
                        if (method.AccessorOwner is IProperty)
                        {
                            sname = Helpers.GetPropertyRef(method.AccessorOwner, emitter, ((IProperty)method.AccessorOwner).Setter == method);
                        }
                        else if (method.AccessorOwner is IEvent)
                        {
                            sname = Helpers.GetEventRef(method.AccessorOwner, emitter, ((IEvent)method.AccessorOwner).RemoveAccessor == method);
                        }
                        else
                        {
                            sname = OverloadsCollection.Create(emitter, method).GetOverloadName();
                        }
                    }
                    else
                    {
                        sname = OverloadsCollection.Create(emitter, method).GetOverloadName();
                    }

                    properties.Add("sn", sname);
                }
                properties.Add("rt", new JRaw(MetadataUtils.GetTypeName(method.ReturnType, emitter, isGenericSpecialization)));

                var attr = MetadataUtils.GetScriptableAttributes(method.ReturnTypeAttributes, emitter, tree).ToList();
                if (attr.Count > 0)
                {
                    JArray attrArr = new JArray();
                    foreach (var a in attr)
                    {
                        attrArr.Add(MetadataUtils.ConstructAttribute(a, null, emitter));
                    }

                    properties.Add("rta", attrArr);
                }

                if (method.Parameters.Count > 0)
                {
                    properties.Add("p", new JArray(method.Parameters.Select(p => new JRaw(MetadataUtils.GetTypeName(p.Type, emitter, isGenericSpecialization)))));
                }
            }
            else if (m is IField)
            {
                var field = (IField)m;

                properties.Add("t", (int)MemberTypes.Field);
                properties.Add("rt", new JRaw(MetadataUtils.GetTypeName(field.ReturnType, emitter, isGenericSpecialization)));
                properties.Add("sn", OverloadsCollection.Create(emitter, field).GetOverloadName());
                if (field.IsReadOnly)
                {
                    properties.Add("ro", field.IsReadOnly);
                }
            }
            else if (m is IProperty)
            {
                var prop = (IProperty)m;
                properties.Add("t", (int)MemberTypes.Property);
                properties.Add("rt", new JRaw(MetadataUtils.GetTypeName(prop.ReturnType, emitter, isGenericSpecialization)));
                if (prop.Parameters.Count > 0)
                {
                    properties.Add("p", new JArray(prop.Parameters.Select(p => new JRaw(MetadataUtils.GetTypeName(p.Type, emitter, isGenericSpecialization)))));
                }

                if (prop.IsIndexer)
                {
                    properties.Add("i", true);
                }

                if (prop.IsIndexer)
                {
                    if (prop.Getter != null)
                    {
                        var parametersInfo = prop.Getter.Parameters.Select(p => MetadataUtils.ConstructParameterInfo(p, emitter, false, false, tree)).ToList();
                        if (parametersInfo.Count > 0)
                        {
                            properties.Add("ipi", new JArray(parametersInfo));
                        }
                    }
                    else if (prop.Setter != null)
                    {
                        var parametersInfo = prop.Setter.Parameters.Take(prop.Setter.Parameters.Count - 1).Select(p => MetadataUtils.ConstructParameterInfo(p, emitter, false, false, tree)).ToList();
                        if (parametersInfo.Count > 0)
                        {
                            properties.Add("ipi", new JArray(parametersInfo));
                        }
                    }
                }

                var inlineGetter = prop.CanGet && (emitter.GetInline(prop.Getter) != null || Helpers.IsScript(prop.Getter));
                var inlineSetter = prop.CanSet && (emitter.GetInline(prop.Setter) != null || Helpers.IsScript(prop.Setter));

                if (inlineGetter || inlineSetter || prop.IsIndexer)
                {
                    if (prop.CanGet)
                    {
                        properties.Add("g", MetadataUtils.ConstructMemberInfo(prop.Getter, emitter, includeDeclaringType, isGenericSpecialization, tree));
                    }

                    if (prop.CanSet)
                    {
                        properties.Add("s", MetadataUtils.ConstructMemberInfo(prop.Setter, emitter, includeDeclaringType, isGenericSpecialization, tree));
                    }
                }
                else
                {
                    var fieldName = OverloadsCollection.Create(emitter, prop).GetOverloadName();
                    if (prop.CanGet)
                    {
                        properties.Add("g", MetadataUtils.ConstructFieldPropertyAccessor(prop.Getter, emitter, fieldName, true, includeDeclaringType, isGenericSpecialization, tree));
                    }
                    if (prop.CanSet)
                    {
                        properties.Add("s", MetadataUtils.ConstructFieldPropertyAccessor(prop.Setter, emitter, fieldName, false, includeDeclaringType, isGenericSpecialization, tree));
                    }

                    properties.Add("fn", fieldName);
                }
            }
            else if (m is IEvent)
            {
                var evt = (IEvent)m;

                properties.Add("t", (int)MemberTypes.Event);
                properties.Add("ad", MetadataUtils.ConstructMemberInfo(evt.AddAccessor, emitter, includeDeclaringType, isGenericSpecialization, tree));
                properties.Add("r", MetadataUtils.ConstructMemberInfo(evt.RemoveAccessor, emitter, includeDeclaringType, isGenericSpecialization, tree));
            }
            else
            {
                throw new ArgumentException("Invalid member " + m);
            }

            return(properties);
        }
Пример #5
0
        protected void VisitInvocationExpression()
        {
            InvocationExpression invocationExpression = this.InvocationExpression;
            int pos      = this.Emitter.Output.Length;
            var oldValue = this.Emitter.ReplaceAwaiterByVar;
            var oldAsyncExpressionHandling = this.Emitter.AsyncExpressionHandling;

            if (this.Emitter.IsAsync && !this.Emitter.AsyncExpressionHandling)
            {
                this.WriteAwaiters(invocationExpression);
                this.Emitter.ReplaceAwaiterByVar     = true;
                this.Emitter.AsyncExpressionHandling = true;
            }

            Tuple <bool, bool, string> inlineInfo = this.Emitter.GetInlineCode(invocationExpression);
            var argsInfo = new ArgumentsInfo(this.Emitter, invocationExpression);

            var argsExpressions = argsInfo.ArgumentsExpressions;
            var paramsArg       = argsInfo.ParamsExpression;
            var argsCount       = argsExpressions.Count();

            if (inlineInfo != null)
            {
                bool   isStaticMethod = inlineInfo.Item1;
                bool   isInlineMethod = inlineInfo.Item2;
                string inlineScript   = inlineInfo.Item3;

                if (isInlineMethod)
                {
                    if (invocationExpression.Arguments.Count > 0)
                    {
                        var code             = invocationExpression.Arguments.First();
                        var inlineExpression = code as PrimitiveExpression;

                        if (inlineExpression == null)
                        {
                            throw new EmitterException(invocationExpression, "Only primitive expression can be inlined");
                        }

                        string value = inlineExpression.Value.ToString().Trim();

                        if (value.Length > 0)
                        {
                            value = InlineArgumentsBlock.ReplaceInlineArgs(this, inlineExpression.Value.ToString(), invocationExpression.Arguments.Skip(1).ToArray());
                            this.Write(value);

                            if (value[value.Length - 1] == ';')
                            {
                                this.Emitter.EnableSemicolon = false;
                                this.WriteNewLine();
                            }
                        }
                        else
                        {
                            // Empty string, emit nothing.
                            this.Emitter.EnableSemicolon = false;
                        }

                        this.Emitter.ReplaceAwaiterByVar     = oldValue;
                        this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                        return;
                    }
                }
                else
                {
                    MemberReferenceExpression targetMemberRef = invocationExpression.Target as MemberReferenceExpression;
                    bool isBase = targetMemberRef != null && targetMemberRef.Target is BaseReferenceExpression;

                    if (!String.IsNullOrEmpty(inlineScript) && (isBase || invocationExpression.Target is IdentifierExpression))
                    {
                        argsInfo.ThisArgument = "this";
                        bool noThis = !inlineScript.Contains("{this}");

                        if (!isStaticMethod && noThis)
                        {
                            this.WriteThis();
                            this.WriteDot();
                        }

                        new InlineArgumentsBlock(this.Emitter, argsInfo, inlineScript).Emit();
                        this.Emitter.ReplaceAwaiterByVar     = oldValue;
                        this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                        return;
                    }
                }
            }

            MemberReferenceExpression targetMember = invocationExpression.Target as MemberReferenceExpression;

            ResolveResult targetMemberResolveResult = null;

            if (targetMember != null)
            {
                targetMemberResolveResult = this.Emitter.Resolver.ResolveNode(targetMember.Target, this.Emitter);
            }

            if (targetMember != null)
            {
                var member = this.Emitter.Resolver.ResolveNode(targetMember.Target, this.Emitter);

                //var targetResolve = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter);
                var targetResolve = this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter);

                if (targetResolve != null)
                {
                    var csharpInvocation = targetResolve as CSharpInvocationResolveResult;

                    InvocationResolveResult invocationResult;
                    bool isExtensionMethodInvocation = false;
                    if (csharpInvocation != null)
                    {
                        if (member != null && member.Type.Kind == TypeKind.Delegate && !csharpInvocation.IsExtensionMethodInvocation)
                        {
                            throw new EmitterException(invocationExpression, "Delegate's methods are not supported. Please use direct delegate invoke.");
                        }

                        if (csharpInvocation.IsExtensionMethodInvocation)
                        {
                            invocationResult            = csharpInvocation;
                            isExtensionMethodInvocation = true;
                            var resolvedMethod = invocationResult.Member as IMethod;
                            if (resolvedMethod != null && resolvedMethod.IsExtensionMethod)
                            {
                                string inline   = this.Emitter.GetInline(resolvedMethod);
                                bool   isNative = this.IsNativeMethod(resolvedMethod);

                                if (string.IsNullOrWhiteSpace(inline) && isNative)
                                {
                                    invocationResult = null;
                                }
                            }
                        }
                        else
                        {
                            invocationResult = null;
                        }

                        if (this.IsEmptyPartialInvoking(csharpInvocation.Member as IMethod))
                        {
                            this.Emitter.SkipSemiColon           = true;
                            this.Emitter.ReplaceAwaiterByVar     = oldValue;
                            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                            return;
                        }
                    }
                    else
                    {
                        invocationResult = targetResolve as InvocationResolveResult;

                        if (invocationResult != null && this.IsEmptyPartialInvoking(invocationResult.Member as IMethod))
                        {
                            this.Emitter.SkipSemiColon           = true;
                            this.Emitter.ReplaceAwaiterByVar     = oldValue;
                            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                            return;
                        }
                    }

                    if (invocationResult == null)
                    {
                        invocationResult = this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter) as InvocationResolveResult;
                    }

                    if (invocationResult != null)
                    {
                        var resolvedMethod = invocationResult.Member as IMethod;

                        if (resolvedMethod != null && resolvedMethod.IsExtensionMethod)
                        {
                            string inline   = this.Emitter.GetInline(resolvedMethod);
                            bool   isNative = this.IsNativeMethod(resolvedMethod);

                            if (isExtensionMethodInvocation)
                            {
                                if (!string.IsNullOrWhiteSpace(inline))
                                {
                                    this.Write("");
                                    StringBuilder savedBuilder = this.Emitter.Output;
                                    this.Emitter.Output = new StringBuilder();
                                    this.WriteThisExtension(invocationExpression.Target);
                                    argsInfo.ThisArgument = this.Emitter.Output.ToString();
                                    this.Emitter.Output   = savedBuilder;
                                    new InlineArgumentsBlock(this.Emitter, argsInfo, inline).Emit();
                                }
                                else if (!isNative)
                                {
                                    var    overloads     = OverloadsCollection.Create(this.Emitter, resolvedMethod);
                                    string name          = BridgeTypes.ToJsName(resolvedMethod.DeclaringType, this.Emitter) + "." + overloads.GetOverloadName();
                                    var    isIgnoreClass = resolvedMethod.DeclaringTypeDefinition != null && this.Emitter.Validator.IsIgnoreType(resolvedMethod.DeclaringTypeDefinition);

                                    this.Write(name);

                                    if (!isIgnoreClass && argsInfo.HasTypeArguments)
                                    {
                                        this.WriteOpenParentheses();
                                        new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                                        this.WriteCloseParentheses();
                                    }

                                    this.WriteOpenParentheses();

                                    this.WriteThisExtension(invocationExpression.Target);

                                    if (invocationExpression.Arguments.Count > 0)
                                    {
                                        this.WriteComma();
                                    }

                                    new ExpressionListBlock(this.Emitter, argsExpressions, paramsArg, invocationExpression).Emit();

                                    this.WriteCloseParentheses();
                                }

                                if (!string.IsNullOrWhiteSpace(inline) || !isNative)
                                {
                                    this.Emitter.ReplaceAwaiterByVar     = oldValue;
                                    this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                                    return;
                                }
                            }
                            else if (isNative)
                            {
                                if (!string.IsNullOrWhiteSpace(inline))
                                {
                                    this.Write("");
                                    StringBuilder savedBuilder = this.Emitter.Output;
                                    this.Emitter.Output = new StringBuilder();
                                    this.WriteThisExtension(invocationExpression.Target);
                                    argsInfo.ThisArgument = this.Emitter.Output.ToString();
                                    this.Emitter.Output   = savedBuilder;
                                    new InlineArgumentsBlock(this.Emitter, argsInfo, inline).Emit();
                                }
                                else
                                {
                                    argsExpressions.First().AcceptVisitor(this.Emitter);
                                    this.WriteDot();
                                    string name = this.Emitter.GetEntityName(resolvedMethod);
                                    this.Write(name);
                                    this.WriteOpenParentheses();
                                    new ExpressionListBlock(this.Emitter, argsExpressions.Skip(1), paramsArg, invocationExpression).Emit();
                                    this.WriteCloseParentheses();
                                }

                                this.Emitter.ReplaceAwaiterByVar     = oldValue;
                                this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;

                                return;
                            }
                        }
                    }
                }
            }

            var proto = false;

            if (targetMember != null && targetMember.Target is BaseReferenceExpression)
            {
                var rr = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter) as MemberResolveResult;

                if (rr != null)
                {
                    proto = rr.IsVirtualCall;

                    /*var method = rr.Member as IMethod;
                     * if (method != null && method.IsVirtual)
                     * {
                     *  proto = true;
                     * }
                     * else
                     * {
                     *  var prop = rr.Member as IProperty;
                     *
                     *  if (prop != null && prop.IsVirtual)
                     *  {
                     *      proto = true;
                     *  }
                     * }*/
                }
            }

            if (proto)
            {
                var baseType = this.Emitter.GetBaseMethodOwnerTypeDefinition(targetMember.MemberName, targetMember.TypeArguments.Count);
                var method   = invocationExpression.GetParent <MethodDeclaration>();

                bool isIgnore = this.Emitter.Validator.IsIgnoreType(baseType);

                if (isIgnore)
                {
                    //throw (System.Exception)this.Emitter.CreateException(targetMember.Target, "Cannot call base method, because parent class code is ignored");
                }

                bool needComma = false;

                var resolveResult = this.Emitter.Resolver.ResolveNode(targetMember, this.Emitter);

                string name = null;

                if (this.Emitter.TypeInfo.GetBaseTypes(this.Emitter).Any())
                {
                    name = BridgeTypes.ToJsName(this.Emitter.TypeInfo.GetBaseClass(this.Emitter), this.Emitter);
                }
                else
                {
                    name = BridgeTypes.ToJsName(baseType, this.Emitter);
                }

                string baseMethod;

                if (resolveResult is InvocationResolveResult)
                {
                    InvocationResolveResult invocationResult = (InvocationResolveResult)resolveResult;
                    baseMethod = OverloadsCollection.Create(this.Emitter, invocationResult.Member).GetOverloadName();
                }
                else if (resolveResult is MemberResolveResult)
                {
                    MemberResolveResult memberResult = (MemberResolveResult)resolveResult;
                    baseMethod = OverloadsCollection.Create(this.Emitter, memberResult.Member).GetOverloadName();
                }
                else
                {
                    baseMethod = targetMember.MemberName;
                    baseMethod = this.Emitter.AssemblyInfo.PreserveMemberCase ? baseMethod : Object.Net.Utilities.StringUtils.ToLowerCamelCase(baseMethod);
                }

                this.Write(name, ".prototype.", baseMethod);

                if (!isIgnore && argsInfo.HasTypeArguments)
                {
                    this.WriteOpenParentheses();
                    new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                    this.WriteCloseParentheses();
                }

                this.WriteDot();

                this.Write("call");
                this.WriteOpenParentheses();

                this.WriteThis();
                needComma = true;

                foreach (var arg in argsExpressions)
                {
                    if (needComma)
                    {
                        this.WriteComma();
                    }

                    needComma = true;
                    arg.AcceptVisitor(this.Emitter);
                }

                this.WriteCloseParentheses();
            }
            else
            {
                var dynamicResolveResult = this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter) as DynamicInvocationResolveResult;

                if (dynamicResolveResult != null)
                {
                    var group = dynamicResolveResult.Target as MethodGroupResolveResult;

                    if (group != null && group.Methods.Count() > 1)
                    {
                        throw new EmitterException(invocationExpression, "Cannot compile this dynamic invocation because there are two or more method overloads with the same parameter count. To work around this limitation, assign the dynamic value to a non-dynamic variable before use or call a method with different parameter count");
                    }
                }

                var     targetResolveResult     = this.Emitter.Resolver.ResolveNode(invocationExpression.Target, this.Emitter);
                var     invocationResolveResult = targetResolveResult as MemberResolveResult;
                IMethod method = null;

                if (invocationResolveResult != null)
                {
                    method = invocationResolveResult.Member as IMethod;
                }

                if (this.IsEmptyPartialInvoking(method))
                {
                    this.Emitter.SkipSemiColon           = true;
                    this.Emitter.ReplaceAwaiterByVar     = oldValue;
                    this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
                    return;
                }

                int count = this.Emitter.Writers.Count;
                invocationExpression.Target.AcceptVisitor(this.Emitter);

                if (this.Emitter.Writers.Count > count)
                {
                    var tuple = this.Emitter.Writers.Pop();

                    if (method != null && method.IsExtensionMethod)
                    {
                        StringBuilder savedBuilder = this.Emitter.Output;
                        this.Emitter.Output = new StringBuilder();
                        this.WriteThisExtension(invocationExpression.Target);
                        argsInfo.ThisArgument = this.Emitter.Output.ToString();
                        this.Emitter.Output   = savedBuilder;
                    }

                    new InlineArgumentsBlock(this.Emitter, argsInfo, tuple.Item1).Emit();
                    var result = this.Emitter.Output.ToString();
                    this.Emitter.Output    = tuple.Item2;
                    this.Emitter.IsNewLine = tuple.Item3;
                    this.Write(result);
                }
                else
                {
                    var isIgnore = false;

                    if (method != null && method.DeclaringTypeDefinition != null && this.Emitter.Validator.IsIgnoreType(method.DeclaringTypeDefinition))
                    {
                        isIgnore = true;
                    }

                    if (!isIgnore && argsInfo.HasTypeArguments)
                    {
                        this.WriteOpenParentheses();
                        new TypeExpressionListBlock(this.Emitter, argsInfo.TypeArguments).Emit();
                        this.WriteCloseParentheses();
                    }

                    this.WriteOpenParentheses();
                    new ExpressionListBlock(this.Emitter, argsExpressions, paramsArg, invocationExpression).Emit();
                    this.WriteCloseParentheses();
                }
            }

            Helpers.CheckValueTypeClone(this.Emitter.Resolver.ResolveNode(invocationExpression, this.Emitter), invocationExpression, this, pos);

            this.Emitter.ReplaceAwaiterByVar     = oldValue;
            this.Emitter.AsyncExpressionHandling = oldAsyncExpressionHandling;
        }