Example #1
0
        public JsNode VisitVariableInitializer(VariableInitializer node)
        {
            var tLocal = node.Annotation <LocalResolveResult>();

            if (tLocal != null && tLocal.Type != null && tLocal.Type.Kind == TypeKind.Struct &&
                node.ToString() == node.NameToken.ToString() && node.NextSibling.ToString() == ";")
            {
                var tType = Type.GetType(tLocal.Type.FullName);
                //对于基本数据类型,不用new
                if (tType == null || !tType.IsPrimitive)
                {
                    var tTypeMember = new JsMemberExpression {
                        Name = tLocal.Type.FullName
                    };
                    var tCtorMember = new JsMemberExpression {
                        Name = "ctor", PreviousMember = tTypeMember
                    };
                    var tInvocation = new JsInvocationExpression {
                        Member = tCtorMember
                    };
                    var tNewObject = new JsNewObjectExpression {
                        Invocation = tInvocation
                    };
                    return(new JsVariableDeclarator
                    {
                        Name = node.Name,
                        Initializer = tNewObject,
                    });
                }
            }
            return(new JsVariableDeclarator {
                Name = node.Name, Initializer = VisitExpression(node.Initializer)
            });
        }
Example #2
0
        void TransformIntoBaseMethodCallIfNeeded(CSharpInvocationResolveResult res, JsInvocationExpression node2)
        {
            var target = res.TargetResult as ThisResolveResult;

            if (target != null && target.CausesNonVirtualInvocation) //base.
            {
                //var info = res.GetInfo();
                //var node = info.Nodes.FirstOrDefault();
                var ce = target.Type;// node.FindThisEntity();
                if (ce != null && Sk.IsExtJsType(ce.GetDefinitionOrArrayType()))
                {
                    node2.Member = Js.This().Member("callParent");
                    if (node2.Arguments.IsNotNullOrEmpty())
                    {
                        node2.Arguments = new List <JsExpression> {
                            Js.NewJsonArray(node2.Arguments.ToArray())
                        }
                    }
                    ;
                    //var me2 = (node2.Member as JsMemberExpression);
                    //me2.Name = "callParent";
                    return;
                }
                IMethod me2;
                var     me = res.Member;
                if (me is IProperty)
                {
                    me2 = ((IProperty)me).Getter;
                }
                else if (me is IMethod)
                {
                    me2 = (IMethod)res.Member;
                }
                else
                {
                    throw new Exception("Can't resolve method from member: " + res.Member);
                }
                var member = SkJs.EntityMethodToJsFunctionRef(me2);
                member       = member.Member("call");
                node2.Member = member;
                if (node2.Arguments == null)
                {
                    node2.Arguments = new List <JsExpression>();
                }
                node2.Arguments.Insert(0, Js.This());
            }
        }

        void ProcessByRefs1()
        {
            ByRefs       = new List <ByReferenceResolveResult>();
            ByRefIndexes = new List <int>();
            RefToRefs    = new List <int>();
            var c = 0;

            foreach (var bin in PrmBindings)
            {
                var binding = bin.Binding;
                var byRef   = binding.CallResult as ByReferenceResolveResult;
                if (byRef == null)
                {
                    c++;
                    continue;
                }
                var x = byRef.ElementResult as LocalResolveResult;
                if (x != null && x.Variable != null && x.Variable.Type.Kind == TypeKind.ByReference)
                {
                    if (binding.Parameter.IsRef || binding.Parameter.IsOut)
                    {
                        RefToRefs.Add(c);
                    }
                    c++;
                    continue;
                }
                ByRefs.Add(byRef);
                ByRefIndexes.Add(c);
                c++;
            }
        }

        void ProcessByRefs2()
        {
            var c = 0;

            for (var i = 0; i < Node2.Arguments.Count; i++)
            {
                if (Node2.Arguments[i] is JsMemberExpression)
                {
                    JsMemberExpression jsmex = Node2.Arguments[i] as JsMemberExpression;
                    if (RefToRefs.Contains(i))
                    {
                        Node2.Arguments[i] = jsmex.PreviousMember; //remove the .Value ref wrapper
                    }
                    else if (ByRefIndexes.Contains(i))
                    {
                        Node2.Arguments[i] = Js.Member(RefIndexToName(c));
                        c++;
                    }
                }
                else if (Node2.Arguments[i] is JsIndexerAccessExpression)
                {
                    if (ByRefIndexes.Contains(i))
                    {
                        Node2.Arguments[i] = Js.Member(RefIndexToName(c));
                        c++;
                    }
                }
            }
        }

        void ProcessByRefs3()
        {
            if (ByRefs.IsNotNullOrEmpty())
            {
                var func = Js.Function();

                //It must assigned to a temporary variable, because typed arrays do not acceppt json.
                //调整原来使用临时对象.Value的赋值方式,修改为Object.defineProperty定义get|set方法的实现
                //临时对象统一调用jsclr里的$Ref方法进行创建
                for (var i = 0; i < ByRefs.Count; i++)
                {
                    var byRef = ByRefs[i];
                    var expr  = VisitExpression(byRef);
                    if (expr is JsMemberExpression)
                    {
                        var memberExpr = expr as JsMemberExpression;
                        if (memberExpr.PreviousMember != null)
                        {
                            var refFuncInvoke = new JsInvocationExpression
                            {
                                Member = new JsMemberExpression {
                                    Name = "$Ref"
                                },
                                Arguments = new List <JsExpression> {
                                    memberExpr.PreviousMember, Js.String(memberExpr.Name)
                                }
                            };
                            func.Add(Js.Var(RefIndexToName(i), refFuncInvoke).Statement());
                        }
                        else
                        {
                            //如果是局部变量的话使用旧实现方式
                            var refFuncInvoke = new JsInvocationExpression
                            {
                                Member = new JsMemberExpression {
                                    Name = "$Ref"
                                },
                                Arguments = new List <JsExpression> {
                                    Js.Member("null"), memberExpr
                                }
                            };
                            func.Add(Js.Var(RefIndexToName(i), refFuncInvoke).Statement());
                        }
                    }
                    else if (expr is JsIndexerAccessExpression)
                    {
                        var indexerExpr   = expr as JsIndexerAccessExpression;
                        var indexArg      = indexerExpr.Arguments[0];
                        var refFuncInvoke = new JsInvocationExpression
                        {
                            Member = new JsMemberExpression {
                                Name = "$Ref"
                            },
                            Arguments = new List <JsExpression> {
                                indexerExpr.Member, indexArg
                            }
                        };
                        func.Add(Js.Var(RefIndexToName(i), refFuncInvoke).Statement());
                    }
                }

                func.Add(Js.Var("$res", Node2).Statement());

                for (var i = 0; i < ByRefs.Count; i++)
                {
                    var byRef      = ByRefs[i];
                    var memberExpr = VisitExpression(byRef) as JsMemberExpression;
                    if (memberExpr != null && memberExpr.PreviousMember == null)
                    {
                        func.Add(memberExpr.Assign(Js.Member(RefIndexToName(i)).Member("Value")).Statement());
                    }
                }

                func.Add(Js.Return(Js.Member("$res")));
                Node2 = Importer.WrapFunctionAndInvoke(Res, func);
            }
        }
