private static void GenerateIndexerExpression(ScriptGenerator generator, MemberSymbol symbol, IndexerExpression expression)
        {
            ScriptTextWriter writer = generator.Writer;

            if (expression.Indexer.IsIntrinsic) {
                GenerateExpression(generator, symbol, expression.ObjectReference);
                writer.Write("[");
                GenerateExpressionList(generator, symbol, expression.Indices);
                writer.Write("]");
            }
            else if (expression.ObjectReference is BaseExpression) {
                Debug.Assert(symbol.Parent is ClassSymbol);

                writer.Write(((ClassSymbol)symbol.Parent).FullGeneratedName);
                writer.Write(".callBaseMethod(this, 'get_");
                writer.Write(expression.Indexer.GeneratedName);
                writer.Write("',");
                writer.WriteTrimmed(" [ ");
                GenerateExpressionList(generator, symbol, expression.Indices);
                writer.WriteTrimmed(" ])");
            }
            else {
                GenerateExpression(generator, expression.Indexer, expression.ObjectReference);
                writer.Write(".get_");
                writer.Write(expression.Indexer.GeneratedName);
                writer.Write("(");
                GenerateExpressionList(generator, expression.Indexer, expression.Indices);
                writer.Write(")");
            }
        }
Example #2
0
        private Expression ProcessOpenBracketsExpressionNode(BinaryExpressionNode node) {
            Expression leftExpression = BuildExpression(node.LeftChild);
            if (leftExpression is MemberExpression) {
                leftExpression = TransformMemberExpression((MemberExpression)leftExpression);
            }

            Debug.Assert((leftExpression.EvaluatedType.Type == SymbolType.Class) ||
                         (leftExpression.EvaluatedType.Type == SymbolType.Record) ||
                         (leftExpression.EvaluatedType.Type == SymbolType.Interface));

            IndexerSymbol indexer = null;
            if (leftExpression.EvaluatedType.Type != SymbolType.Interface) {
                indexer = ((ClassSymbol)leftExpression.EvaluatedType).GetIndexer();
            }
            else {
                indexer = ((InterfaceSymbol)leftExpression.EvaluatedType).Indexer;
            }
            Debug.Assert(indexer != null);
            Debug.Assert(indexer.MatchFilter(leftExpression.MemberMask));

            IndexerExpression indexerExpression = new IndexerExpression(leftExpression, indexer);

            Debug.Assert(node.RightChild is ExpressionListNode);
            ICollection<Expression> args = BuildExpressionList((ExpressionListNode)node.RightChild);

            foreach (Expression paramExpr in args) {
                indexerExpression.AddIndexParameterValue(paramExpr);
            }

            return indexerExpression;
        }
