예제 #1
0
        private JsExpression CompileImportedTypeCheckCode(IType type, ref JsExpression @this, IRuntimeContext context, bool isTypeIs)
        {
            var def = type.GetDefinition();

            if (def == null)
            {
                return(null);
            }
            var ia = AttributeReader.ReadAttribute <ImportedAttribute>(def);

            if (ia == null || string.IsNullOrEmpty(ia.TypeCheckCode))
            {
                return(null);
            }

            // Can ignore errors here because they are caught by the metadata importer
            var method    = MetadataUtils.CreateTypeCheckMethod(type, _compilation);
            var tokens    = InlineCodeMethodCompiler.Tokenize(method, ia.TypeCheckCode, _ => {});
            int thisCount = tokens.Count(t => t.Type == InlineCodeToken.TokenType.This);

            if (!isTypeIs || thisCount > 0)
            {
                @this = context.EnsureCanBeEvaluatedMultipleTimes(@this, new JsExpression[0]);
            }
            return(JsExpression.LogicalAnd(
                       ReferenceNotEquals(@this, JsExpression.Null, context),
                       InlineCodeMethodCompiler.CompileInlineCodeMethodInvocation(method, tokens, @this, EmptyList <JsExpression> .Instance, n => { var t = ReflectionHelper.ParseReflectionName(n).Resolve(_compilation); return t.Kind == TypeKind.Unknown ? JsExpression.Null : InstantiateType(t, context); }, t => InstantiateTypeForUseAsTypeArgumentInInlineCode(t, context), _ => {})));
        }
        private JsExpression CreateDefaultConstructorInvocation(IMethod defaultConstructor, JsExpression typeRef)
        {
            var sem = _metadataImporter.GetConstructorSemantics(defaultConstructor);

            switch (sem.Type)
            {
            case ConstructorScriptSemantics.ImplType.UnnamedConstructor:                      // default behavior is good enough.
            case ConstructorScriptSemantics.ImplType.NotUsableFromScript:                     // Can't be invoked so we don't need to create it.
                return(null);

            case ConstructorScriptSemantics.ImplType.NamedConstructor:
                return(JsExpression.New(JsExpression.Member(typeRef, sem.Name)));

            case ConstructorScriptSemantics.ImplType.StaticMethod:
                return(JsExpression.Invocation(JsExpression.Member(typeRef, sem.Name)));

            case ConstructorScriptSemantics.ImplType.InlineCode:
                var prevRegion = _errorReporter.Region;
                try {
                    _errorReporter.Region = defaultConstructor.Region;
                    return(InlineCodeMethodCompiler.CompileInlineCodeMethodInvocation(defaultConstructor, sem.LiteralCode, null, EmptyList <JsExpression> .Instance, r => r.Resolve(_compilation), _runtimeLibrary.GetScriptType, false, s => _errorReporter.Message(7525, s)));
                }
                finally {
                    _errorReporter.Region = prevRegion;
                }

            case ConstructorScriptSemantics.ImplType.Json:
                return(JsExpression.ObjectLiteral());

            default:
                throw new Exception("Invalid constructor implementation type: " + sem.Type);
            }
        }