Example #3
0
        public JsNode VisitInvocationResolveResult(CSharpInvocationResolveResult res)
        {
            Res = res;

            ProcessMember();

            if (MethodAtt != null && MethodAtt.InlineCode != null)
            {
                return(Js.CodeExpression(MethodAtt.InlineCode));
            }

            var conditional = ProcessConditional();

            if (conditional)
            {
                return(null);
            }

            bool omittedCalls;
            var  omittedCallsNode = ProcessOmitCalls(out omittedCalls);

            if (omittedCalls)
            {
                return(omittedCallsNode);
            }

            JsMember = SkJs.EntityToMember(Member);

            qiucw.CheckAddInvocation(res, JsMember.Name);

            ProcessTarget();

            ProcessPrmBindings();

            ProcessNativeParams();

            ProcessByRefs1();

            PrmBindings.ForEach(t => t.JsCallResult = VisitExpression(t.Binding.CallResult));
            Node2 = new JsInvocationExpression
            {
                Member    = JsMember,
                Arguments = PrmBindings.Select(t => t.JsCallResult).ToList(),
            };

            ProcessByRefs2();

            ProcessExtensionImplementedInInstance();

            TransformIntoBaseMethodCallIfNeeded(Res, Node2);

            ProcessArgsCustomization();

            ProcessGenericMethodArgs();

            var inlineCodeExpression = ProcessInlineCodeExpression();

            if (inlineCodeExpression != null)
            {
                return(inlineCodeExpression);
            }



            var omittedDotOperator = ProcessOmitDotOperator();

            if (omittedDotOperator != null)
            {
                return(omittedDotOperator);
            }

            ProcessRemoveEmptyPreviousMemberName();

            var indexerAccess = ProcessIndexer();

            if (indexerAccess != null)
            {
                return(indexerAccess);
            }

            ProcessByRefs3();

            return(Node2);
        }