Example #3
0
        private Expression ProcessOpenParenExpressionNode(BinaryExpressionNode node) {
            bool isDelegateInvoke = false;
            Expression leftExpression = BuildExpression(node.LeftChild);

            if (leftExpression is LocalExpression) {
                Debug.Assert(leftExpression.EvaluatedType.Type == SymbolType.Delegate);

                // Handle the implicit delegate invoke scenario by turning the expression
                // into an explicit call into the delegate's Invoke method

                MemberSymbol invokeMethodSymbol = leftExpression.EvaluatedType.GetMember("Invoke");
                Debug.Assert(invokeMethodSymbol != null);

                leftExpression = new MemberExpression(leftExpression, invokeMethodSymbol);
                isDelegateInvoke = true;
            }

            if (leftExpression.Type != ExpressionType.Member) {
                // A method call was evaluated into a non-member expression as part of building
                // the left node. For example, Nullable<T>.GetValueOrDefault() becomes a logical or expression.

                return leftExpression;
            }

            MemberExpression memberExpression = (MemberExpression)leftExpression;

            ExpressionListNode argNodes = null;
            List<Expression> args = null;
            if (node.RightChild != null) {
                Debug.Assert(node.RightChild is ExpressionListNode);

                argNodes = (ExpressionListNode)node.RightChild;
                args = BuildExpressionList(argNodes);
            }

            MethodExpression methodExpression = null;

            if (memberExpression.Member.Type != SymbolType.Method) {
                // A non-method member is being used in a method call; the member must be
                // a delegate...
                Debug.Assert(memberExpression.EvaluatedType.Type == SymbolType.Delegate);
                Expression instanceExpression = TransformMemberExpression(memberExpression);

                MethodSymbol invokeMethod =
                    (MethodSymbol)memberExpression.EvaluatedType.GetMember("Invoke");
                Debug.Assert(invokeMethod != null);

                methodExpression = new MethodExpression(instanceExpression, invokeMethod);
                isDelegateInvoke = true;
            }
            else {
                // The member being accessed is a method...

                // REVIEW: Uggh... this has become too complex over time with all the transformations
                //         added over time. Refactoring needed...

                MethodSymbol method = (MethodSymbol)memberExpression.Member;
                TypeSymbol objectType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Object);
                TypeSymbol typeType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Type);
                TypeSymbol dictionaryType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Dictionary);
                TypeSymbol genericDictionaryType = _symbolSet.ResolveIntrinsicType(IntrinsicType.GenericDictionary);
                TypeSymbol numberType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Number);
                TypeSymbol stringType = _symbolSet.ResolveIntrinsicType(IntrinsicType.String);
                TypeSymbol scriptType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Script);
                TypeSymbol argsType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Arguments);

                if ((method.Parent == objectType) &&
                    method.Name.Equals("GetType", StringComparison.Ordinal)) {
                    // Since we can't extend object's prototype, we need to transform the
                    // natural c# syntax into a static method.
                    // Object.GetType instance method becomes Type.GetInstanceType static method

                    TypeSymbol typeSymbol = typeType;

                    method = (MethodSymbol)typeSymbol.GetMember("GetInstanceType");
                    Debug.Assert(method != null);

                    methodExpression = new MethodExpression(new TypeExpression(typeSymbol, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                            method);
                    methodExpression.AddParameterValue(memberExpression.ObjectReference);
                    return methodExpression;
                }
                else if ((method.Parent == objectType) &&
                         (method.Name.Equals("ToString", StringComparison.Ordinal) ||
                          method.Name.Equals("ToLocaleString", StringComparison.Ordinal)) &&
                         (memberExpression.ObjectReference.EvaluatedType == stringType)) {
                    // No-op ToString calls on strings (this happens when performing a ToString
                    // on a named enum value.
                    return memberExpression.ObjectReference;
                }
                else if ((method.Parent == objectType) &&
                         (method.Name.Equals("ToString", StringComparison.Ordinal) ||
                          method.Name.Equals("ToLocaleString", StringComparison.Ordinal)) &&
                         (memberExpression.ObjectReference.EvaluatedType is EnumerationSymbol)) {
                    EnumerationSymbol enumSymbol = (EnumerationSymbol)memberExpression.ObjectReference.EvaluatedType;

                    if (enumSymbol.UseNamedValues) {
                        // If the enum value is a named enum, then it is already a string.
                        return memberExpression.ObjectReference;
                    }

                    return new MethodExpression(memberExpression.ObjectReference, method);
                }
                else if (((method.Parent == dictionaryType) || (method.Parent == genericDictionaryType)) &&
                         method.Name.Equals("ContainsKey", StringComparison.Ordinal)) {
                    // Switch the instance ContainsKey method on Dictionary to
                    // calls to the static KeyExists method.
                    Debug.Assert(args.Count == 1);

                    MethodSymbol keyExistsMethod = (MethodSymbol)dictionaryType.GetMember("KeyExists");
                    Debug.Assert(keyExistsMethod != null);

                    methodExpression = new MethodExpression(new TypeExpression(dictionaryType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                            keyExistsMethod);
                    methodExpression.AddParameterValue(memberExpression.ObjectReference);
                    methodExpression.AddParameterValue(args[0]);

                    return methodExpression;
                }
                else if (((method.Parent == dictionaryType) || (method.Parent == genericDictionaryType)) &&
                         method.Name.Equals("Remove", StringComparison.Ordinal)) {
                    // Switch the instance Remove method on Dictionary to
                    // calls to the static DeleteKey method.
                    Debug.Assert(args.Count == 1);

                    return new LateBoundExpression(memberExpression.ObjectReference,
                                                   args[0], LateBoundOperation.DeleteField,
                                                   objectType);
                }
                else if (((method.Parent == dictionaryType) || (method.Parent == genericDictionaryType)) &&
                         method.Name.Equals("Clear")) {
                    // Switch the instance Clear method on Dictionary to
                    // calls to the static ClearKeys method.
                    MethodSymbol clearKeysMethod = (MethodSymbol)dictionaryType.GetMember("ClearKeys");
                    Debug.Assert(clearKeysMethod != null);

                    methodExpression = new MethodExpression(new TypeExpression(dictionaryType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                            clearKeysMethod);
                    methodExpression.AddParameterValue(memberExpression.ObjectReference);
                    return methodExpression;
                }
                else if (((method.Parent == dictionaryType) || (((TypeSymbol)method.Parent).GenericType == genericDictionaryType)) &&
                         ((method.Visibility & MemberVisibility.Static) != 0) &&
                         method.Name.Equals("GetDictionary", StringComparison.Ordinal)) {
                    // Dictionary.GetDictionary is a no-op method; we're just interested
                    // in the object being passed in.
                    // However we'll re-evaluate the argument to be of dictionary type
                    // so that subsequent use of this expression sees it as a dictionary.
                    Debug.Assert(args.Count == 1);
                    args[0].Reevaluate((TypeSymbol)method.Parent);

                    return args[0];
                }
                else if ((method.Parent == stringType) &&
                         (method.Name.Equals("Escape", StringComparison.Ordinal) ||
                          method.Name.Equals("Unescape", StringComparison.Ordinal) ||
                          method.Name.Equals("EncodeUri", StringComparison.Ordinal) ||
                          method.Name.Equals("DecodeUri", StringComparison.Ordinal) ||
                          method.Name.Equals("EncodeUriComponent", StringComparison.Ordinal) ||
                          method.Name.Equals("DecodeUriComponent", StringComparison.Ordinal))) {
                    // String.<Method> becomes Script.<Method>, as its a global method in script
                    MethodSymbol scriptMethod = (MethodSymbol)scriptType.GetMember(method.Name);

                    methodExpression = new MethodExpression(new TypeExpression(scriptType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                            scriptMethod);
                    methodExpression.AddParameterValue(memberExpression.ObjectReference);
                    return methodExpression;
                }
                else if ((method.Parent == scriptType) &&
                         method.Name.Equals("Literal", StringComparison.Ordinal)) {
                    // Convert a call to Script.Literal into a literal expression

                    Debug.Assert(args.Count >= 1);
                    string script = null;

                    if (args[0].Type == ExpressionType.Field) {
                        Debug.Assert(args[0].EvaluatedType == stringType);

                        FieldSymbol field = ((FieldExpression)args[0]).Field;
                        if (field.IsConstant) {
                            Debug.Assert(field.Value is string);
                            script = (string)field.Value;
                        }
                    }
                    else if (args[0].Type == ExpressionType.Literal) {
                        Debug.Assert(((LiteralExpression)args[0]).Value is string);
                        script = (string)((LiteralExpression)args[0]).Value;
                    }

                    if (script == null) {
                        // TODO: When we start raising errors at the expression level instead of the statement
                        //       level, we should return an ErrorExpression instead of a dummy expression.
                        Token argToken = argNodes.Expressions[0].Token;

                        _errorHandler.ReportError("The argument to Script.Literal must be a constant string.",
                                                  argToken.Location);
                        return new InlineScriptExpression("", objectType);
                    }

                    InlineScriptExpression scriptExpression = new InlineScriptExpression(script, objectType);
                    for (int i = 1; i < args.Count; i++) {
                        scriptExpression.AddParameterValue(args[i]);
                    }

                    return scriptExpression;
                }
                else if ((method.Parent == scriptType) &&
                         method.Name.Equals("Boolean", StringComparison.Ordinal)) {
                    Debug.Assert(args.Count == 1);

                    return new UnaryExpression(Operator.LogicalNot, new UnaryExpression(Operator.LogicalNot, args[0]));
                }
                else if ((method.Parent == scriptType) &&
                         method.Name.Equals("Value", StringComparison.Ordinal)) {
                    Debug.Assert(args.Count >= 2);

                    Expression expr = args[0];
                    for (int i = 1; i < args.Count; i++) {
                        expr = new BinaryExpression(Operator.LogicalOr, expr, args[i]);
                    }

                    expr.Reevaluate(args[0].EvaluatedType);
                    expr.AddParenthesisHint();

                    return expr;
                }
                else if (method.Parent == argsType) {
                    if (method.Name.Equals("GetArgument", StringComparison.Ordinal)) {
                        // Switch Arguments.GetArgument into Arguments[]
                        Debug.Assert(args.Count == 1);

                        IndexerExpression indexExpression =
                            new IndexerExpression(new LiteralExpression(typeType, method.Parent),
                                                  ((ClassSymbol)method.Parent).GetIndexer());
                        indexExpression.AddIndexParameterValue(args[0]);

                        return indexExpression;
                    }
                    else if (method.Name.Equals("ToArray", StringComparison.Ordinal)) {
                        // Switch Arguments.ToArray into Array.ToArray(arguments)

                        TypeSymbol arrayType = _symbolSet.ResolveIntrinsicType(IntrinsicType.Array);
                        MethodSymbol toArrayMethod = (MethodSymbol)arrayType.GetMember("ToArray");

                        InlineScriptExpression argsExpression =
                            new InlineScriptExpression("arguments", objectType, /* parenthesize */ false);
                        MethodExpression toArrayExpression =
                            new MethodExpression(new TypeExpression(arrayType, SymbolFilter.Public | SymbolFilter.StaticMembers),
                                                 toArrayMethod);
                        toArrayExpression.AddParameterValue(argsExpression);

                        return toArrayExpression;
                    }
                }
                else {
                    bool lateBound = false;

                    if (method.Parent == scriptType) {
                        LateBoundOperation lateBoundOperation = LateBoundOperation.InvokeMethod;

                        if (method.Name.Equals("InvokeMethod", StringComparison.Ordinal)) {
                            lateBound = true;
                        }
                        else if (method.Name.Equals("DeleteField", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.DeleteField;
                        }
                        else if (method.Name.Equals("GetField", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.GetField;
                        }
                        else if (method.Name.Equals("SetField", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.SetField;
                        }
                        else if (method.Name.Equals("GetScriptType", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.GetScriptType;
                        }
                        else if (method.Name.Equals("HasField", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.HasField;
                        }
                        else if (method.Name.Equals("HasMethod", StringComparison.Ordinal)) {
                            lateBound = true;
                            lateBoundOperation = LateBoundOperation.HasMethod;
                        }
                        else if (method.Name.Equals("CreateInstance", StringComparison.Ordinal)) {
                            Debug.Assert(args.Count >= 1);

                            if ((args[0].Type == ExpressionType.MethodInvoke) ||
                                (args[0].Type == ExpressionType.PropertyGet)) {
                                // When using the result of a method call/property access directly
                                // with Type.CreateInstance, the following script would be generated:
                                //
                                // new method()()
                                // which is invalid. Instead we need to generate the following:
                                // var type = method();
                                // new type()

                                _errorHandler.ReportError("You must store the type returned from a method or property into a local variable to use with Type.CreateInstance.",
                                                          node.Token.Location);
                            }

                            NewExpression newExpression = new NewExpression(args[0], objectType);
                            if (args.Count > 1) {
                                bool first = true;
                                foreach (Expression paramExpr in args) {
                                    if (first) {
                                        first = false;
                                        continue;
                                    }
                                    newExpression.AddParameterValue(paramExpr);
                                }
                            }
                            return newExpression;
                        }

                        if (lateBound) {
                            // Switch explicit late-bound calls into implicit late-bound expressions
                            // in script
                            Debug.Assert((args != null) &&
                                         (((lateBoundOperation == LateBoundOperation.GetScriptType) && (args.Count == 1)) ||
                                          (args.Count >= 2)));

                            LateBoundExpression lateBoundExpression = null;
                            Expression instanceExpression = null;
                            Expression nameExpression = null;

                            foreach (Expression paramExpr in args) {
                                if (instanceExpression == null) {
                                    instanceExpression = paramExpr;

                                    if (lateBoundOperation == LateBoundOperation.GetScriptType) {
                                        // GetScriptType only takes an instance
                                        return new LateBoundExpression(instanceExpression, null,
                                                                       lateBoundOperation, objectType);
                                    }
                                    continue;
                                }
                                if (nameExpression == null) {
                                    nameExpression = paramExpr;

                                    Expression objectExpression = instanceExpression;
                                    if (lateBoundOperation == LateBoundOperation.InvokeMethod) {
                                        if ((instanceExpression.Type == ExpressionType.Literal) &&
                                            (((LiteralExpression)instanceExpression).Value == null)) {
                                            objectExpression = null;

                                            LiteralExpression literalExpression = nameExpression as LiteralExpression;
                                            if (literalExpression == null) {
                                                _errorHandler.ReportError("The name of a global method must be a constant string known at compile time.",
                                                                          argNodes.Expressions[0].Token.Location);
                                            }
                                            else if (!Utility.IsValidIdentifier((string)literalExpression.Value)) {
                                                _errorHandler.ReportError("The name of a global method must be a valid identifer.",
                                                                          argNodes.Expressions[0].Token.Location);
                                            }
                                        }
                                    }

                                    lateBoundExpression = new LateBoundExpression(objectExpression, nameExpression,
                                                                                  lateBoundOperation, objectType);
                                    continue;
                                }

                                lateBoundExpression.AddParameterValue(paramExpr);
                            }

                            Debug.Assert(lateBoundExpression != null);
                            return lateBoundExpression;
                        }
                    }

                    if (!method.MatchesConditions(_options.Defines)) {
                        return null;
                    }

                    methodExpression = new MethodExpression(memberExpression.ObjectReference,
                                                            method);
                }
            }

            if (args != null) {
                foreach (Expression paramExpr in args) {
                    methodExpression.AddParameterValue(paramExpr);
                }
            }

            if (isDelegateInvoke) {
                return new DelegateInvokeExpression(methodExpression);
            }
            return methodExpression;
        }
        private static void GenerateIndexerExpression(ScriptGenerator generator, MemberSymbol symbol, IndexerExpression expression)
        {
            ScriptTextWriter writer = generator.Writer;

            if (expression.Indexer.UseScriptIndexer) {
                GenerateExpression(generator, symbol, expression.ObjectReference);
                writer.Write("[");
                GenerateExpressionList(generator, symbol, expression.Indices);
                writer.Write("]");
            }
            else if (expression.ObjectReference is BaseExpression) {
                writer.Write("ss.base(");
                writer.Write(generator.CurrentImplementation.ThisIdentifier);
                writer.Write(", 'get_");
                writer.Write(expression.Indexer.GeneratedName);
                writer.Write("').call(");
                writer.Write(generator.CurrentImplementation.ThisIdentifier);
                writer.Write(", ");
                GenerateExpressionList(generator, symbol, expression.Indices);
                writer.Write(")");
            }
            else {
                GenerateExpression(generator, expression.Indexer, expression.ObjectReference);
                writer.Write(".get_");
                writer.Write(expression.Indexer.GeneratedName);
                writer.Write("(");
                GenerateExpressionList(generator, expression.Indexer, expression.Indices);
                writer.Write(")");
            }
        }