예제 #3
0
        private void AddClassMembers(JsClass c, JsExpression typeRef, List <JsStatement> stmts)
        {
            if (c.InstanceMethods.Count > 0)
            {
                stmts.Add(new JsExpressionStatement(JsExpression.Assign(JsExpression.Member(typeRef, Prototype), JsExpression.ObjectLiteral(c.InstanceMethods.Select(m => new JsObjectLiteralProperty(m.Name, m.Definition != null ? RewriteMethod(m) : JsExpression.Null))))));
            }

            if (c.NamedConstructors.Count > 0)
            {
                stmts.AddRange(c.NamedConstructors.Select(m => new JsExpressionStatement(JsExpression.Assign(JsExpression.Member(typeRef, m.Name), m.Definition))));
                stmts.Add(new JsExpressionStatement(c.NamedConstructors.Reverse().Aggregate((JsExpression)JsExpression.Member(typeRef, Prototype), (right, ctor) => JsExpression.Assign(JsExpression.Member(JsExpression.Member(typeRef, ctor.Name), Prototype), right))));                     // This generates a statement like {C}.ctor1.prototype = {C}.ctor2.prototype = {C}.prototoype
            }

            var defaultConstructor = Saltarelle.Compiler.Utils.SelfParameterize(c.CSharpTypeDefinition).GetConstructors().SingleOrDefault(x => x.Parameters.Count == 0 && x.IsPublic);

            if (defaultConstructor != null)
            {
                var sem = _metadataImporter.GetConstructorSemantics(defaultConstructor);
                if (sem.Type != ConstructorScriptSemantics.ImplType.UnnamedConstructor && sem.Type != ConstructorScriptSemantics.ImplType.NotUsableFromScript)
                {
                    var createInstance = MetadataUtils.CompileConstructorInvocation(defaultConstructor, null, c.CSharpTypeDefinition, null, EmptyList <ResolveResult> .Instance, _compilation, _metadataImporter, _namer, _runtimeLibrary, _errorReporter, null, null);
                    stmts.Add(new JsExpressionStatement(
                                  JsExpression.Assign(
                                      JsExpression.Member(typeRef, "createInstance"),
                                      JsExpression.FunctionDefinition(new string[0], new JsBlockStatement(createInstance.AdditionalStatements.Concat(new[] { new JsReturnStatement(createInstance.Expression) }))))));
                }
            }

            stmts.AddRange(c.StaticMethods.Select(m => new JsExpressionStatement(JsExpression.Assign(JsExpression.Member(typeRef, m.Name), RewriteMethod(m)))));

            if (MetadataUtils.IsSerializable(c.CSharpTypeDefinition))
            {
                string typeCheckCode = MetadataUtils.GetSerializableTypeCheckCode(c.CSharpTypeDefinition);
                if (!string.IsNullOrEmpty(typeCheckCode))
                {
                    var oldReg = _errorReporter.Region;
                    _errorReporter.Region = c.CSharpTypeDefinition.Attributes.Single(a => a.AttributeType.FullName == typeof(SerializableAttribute).FullName).Region;
                    var method = MetadataUtils.CreateTypeCheckMethod(Saltarelle.Compiler.Utils.SelfParameterize(c.CSharpTypeDefinition), _compilation);

                    var errors = new List <string>();
                    var tokens = InlineCodeMethodCompiler.Tokenize(method, typeCheckCode, errors.Add);
                    if (errors.Count == 0)
                    {
                        var context = new DefaultRuntimeContext(c.CSharpTypeDefinition, _metadataImporter, _errorReporter, _namer);
                        var result  = InlineCodeMethodCompiler.CompileInlineCodeMethodInvocation(method, tokens, JsExpression.Identifier("obj"), new JsExpression[0],
                                                                                                 n => {
                            var type = ReflectionHelper.ParseReflectionName(n).Resolve(_compilation);
                            if (type.Kind == TypeKind.Unknown)
                            {
                                errors.Add("Unknown type '" + n + "' specified in inline implementation");
                                return(JsExpression.Null);
                            }
                            return(_runtimeLibrary.InstantiateType(type, context));
                        },
                                                                                                 t => _runtimeLibrary.InstantiateTypeForUseAsTypeArgumentInInlineCode(t, context),
                                                                                                 errors.Add);

                        stmts.Add(new JsExpressionStatement(
                                      JsExpression.Assign(
                                          JsExpression.Member(typeRef, "isInstanceOfType"),
                                          JsExpression.FunctionDefinition(new[] { "obj" }, new JsReturnStatement(result)))));

                        foreach (var e in errors)
                        {
                            _errorReporter.Message(Messages._7157, c.CSharpTypeDefinition.FullName, e);
                        }
                    }
                    _errorReporter.Region = oldReg;
                }
            }

            if (MetadataUtils.IsJsGeneric(c.CSharpTypeDefinition, _metadataImporter))
            {
                var args = new List <JsExpression> {
                    typeRef, new JsTypeReferenceExpression(c.CSharpTypeDefinition), JsExpression.ArrayLiteral(c.CSharpTypeDefinition.TypeParameters.Select(tp => JsExpression.Identifier(_namer.GetTypeParameterName(tp))))
                };
                if (c.CSharpTypeDefinition.Kind == TypeKind.Class)
                {
                    args.Add(JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(GetBaseClass(c.CSharpTypeDefinition) ?? JsExpression.Null)));
                }
                args.Add(JsExpression.FunctionDefinition(new string[0], new JsReturnStatement(JsExpression.ArrayLiteral(GetImplementedInterfaces(c.CSharpTypeDefinition)))));
                var metadata = GetMetadataDescriptor(c.CSharpTypeDefinition, true);
                if (metadata != null)
                {
                    args.Add(metadata);
                }
                stmts.Add(new JsExpressionStatement(JsExpression.Invocation(JsExpression.Member(_systemScript, c.CSharpTypeDefinition.Kind == TypeKind.Class ? RegisterGenericClassInstance : RegisterGenericInterfaceInstance), args)));
            }
        }