Example #4
0
        public static StringSegment ParseJsToken(this StringSegment literal, out JsToken token, bool filterExpression)
        {
            literal = literal.AdvancePastWhitespace();

            if (literal.IsNullOrEmpty())
            {
                token = null;
                return(literal);
            }

            var c = literal.GetChar(0);

            if (c == '(')
            {
                literal = literal.Advance(1);
                literal = literal.ParseJsExpression(out var bracketsExpr);
                literal = literal.AdvancePastWhitespace();

                c = literal.GetChar(0);
                if (c == ')')
                {
                    literal = literal.Advance(1);
                    token   = bracketsExpr;
                    return(literal);
                }

                throw new SyntaxErrorException($"Expected ')' but instead found '{c}': {literal.SubstringWithElipsis(0, 50)}");
            }

            token = null;
            c     = (char)0;

            if (literal.IsNullOrEmpty())
            {
                return(TypeConstants.EmptyStringSegment);
            }

            var i = 0;

            literal = literal.AdvancePastWhitespace();

            var firstChar = literal.GetChar(0);

            if (firstChar == '\'' || firstChar == '"' || firstChar == '`' || firstChar == '′')
            {
                i = 1;
                var hasEscapeChar = false;
                while (i < literal.Length && ((c = literal.GetChar(i)) != firstChar || literal.GetChar(i - 1) == '\\'))
                {
                    i++;
                    if (!hasEscapeChar)
                    {
                        hasEscapeChar = c == '\\';
                    }
                }

                if (i >= literal.Length || literal.GetChar(i) != firstChar)
                {
                    throw new SyntaxErrorException($"Unterminated string literal: {literal}");
                }

                var str = literal.Substring(1, i - 1);
                token = new JsLiteral(str);

                if (hasEscapeChar)
                {
                    var sb = StringBuilderCache.Allocate();
                    for (var j = 0; j < str.Length; j++)
                    {
                        // strip the back-slash used to escape quote char in strings
                        var ch = str[j];
                        if (ch != '\\' || (j + 1 >= str.Length || str[j + 1] != firstChar))
                        {
                            sb.Append(ch);
                        }
                    }
                    token = new JsLiteral(StringBuilderCache.ReturnAndFree(sb));
                }

                return(literal.Advance(i + 1));
            }
            if (firstChar >= '0' && firstChar <= '9')
            {
                i = 1;
                var hasExponent = false;
                var hasDecimal  = false;

                while (i < literal.Length && IsNumericChar(c = literal.GetChar(i)) ||
                       (hasExponent = (c == 'e' || c == 'E')))
                {
                    if (c == '.')
                    {
                        hasDecimal = true;
                    }

                    i++;

                    if (hasExponent)
                    {
                        i += 2; // [e+1]0

                        while (i < literal.Length && IsNumericChar(literal.GetChar(i)))
                        {
                            i++;
                        }

                        break;
                    }
                }

                var numLiteral = literal.Subsegment(0, i);

                //don't convert into ternary to avoid Type coercion
                if (hasDecimal || hasExponent)
                {
                    token = new JsLiteral(numLiteral.TryParseDouble(out double d) ? d : default(double));
                }
                else
                {
                    token = new JsLiteral(numLiteral.ParseSignedInteger());
                }

                return(literal.Advance(i));
            }
            if (firstChar == '{')
            {
                var props = new List <JsProperty>();

                literal = literal.Advance(1);
                while (!literal.IsNullOrEmpty())
                {
                    literal = literal.AdvancePastWhitespace();
                    if (literal.GetChar(0) == '}')
                    {
                        literal = literal.Advance(1);
                        break;
                    }

                    literal = literal.ParseJsToken(out var mapKeyToken);

                    if (!(mapKeyToken is JsLiteral) && !(mapKeyToken is JsIdentifier))
                    {
                        throw new SyntaxErrorException($"'{mapKeyToken}' is not a valid Object key, expected literal or identifier.");
                    }

                    JsToken mapValueToken;
                    bool    shorthand = false;

                    literal = literal.AdvancePastWhitespace();
                    if (literal.Length > 0 && literal.GetChar(0) == ':')
                    {
                        literal = literal.Advance(1);
                        literal = literal.ParseJsExpression(out mapValueToken);
                    }
                    else
                    {
                        shorthand = true;
                        if (literal.Length == 0 || (c = literal.GetChar(0)) != ',' && c != '}')
                        {
                            throw new SyntaxErrorException($"Unterminated object literal near: {literal.SubstringWithElipsis(0, 50)}");
                        }

                        mapValueToken = mapKeyToken;
                    }

                    props.Add(new JsProperty(mapKeyToken, mapValueToken, shorthand));

                    literal = literal.AdvancePastWhitespace();
                    if (literal.IsNullOrEmpty())
                    {
                        break;
                    }

                    if (literal.GetChar(0) == '}')
                    {
                        literal = literal.Advance(1);
                        break;
                    }

                    literal = literal.AdvancePastChar(',');
                    literal = literal.AdvancePastWhitespace();
                }

                token = new JsObjectExpression(props);
                return(literal);
            }
            if (firstChar == '[')
            {
                literal = literal.ParseArguments(out var elements, termination: ']');

                token = new JsArrayExpression(elements);
                return(literal);
            }
            if (firstChar.IsOperatorChar())
            {
                if (literal.StartsWith(">="))
                {
                    token = JsGreaterThanEqual.Operator;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("<="))
                {
                    token = JsLessThanEqual.Operator;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("!=="))
                {
                    token = JsStrictNotEquals.Operator;
                    return(literal.Advance(3));
                }
                if (literal.StartsWith("!="))
                {
                    token = JsNotEquals.Operator;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("==="))
                {
                    token = JsStrictEquals.Operator;
                    return(literal.Advance(3));
                }
                if (literal.StartsWith("=="))
                {
                    token = JsEquals.Operator;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("||"))
                {
                    token = JsOr.Operator;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("&&"))
                {
                    token = JsAnd.Operator;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith("<<"))
                {
                    token = JsBitwiseLeftShift.Operator;
                    return(literal.Advance(2));
                }
                if (literal.StartsWith(">>"))
                {
                    token = JsBitwiseRightShift.Operator;
                    return(literal.Advance(2));
                }

                switch (firstChar)
                {
                case '>':
                    token = JsGreaterThan.Operator;
                    return(literal.Advance(1));

                case '<':
                    token = JsLessThan.Operator;
                    return(literal.Advance(1));

                case '=':
                    token = JsAssignment.Operator;
                    return(literal.Advance(1));

                case '!':
                    token = JsNot.Operator;
                    return(literal.Advance(1));

                case '+':
                    token = JsAddition.Operator;
                    return(literal.Advance(1));

                case '-':
                    token = JsSubtraction.Operator;
                    return(literal.Advance(1));

                case '*':
                    token = JsMultiplication.Operator;
                    return(literal.Advance(1));

                case '/':
                    token = JsDivision.Operator;
                    return(literal.Advance(1));

                case '&':
                    token = JsBitwiseAnd.Operator;
                    return(literal.Advance(1));

                case '|':
                    token = JsBitwiseOr.Operator;
                    return(literal.Advance(1));

                case '^':
                    token = JsBitwiseXOr.Operator;
                    return(literal.Advance(1));

                case '%':
                    token = JsMod.Operator;
                    return(literal.Advance(1));

                default:
                    throw new SyntaxErrorException($"Invalid Operator found near: '{literal.SubstringWithElipsis(0, 50)}'");
                }
            }

            // identifier
            var preIdentifierLiteral = literal;

            literal = literal.ParseIdentifier(out var node);

            literal = literal.AdvancePastWhitespace();
            if (!literal.IsNullOrEmpty())
            {
                c = literal.GetChar(i);
                if (c == '.' || c == '[')
                {
                    while (true)
                    {
                        literal = literal.Advance(1);

                        if (c == '.')
                        {
                            literal = literal.AdvancePastWhitespace();
                            literal = literal.ParseIdentifier(out var property);
                            node    = new JsMemberExpression(node, property, computed: false);
                        }
                        else if (c == '[')
                        {
                            literal = literal.AdvancePastWhitespace();
                            literal = literal.ParseJsExpression(out var property);
                            node    = new JsMemberExpression(node, property, computed: true);

                            literal = literal.AdvancePastWhitespace();
                            if (literal.IsNullOrEmpty() || literal.GetChar(0) != ']')
                            {
                                throw new SyntaxErrorException($"Expected ']' but was '{literal.GetChar(0)}'");
                            }

                            literal = literal.Advance(1);
                        }

                        literal = literal.AdvancePastWhitespace();

                        if (literal.IsNullOrWhiteSpace())
                        {
                            break;
                        }

                        c = literal.GetChar(0);
                        if (c == '(')
                        {
                            throw new SyntaxErrorException("Call expression found on member expression. Only filters can be invoked.");
                        }

                        if (!(c == '.' || c == '['))
                        {
                            break;
                        }
                    }
                }
                else if (c == '(' || (filterExpression && c == ':'))
                {
                    literal = preIdentifierLiteral.ParseJsCallExpression(out var callExpr, filterExpression: filterExpression);
                    token   = callExpr;
                    return(literal);
                }
            }

            token = node;
            return(literal);
        }
Example #5
0
 /// <summary>
 /// Equalses the specified other.
 /// </summary>
 /// <param name="other">The other.</param>
 /// <returns><c>true</c> if XXXX, <c>false</c> otherwise.</returns>
 protected bool Equals(JsMemberExpression other)
 {
     return(Equals(Object, other.Object) &&
            Equals(Property, other.Property) &&
            Computed == other.Computed);
 }