bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler)
        {
            CompilationUnitNode compilationUnitNode = (CompilationUnitNode)node;

            foreach (AttributeBlockNode attribBlock in compilationUnitNode.Attributes) {
                AttributeNode scriptNamespaceNode = AttributeNode.FindAttribute(attribBlock.Attributes, "ScriptNamespace");
                if (scriptNamespaceNode != null) {
                    string scriptNamespace = (string)((LiteralNode)scriptNamespaceNode.Arguments[0]).Value;

                    if (Utility.IsValidScriptNamespace(scriptNamespace) == false) {
                        errorHandler.ReportError("A script namespace must be a valid script identifier.",
                                                 scriptNamespaceNode.Token.Location);
                    }
                }
            }

            foreach (ParseNode childNode in compilationUnitNode.Members) {
                if (!(childNode is NamespaceNode)) {
                    errorHandler.ReportError("Non-namespaced types are not supported.",
                                             childNode.Token.Location);
                    return false;
                }
            }

            return true;
        }
예제 #2
0
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            NewNode newNode = (NewNode)node;

            // TODO: This is somewhat hacky - it only looks for any type named Dictionary
            //       rather than resolving the type and checking if its actually
            //       System.Dictionary.
            //       This is because validators don't have a reference to the SymbolSet.

            NameNode typeNode = newNode.TypeReference as NameNode;
            if ((typeNode != null) && (typeNode.Name.Equals("Dictionary"))) {
                if (newNode.Arguments != null) {
                    Debug.Assert(newNode.Arguments is ExpressionListNode);
                    ParseNodeList arguments = ((ExpressionListNode)newNode.Arguments).Expressions;

                    if (arguments.Count != 0) {
                        if (arguments.Count % 2 != 0) {
                            errorHandler.ReportError("Missing value parameter for the last name parameter in Dictionary instantiation.",
                                                     newNode.Token.Location);
                        }

                        for (int i = 0; i < arguments.Count; i += 2) {
                            ParseNode nameArgumentNode = arguments[i];
                            if ((nameArgumentNode.NodeType != ParseNodeType.Literal) ||
                                (((LiteralNode)nameArgumentNode).Literal.LiteralType != LiteralTokenType.String)) {
                                errorHandler.ReportError("Name parameters in Dictionary instantiation must be string literals.",
                                                         nameArgumentNode.Token.Location);
                            }
                        }
                    }
                }
            }

            return true;
        }
예제 #3
0
        public MetadataImporter(CompilerOptions options, IErrorHandler errorHandler) {
            Debug.Assert(options != null);
            Debug.Assert(errorHandler != null);

            _options = options;
            _errorHandler = errorHandler;
        }
예제 #4
0
 public ExpressionBuilder(ILocalSymbolTable symbolTable, FieldSymbol fieldContext, IErrorHandler errorHandler, CompilerOptions options) {
     _symbolTable = symbolTable;
     _symbolContext = fieldContext;
     _classContext = ((ClassSymbol)fieldContext.Parent).PrimaryPartialClass;
     _symbolSet = fieldContext.SymbolSet;
     _errorHandler = errorHandler;
     _options = options;
 }
예제 #5
0
        public StatementBuilder(ILocalSymbolTable symbolTable, CodeMemberSymbol memberContext, IErrorHandler errorHandler, CompilerOptions options) {
            _symbolTable = symbolTable;
            _memberContext = memberContext;
            _symbolSet = memberContext.SymbolSet;
            _errorHandler = errorHandler;

            _expressionBuilder = new ExpressionBuilder(symbolTable, memberContext, errorHandler, options);
        }
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler)
        {
            MethodDeclarationNode methodNode = (MethodDeclarationNode)node;

            if (((methodNode.Modifiers & Modifiers.Static) == 0) &&
                ((methodNode.Modifiers & Modifiers.New) != 0)) {
                errorHandler.ReportError("The new modifier is not supported on instance members.",
                                         methodNode.Token.Location);
                return false;
            }

            if ((methodNode.Modifiers & Modifiers.Extern) != 0) {
                AttributeNode altSigAttribute
                    = AttributeNode.FindAttribute(methodNode.Attributes, "AlternateSignature");
                if (altSigAttribute == null) {
                    errorHandler.ReportError("Extern methods should only be used to declare alternate signatures and marked with [AlternateSignature].",
                                             methodNode.Token.Location);
                    return false;
                }

                CustomTypeNode typeNode = (CustomTypeNode)methodNode.Parent;
                MethodDeclarationNode implMethodNode = null;

                if (methodNode.NodeType == ParseNodeType.MethodDeclaration) {
                    foreach (MemberNode memberNode in typeNode.Members) {
                        if ((memberNode.NodeType == ParseNodeType.MethodDeclaration) &&
                            ((memberNode.Modifiers & Modifiers.Extern) == 0) &&
                            memberNode.Name.Equals(methodNode.Name, StringComparison.Ordinal)) {
                            implMethodNode = (MethodDeclarationNode)memberNode;
                            break;
                        }
                    }
                }
                else if (methodNode.NodeType == ParseNodeType.ConstructorDeclaration) {
                    foreach (MemberNode memberNode in typeNode.Members) {
                        if ((memberNode.NodeType == ParseNodeType.ConstructorDeclaration) &&
                            ((memberNode.Modifiers & Modifiers.Extern) == 0)) {
                            implMethodNode = (MethodDeclarationNode)memberNode;
                            break;
                        }
                    }
                }

                if (implMethodNode == null) {
                    errorHandler.ReportError("Extern methods used to declare alternate signatures should have a corresponding non-extern implementation as well.",
                                             methodNode.Token.Location);
                    return false;
                }

                if ((methodNode.Modifiers & (Modifiers.Static | Modifiers.AccessMask)) !=
                    (implMethodNode.Modifiers & (Modifiers.Static | Modifiers.AccessMask))) {
                    errorHandler.ReportError("The implemenation method and associated alternate signature methods should have the same access type.",
                                             methodNode.Token.Location);
                }
            }

            return true;
        }
예제 #7
0
        public SimpleCompilation(string outputPath)
        {
            _references = new List<string>();
            _sources = new List<IStreamSource>();
            _output = new FileStreamSource(outputPath, writable: true);

            _options = new CompilerOptions();
            _options.Minimize = false;
        }
예제 #8
0
        public ScriptGenerator(TextWriter writer, CompilerOptions options, IErrorHandler errorHandler) {
            Debug.Assert(writer != null);
            _writer = new ScriptTextWriter(writer, options);

            _options = options;
            _errorHandler = errorHandler;

            _classes = new List<ClassSymbol>();
        }
예제 #9
0
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            NameNode nameNode = (NameNode)node;

            if (Utility.IsKeyword(nameNode.Name)) {
                errorHandler.ReportError(nameNode.Name + " is a reserved word.",
                                         nameNode.Token.Location);
            }

            return true;
        }
예제 #10
0
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            ArrayTypeNode typeNode = (ArrayTypeNode)node;

            if (typeNode.Rank != 1) {
                errorHandler.ReportError("Only single dimensional arrays are supported.",
                                         typeNode.Token.Location);
            }

            return true;
        }
예제 #11
0
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            TryNode tryNode = (TryNode)node;

            if ((tryNode.CatchClauses != null) && (tryNode.CatchClauses.Count > 1)) {
                errorHandler.ReportError("Try/Catch statements are limited to a single catch clause.",
                                         tryNode.Token.Location);
                return false;
            }

            return true;
        }
예제 #12
0
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            ParameterNode paramNode = (ParameterNode)node;

            if (paramNode.Flags != ParameterFlags.None) {
                errorHandler.ReportError("Out, Ref and Params style of parameters are not yet implemented.",
                                         paramNode.Token.Location);
                return false;
            }

            return true;
        }
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            FieldDeclarationNode fieldNode = (FieldDeclarationNode)node;

            if (fieldNode.Initializers.Count > 1) {
                errorHandler.ReportError("Field declarations are limited to a single field per declaration.",
                                         fieldNode.Token.Location);
                return false;
            }

            return true;
        }
예제 #14
0
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            ThrowNode throwNode = (ThrowNode)node;

            if (throwNode.Value == null) {
                errorHandler.ReportError("Throw statements must specify an exception object.",
                                         throwNode.Token.Location);
                return false;
            }

            return true;
        }
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            EventDeclarationNode eventNode = (EventDeclarationNode)node;

            if (((eventNode.Modifiers & Modifiers.Static) == 0) &&
                ((eventNode.Modifiers & Modifiers.New) != 0)) {
                errorHandler.ReportError("The new modifier is not supported on instance members.",
                                         eventNode.Token.Location);
                return false;
            }

            return true;
        }
예제 #16
0
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            ArrayNewNode newNode = (ArrayNewNode)node;

            if (newNode.ExpressionList != null) {
                Debug.Assert(newNode.ExpressionList.NodeType == ParseNodeType.ExpressionList);
                ExpressionListNode argsList = (ExpressionListNode)newNode.ExpressionList;

                if (argsList.Expressions.Count != 1) {
                    errorHandler.ReportError("Only single dimensional arrays are supported.",
                                             newNode.ExpressionList.Token.Location);
                }
            }

            return true;
        }
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            EnumerationFieldNode enumFieldNode = (EnumerationFieldNode)node;

            object fieldValue = enumFieldNode.Value;
            if (fieldValue == null) {
                errorHandler.ReportError("Enumeration fields must have an explicit constant value specified.",
                                         enumFieldNode.Token.Location);
                return false;
            }

            if ((fieldValue is long) || (fieldValue is ulong)) {
                errorHandler.ReportError("Enumeration fields cannot have long or ulong underlying type.",
                                         enumFieldNode.Token.Location);
            }

            return true;
        }
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            PropertyDeclarationNode propertyNode = (PropertyDeclarationNode)node;

            if (((propertyNode.Modifiers & Modifiers.Static) == 0) &&
                ((propertyNode.Modifiers & Modifiers.New) != 0)) {
                errorHandler.ReportError("The new modifier is not supported on instance members.",
                                         propertyNode.Token.Location);
                return false;
            }

            if (propertyNode.GetAccessor == null) {
                errorHandler.ReportError("Set-only properties are not supported. Use a set method instead.",
                                         propertyNode.Token.Location);
                return false;
            }

            return true;
        }
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            IndexerDeclarationNode indexerNode = (IndexerDeclarationNode)node;

            if ((indexerNode.Modifiers & Modifiers.New) != 0) {

                errorHandler.ReportError("The new modifier is not supported.",
                                         indexerNode.Token.Location);
                
                return false;
            }

            if (indexerNode.GetAccessor == null) {
                errorHandler.ReportError("Set-only properties are not supported. Use a set method instead.",
                                         indexerNode.Token.Location);
                return false;
            }

            return true;
        }
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler)
        {
            NamespaceNode namespaceNode = (NamespaceNode)node;

            bool valid = true;

            foreach (ParseNode childNode in namespaceNode.Members) {
                if (childNode is NamespaceNode) {
                    errorHandler.ReportError("Nested namespaces are not supported.",
                                             childNode.Token.Location);
                    valid = false;
                }
            }

            if (namespaceNode.Name.Equals("System") ||
                namespaceNode.Name.StartsWith("System.")) {

                // Usage of the System namespace is limited to imported types.

                foreach (ParseNode childNode in namespaceNode.Members) {
                    bool allowed = false;

                    if (childNode is UserTypeNode) {
                        ParseNodeList attributes = ((UserTypeNode)childNode).Attributes;
                        if (AttributeNode.FindAttribute(attributes, "ScriptImport") != null) {
                            allowed = true;
                        }
                    }

                    if (allowed == false) {
                        errorHandler.ReportError("Only types marked as Imported are allowed within the System namespace.",
                                                 namespaceNode.Token.Location);
                        valid = false;
                        break;
                    }
                }
            }

            return valid;
        }
예제 #21
0
        public bool Compile(CompilerOptions options)
        {
            if (options == null) {
                throw new ArgumentNullException("options");
            }
            _options = options;

            _hasErrors = false;
            _symbols = new SymbolSet();

            ImportMetadata();
            if (_hasErrors) {
                return false;
            }

            BuildCodeModel();
            if (_hasErrors) {
                return false;
            }

            BuildMetadata();
            if (_hasErrors) {
                return false;
            }

            BuildImplementation();
            if (_hasErrors) {
                return false;
            }

            GenerateScript();
            if (_hasErrors) {
                return false;
            }

            return true;
        }
예제 #22
0
        private static CompilerOptions CreateCompilerOptions(CommandLine commandLine)
        {
            List<string> references = new List<string>();
            List<IStreamSource> sources = new List<IStreamSource>();
            List<IStreamSource> resources = new List<IStreamSource>();
            List<string> defines = new List<string>();
            List<string> scripts = new List<string>();
            bool debug = false;
            bool includeTests = false;
            bool minimize = true;
            bool copyRefs = false;
            IStreamSource scriptFile = null;
            IStreamSource templateFile = null;
            IStreamSource docCommentFile = null;

            foreach (string fileName in commandLine.Arguments) {
                // TODO: This is a hack... something in the .net 4 build system causes
                //       generation of an AssemblyAttributes.cs file with fully-qualified
                //       type names, that we can't handle (this comes from multitargeting),
                //       and there doesn't seem like a way to turn it off.
                if (fileName.EndsWith(".AssemblyAttributes.cs", StringComparison.OrdinalIgnoreCase)) {
                    continue;
                }
                sources.Add(new FileInputStreamSource(fileName));
            }

            object referencesObject = commandLine.Options["ref"];
            if (referencesObject is string) {
                references.Add((string)referencesObject);
            }
            else if (referencesObject is ArrayList) {
                ArrayList referenceList = (ArrayList)referencesObject;

                foreach (string reference in referenceList) {
                    // TODO: This is a hack... something in the .net 4 build system causes
                    //       System.Core.dll to get included [sometimes].
                    //       That shouldn't happen... so filter it out here.
                    if (reference.EndsWith("System.Core.dll", StringComparison.OrdinalIgnoreCase)) {
                        continue;
                    }
                    references.Add(reference);
                }
            }

            object resourcesObject = commandLine.Options["res"];
            if (resourcesObject is string) {
                resources.Add(new FileInputStreamSource((string)resourcesObject));
            }
            else if (resourcesObject is ArrayList) {
                ArrayList resourceList = (ArrayList)resourcesObject;

                foreach (string resource in resourceList) {
                    resources.Add(new FileInputStreamSource(resource));
                }
            }

            object definesObject = commandLine.Options["D"];
            if (definesObject is string) {
                defines.Add((string)definesObject);
            }
            else if (definesObject is ArrayList) {
                ArrayList definesList = (ArrayList)definesObject;

                foreach (string definedVariable in definesList) {
                    defines.Add(definedVariable);
                }
            }

            string scriptFilePath = null;
            if (commandLine.Options.Contains("out")) {
                scriptFilePath = (string)commandLine.Options["out"];
                if (scriptFilePath.IndexOfAny(Path.GetInvalidPathChars()) < 0) {
                    scriptFile = new FileOutputStreamSource(scriptFilePath);
                }
            }

            if (commandLine.Options.Contains("template")) {
                templateFile = new FileInputStreamSource((string)commandLine.Options["template"], "Template");
            }

            if (commandLine.Options.Contains("doc")) {
                docCommentFile = new FileInputStreamSource((string)commandLine.Options["doc"], "DocComment");
            }

            debug = commandLine.Options.Contains("debug");
            if (debug && !defines.Contains("DEBUG")) {
                defines.Add("DEBUG");
            }

            includeTests = commandLine.Options.Contains("tests");
            minimize = commandLine.Options.Contains("minimize");
            copyRefs = commandLine.Options.Contains("copyRefs");

            CompilerOptions compilerOptions = new CompilerOptions();
            compilerOptions.DebugFlavor = debug;
            compilerOptions.IncludeTests = includeTests;
            compilerOptions.Defines = defines;
            compilerOptions.Minimize = minimize;
            compilerOptions.References = references;
            compilerOptions.Sources = sources;
            compilerOptions.Resources = resources;
            compilerOptions.ScriptFile = scriptFile;
            compilerOptions.TemplateFile = templateFile;
            compilerOptions.DocCommentFile = docCommentFile;
            compilerOptions.CopyReferences = copyRefs;

            compilerOptions.InternalTestMode = commandLine.Options.Contains("test");
            if (compilerOptions.InternalTestMode) {
                compilerOptions.InternalTestType = (string)commandLine.Options["test"];
            }

            return compilerOptions;
        }
예제 #23
0
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            CustomTypeNode typeNode = (CustomTypeNode)node;

            bool restrictToMethodMembers = false;
            bool hasCodeMembers = false;
            ParseNode codeMemberNode = null;

            AttributeNode importedTypeAttribute = AttributeNode.FindAttribute(typeNode.Attributes, "Imported");
            if (importedTypeAttribute != null) {
                // This is an imported type definition... we'll assume its valid, since
                // the set of restrictions for such types is fewer, and different, so
                // for now that translates into skipping the members.

                return false;
            }

            AttributeNode scriptNamespaceNode = AttributeNode.FindAttribute(typeNode.Attributes, "ScriptNamespace");
            if (scriptNamespaceNode != null) {
                string scriptNamespace = (string)((LiteralNode)scriptNamespaceNode.Arguments[0]).Value;

                if (Utility.IsValidScriptNamespace(scriptNamespace) == false) {
                    errorHandler.ReportError("A script namespace must be a valid script identifier.",
                                             scriptNamespaceNode.Token.Location);
                }
            }

            if (typeNode.Type == TokenType.Struct) {
                errorHandler.ReportError("Struct types are not supported. Use classes annotated with the Record metadata attribute.",
                                         typeNode.Token.Location);
                return false;
            }

            if (((typeNode.Modifiers & Modifiers.Partial) != 0) &&
                (typeNode.Type != TokenType.Class)) {
                errorHandler.ReportError("Partial types can only be classes, not enumerations or interfaces.",
                                         typeNode.Token.Location);
                return false;
            }

            if ((typeNode.Type == TokenType.Interface) &&
                (typeNode.BaseTypes.Count != 0)) {
                errorHandler.ReportError("Derived interface types are not supported.",
                                         typeNode.Token.Location);
                return false;
            }

            if (typeNode.Type == TokenType.Class) {
                if (typeNode.BaseTypes.Count != 0) {
                    NameNode baseTypeNameNode = typeNode.BaseTypes[0] as NameNode;

                    if (baseTypeNameNode != null) {
                        if (String.CompareOrdinal(baseTypeNameNode.Name, "Record") == 0) {
                            if ((typeNode.Modifiers & Modifiers.Sealed) == 0) {
                                errorHandler.ReportError("Classes derived from the Record base class must be marked as sealed.",
                                                         typeNode.Token.Location);
                            }

                            if (typeNode.BaseTypes.Count != 1) {
                                errorHandler.ReportError("Classes derived from the Record base class cannot implement interfaces.",
                                                         typeNode.Token.Location);
                            }
                        }
                        else if (String.CompareOrdinal(baseTypeNameNode.Name, "TestClass") == 0) {
                            if ((typeNode.Modifiers & Modifiers.Internal) == 0) {
                                errorHandler.ReportError("Classes derived from TestClass must be marked as internal.",
                                                         typeNode.Token.Location);
                            }
                            if ((typeNode.Modifiers & Modifiers.Static) != 0) {
                                errorHandler.ReportError("Classes derived from TestClass must not be marked as static.",
                                                         typeNode.Token.Location);
                            }
                            if ((typeNode.Modifiers & Modifiers.Sealed) == 0) {
                                errorHandler.ReportError("Classes derived from TestClass must be marked as sealed.",
                                                         typeNode.Token.Location);
                            }
                            if (typeNode.BaseTypes.Count != 1) {
                                errorHandler.ReportError("Classes derived from TestClass cannot implement interfaces.",
                                                         typeNode.Token.Location);
                            }
                        }
                    }
                }

                AttributeNode globalMethodsAttribute = AttributeNode.FindAttribute(typeNode.Attributes, "GlobalMethods");
                if (globalMethodsAttribute != null) {
                    restrictToMethodMembers = true;

                    if ((typeNode.Modifiers & Modifiers.Static) == 0) {
                        errorHandler.ReportError("GlobalMethods attribute can only be set on static classes.",
                                                 typeNode.Token.Location);
                    }
                }

                AttributeNode mixinAttribute = AttributeNode.FindAttribute(typeNode.Attributes, "Mixin");
                if (mixinAttribute != null) {
                    restrictToMethodMembers = true;

                    if ((typeNode.Modifiers & Modifiers.Static) == 0) {
                        errorHandler.ReportError("Mixin attribute can only be set on static classes.",
                                                 typeNode.Token.Location);
                    }
                }
            }

            if ((typeNode.Members != null) && (typeNode.Members.Count != 0)) {
                Dictionary<string, object> memberNames = new Dictionary<string, object>();
                bool hasCtor = false;

                foreach (ParseNode genericMemberNode in typeNode.Members) {
                    if (!(genericMemberNode is MemberNode)) {
                        errorHandler.ReportError("Only members are allowed inside types. Nested types are not supported.",
                                                 node.Token.Location);
                        continue;
                    }

                    MemberNode memberNode = (MemberNode)genericMemberNode;

                    if ((memberNode.Modifiers & Modifiers.Extern) != 0) {
                        // Extern methods are placeholders for creating overload signatures
                        continue;
                    }

                    if (restrictToMethodMembers &&
                        (memberNode.NodeType != ParseNodeType.MethodDeclaration) &&
                        (memberNode.NodeType != ParseNodeType.ConstructorDeclaration)) {
                        errorHandler.ReportError("Classes marked with GlobalMethods or Mixin attribute should only have methods.",
                                                 memberNode.Token.Location);
                    }

                    if (memberNode.NodeType == ParseNodeType.ConstructorDeclaration) {
                        if ((memberNode.Modifiers & Modifiers.Static) == 0) {
                            if (hasCtor) {
                                errorHandler.ReportError("Constructor overloads are not supported.",
                                                         memberNode.Token.Location);
                            }
                            hasCtor = true;
                        }
                        continue;
                    }
                    if (memberNode.NodeType == ParseNodeType.OperatorDeclaration) {
                        // Operators don't have a name
                        continue;
                    }

                    string name = memberNode.Name;
                    if (memberNames.ContainsKey(name)) {
                        errorHandler.ReportError("Duplicate-named member. Method overloads are not supported.",
                                                 memberNode.Token.Location);
                    }

                    memberNames[name] = null;

                    bool preserveCase = (AttributeNode.FindAttribute(memberNode.Attributes, "PreserveCase") != null);
                    if (Utility.IsKeyword(name, /* testCamelCase */ (preserveCase == false))) {
                        errorHandler.ReportError("Invalid member name. Member names should not use keywords.",
                                                 memberNode.Token.Location);
                    }
             
                    if (hasCodeMembers == false) {
                        hasCodeMembers = ((memberNode.NodeType == ParseNodeType.PropertyDeclaration) ||
                                          (memberNode.NodeType == ParseNodeType.MethodDeclaration) ||
                                          (memberNode.NodeType == ParseNodeType.EventDeclaration) ||
                                          (memberNode.NodeType == ParseNodeType.IndexerDeclaration));
                        codeMemberNode = memberNode;
                    }
                }
            }

            if ((typeNode.Type == TokenType.Struct) && hasCodeMembers) {
                errorHandler.ReportError("A struct type is limited to field and constructor members.",
                                         codeMemberNode.Token.Location);
            }

            return true;
        }
예제 #24
0
 public CodeModelBuilder(CompilerOptions options, IErrorHandler errorHandler) {
     _options = options;
     _errorHandler = errorHandler;
 }
예제 #25
0
        private Type GetValidatorType(ParseNodeType nodeType, CompilerOptions options) {
            switch (nodeType) {
                case ParseNodeType.CompilationUnit:
                    return typeof(CompilationUnitNodeValidator);
                case ParseNodeType.Namespace:
                    return typeof(NamespaceNodeValidator);
                case ParseNodeType.Name:
                case ParseNodeType.GenericName:
                    return typeof(NameNodeValidator);
                case ParseNodeType.Type:
                    return typeof(CustomTypeNodeValidator);
                case ParseNodeType.ArrayType:
                    return typeof(ArrayTypeNodeValidator);
                case ParseNodeType.FormalParameter:
                    return typeof(ParameterNodeValidator);
                case ParseNodeType.EnumerationFieldDeclaration:
                    return typeof(EnumerationFieldNodeValidator);
                case ParseNodeType.FieldDeclaration:
                case ParseNodeType.ConstFieldDeclaration:
                    return typeof(FieldDeclarationNodeValidator);
                case ParseNodeType.IndexerDeclaration:
                    return typeof(IndexerDeclarationNodeValidator);
                case ParseNodeType.PropertyDeclaration:
                    return typeof(PropertyDeclarationNodeValidator);
                case ParseNodeType.EventDeclaration:
                    return typeof(EventDeclarationNodeValidator);
                case ParseNodeType.MethodDeclaration:
                case ParseNodeType.ConstructorDeclaration:
                    return typeof(MethodDeclarationNodeValidator);
                case ParseNodeType.Throw:
                    return typeof(ThrowNodeValidator);
                case ParseNodeType.Try:
                    return typeof(TryNodeValidator);
                case ParseNodeType.ArrayNew:
                    return typeof(ArrayNewNodeValidator);
                case ParseNodeType.New:
                    return typeof(NewNodeValidator);
                case ParseNodeType.Catch:
                case ParseNodeType.ArrayInitializer:
                case ParseNodeType.Literal:
                case ParseNodeType.AttributeBlock:
                case ParseNodeType.Attribute:
                case ParseNodeType.AccessorDeclaration:
                case ParseNodeType.VariableDeclaration:
                case ParseNodeType.ConstDeclaration:
                case ParseNodeType.MultiPartName:
                case ParseNodeType.UsingNamespace:
                case ParseNodeType.PredefinedType:
                case ParseNodeType.UnaryExpression:
                case ParseNodeType.Conditional:
                case ParseNodeType.Block:
                case ParseNodeType.ExpressionStatement:
                case ParseNodeType.EmptyStatement:
                case ParseNodeType.VariableDeclarator:
                case ParseNodeType.IfElse:
                case ParseNodeType.Switch:
                case ParseNodeType.SwitchSection:
                case ParseNodeType.For:
                case ParseNodeType.Foreach:
                case ParseNodeType.While:
                case ParseNodeType.DoWhile:
                case ParseNodeType.CaseLabel:
                case ParseNodeType.DefaultLabel:
                case ParseNodeType.This:
                case ParseNodeType.Base:
                case ParseNodeType.Cast:
                case ParseNodeType.ExpressionList:
                case ParseNodeType.Break:
                case ParseNodeType.Continue:
                case ParseNodeType.Return:
                case ParseNodeType.Typeof:
                case ParseNodeType.Delegate:
                case ParseNodeType.UsingAlias:
                case ParseNodeType.AnonymousMethod:
                case ParseNodeType.BinaryExpression:
                    // No validation required
                    break;
                case ParseNodeType.PointerType:
                case ParseNodeType.OperatorDeclaration:
                case ParseNodeType.DestructorDeclaration:
                case ParseNodeType.Goto:
                case ParseNodeType.Lock:
                case ParseNodeType.UnsafeStatement:
                case ParseNodeType.YieldReturn:
                case ParseNodeType.YieldBreak:
                case ParseNodeType.LabeledStatement:
                case ParseNodeType.Checked:
                case ParseNodeType.Unchecked:
                case ParseNodeType.Using:
                case ParseNodeType.Sizeof:
                case ParseNodeType.Fixed:
                case ParseNodeType.StackAlloc:
                case ParseNodeType.DefaultValueExpression:
                case ParseNodeType.ExternAlias:
                case ParseNodeType.AliasQualifiedName:
                case ParseNodeType.TypeParameter:
                case ParseNodeType.ConstraintClause:
                    return typeof(UnsupportedParseNodeValidator);
                default:
                    Debug.Fail("Unexpected node type in validator: " + nodeType);
                    break;
            }

            return null;
        }
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler)
        {
            CustomTypeNode typeNode = (CustomTypeNode)node;

            bool extensionRestrictions = false;
            bool moduleRestrictions = false;
            bool recordRestrictions = false;
            bool hasCodeMembers = false;
            ParseNode codeMemberNode = null;

            AttributeNode importedTypeAttribute = AttributeNode.FindAttribute(typeNode.Attributes, "ScriptImport");
            if (importedTypeAttribute != null) {
                // This is an imported type definition... we'll assume its valid, since
                // the set of restrictions for such types is fewer, and different, so
                // for now that translates into skipping the members.

                return false;
            }

            if (typeNode.Type == TokenType.Struct) {
                errorHandler.ReportError("Struct types are not supported. Use classes annotated with the Record metadata attribute.",
                                         typeNode.Token.Location);
                return false;
            }

            if (((typeNode.Modifiers & Modifiers.Partial) != 0) &&
                (typeNode.Type != TokenType.Class)) {
                errorHandler.ReportError("Partial types can only be classes, not enumerations or interfaces.",
                                         typeNode.Token.Location);
                return false;
            }

            if ((typeNode.Type == TokenType.Interface) &&
                (typeNode.BaseTypes.Count != 0)) {
                errorHandler.ReportError("Derived interface types are not supported.",
                                         typeNode.Token.Location);
                return false;
            }

            if (typeNode.Type == TokenType.Class) {
                if (typeNode.BaseTypes.Count != 0) {
                    NameNode baseTypeNameNode = typeNode.BaseTypes[0] as NameNode;

                    if (baseTypeNameNode != null) {
                        if (String.CompareOrdinal(baseTypeNameNode.Name, "TestClass") == 0) {
                            if ((typeNode.Modifiers & Modifiers.Internal) == 0) {
                                errorHandler.ReportError("Classes derived from TestClass must be marked as internal.",
                                                         typeNode.Token.Location);
                            }
                            if ((typeNode.Modifiers & Modifiers.Static) != 0) {
                                errorHandler.ReportError("Classes derived from TestClass must not be marked as static.",
                                                         typeNode.Token.Location);
                            }
                            if ((typeNode.Modifiers & Modifiers.Sealed) == 0) {
                                errorHandler.ReportError("Classes derived from TestClass must be marked as sealed.",
                                                         typeNode.Token.Location);
                            }
                            if (typeNode.BaseTypes.Count != 1) {
                                errorHandler.ReportError("Classes derived from TestClass cannot implement interfaces.",
                                                         typeNode.Token.Location);
                            }
                        }
                    }
                }

                AttributeNode objectAttribute = AttributeNode.FindAttribute(typeNode.Attributes, "ScriptObject");
                if (objectAttribute != null) {
                    if ((typeNode.Modifiers & Modifiers.Sealed) == 0) {
                        errorHandler.ReportError("ScriptObject attribute can only be set on sealed classes.",
                                                 typeNode.Token.Location);
                    }

                    if (typeNode.BaseTypes.Count != 0) {
                        errorHandler.ReportError("Classes marked with ScriptObject must not derive from another class or implement interfaces.",
                                                 typeNode.Token.Location);
                    }

                    recordRestrictions = true;
                }

                AttributeNode extensionAttribute = AttributeNode.FindAttribute(typeNode.Attributes, "ScriptExtension");
                if (extensionAttribute != null) {
                    extensionRestrictions = true;

                    if ((typeNode.Modifiers & Modifiers.Static) == 0) {
                        errorHandler.ReportError("ScriptExtension attribute can only be set on static classes.",
                                                 typeNode.Token.Location);
                    }

                    if ((extensionAttribute.Arguments.Count != 1) ||
                        !(extensionAttribute.Arguments[0] is LiteralNode) ||
                        !(((LiteralNode)extensionAttribute.Arguments[0]).Value is string) ||
                        String.IsNullOrEmpty((string)((LiteralNode)extensionAttribute.Arguments[0]).Value)) {
                        errorHandler.ReportError("ScriptExtension attribute declaration must specify the object being extended.",
                                                 typeNode.Token.Location);
                    }
                }

                AttributeNode moduleAttribute = AttributeNode.FindAttribute(typeNode.Attributes, "ScriptModule");
                if (moduleAttribute != null) {
                    moduleRestrictions = true;

                    if (((typeNode.Modifiers & Modifiers.Static) == 0) ||
                        ((typeNode.Modifiers & Modifiers.Internal) == 0)) {
                        errorHandler.ReportError("ScriptModule attribute can only be set on internal static classes.",
                                                 typeNode.Token.Location);
                    }
                }
            }

            if ((typeNode.Members != null) && (typeNode.Members.Count != 0)) {
                Dictionary<string, object> memberNames = new Dictionary<string, object>();
                bool hasCtor = false;

                foreach (ParseNode genericMemberNode in typeNode.Members) {
                    if (!(genericMemberNode is MemberNode)) {
                        errorHandler.ReportError("Only members are allowed inside types. Nested types are not supported.",
                                                 node.Token.Location);
                        continue;
                    }

                    MemberNode memberNode = (MemberNode)genericMemberNode;

                    if ((memberNode.Modifiers & Modifiers.Extern) != 0) {
                        // Extern methods are placeholders for creating overload signatures
                        continue;
                    }

                    if (extensionRestrictions && (memberNode.NodeType != ParseNodeType.MethodDeclaration)) {
                        errorHandler.ReportError("Classes marked with ScriptExtension attribute should only have methods.",
                                                 memberNode.Token.Location);
                    }

                    if (moduleRestrictions && (memberNode.NodeType != ParseNodeType.ConstructorDeclaration)) {
                        errorHandler.ReportError("Classes marked with ScriptModule attribute should only have a static constructor.",
                                                 memberNode.Token.Location);
                    }

                    if (recordRestrictions &&
                        (((memberNode.Modifiers & Modifiers.Static) != 0) ||
                         ((memberNode.NodeType != ParseNodeType.ConstructorDeclaration) &&
                          (memberNode.NodeType != ParseNodeType.FieldDeclaration)))) {
                        errorHandler.ReportError("Classes marked with ScriptObject attribute should only have a constructor and field members.",
                                                 memberNode.Token.Location);
                    }

                    if (memberNode.NodeType == ParseNodeType.ConstructorDeclaration) {
                        if ((memberNode.Modifiers & Modifiers.Static) == 0) {
                            if (hasCtor) {
                                errorHandler.ReportError("Constructor overloads are not supported.",
                                                         memberNode.Token.Location);
                            }
                            hasCtor = true;
                        }
                        continue;
                    }
                    if (memberNode.NodeType == ParseNodeType.OperatorDeclaration) {
                        // Operators don't have a name
                        continue;
                    }

                    string name = memberNode.Name;
                    if (memberNames.ContainsKey(name)) {
                        errorHandler.ReportError("Duplicate-named member. Method overloads are not supported.",
                                                 memberNode.Token.Location);
                    }

                    memberNames[name] = null;

                    string nameToValidate = name;
                    bool preserveCase = false;
                    AttributeNode nameAttribute = AttributeNode.FindAttribute(memberNode.Attributes, "ScriptName");
                    if ((nameAttribute != null) && (nameAttribute.Arguments.Count != 0)) {
                        foreach (ParseNode argNode in nameAttribute.Arguments) {
                            if (argNode.NodeType == ParseNodeType.Literal) {
                                nameToValidate = (string)((LiteralNode)argNode).Value;
                            }
                            else if (argNode.NodeType == ParseNodeType.BinaryExpression) {
                                if (String.CompareOrdinal(((NameNode)((BinaryExpressionNode)argNode).LeftChild).Name, "PreserveCase") == 0) {
                                    preserveCase = (bool)((LiteralNode)((BinaryExpressionNode)argNode).RightChild).Value;
                                }
                            }
                        }
                    }

                    if (Utility.IsKeyword(nameToValidate, /* testCamelCase */ (preserveCase == false))) {
                        errorHandler.ReportError("Invalid member name. Member names should not use keywords.",
                                                 memberNode.Token.Location);
                    }

                    if (hasCodeMembers == false) {
                        hasCodeMembers = ((memberNode.NodeType == ParseNodeType.PropertyDeclaration) ||
                                          (memberNode.NodeType == ParseNodeType.MethodDeclaration) ||
                                          (memberNode.NodeType == ParseNodeType.EventDeclaration) ||
                                          (memberNode.NodeType == ParseNodeType.IndexerDeclaration));
                        codeMemberNode = memberNode;
                    }
                }
            }

            return true;
        }
예제 #27
0
        public ICollection<TypeSymbol> BuildMetadata(ParseNodeList compilationUnits, SymbolSet symbols, CompilerOptions options) {
            Debug.Assert(compilationUnits != null);
            Debug.Assert(symbols != null);

            _symbols = symbols;
            _symbolTable = symbols;
            _options = options;

            string scriptName = GetAssemblyScriptName(compilationUnits);
            if (String.IsNullOrEmpty(scriptName)) {
                _errorHandler.ReportError("You must declare a ScriptAssembly attribute.", String.Empty);
            }
            else if (Utility.IsValidScriptName(scriptName) == false) {
                string errorMessage = "The ScriptAssembly attribute referenced an invalid name '{0}'. Script names must only contain letters, numbers, dots or underscores.";
                _errorHandler.ReportError(String.Format(errorMessage, scriptName), String.Empty);
            }
            symbols.ScriptName = scriptName;

            string scriptPrefix = GetAssemblyScriptPrefix(compilationUnits);
            if (String.IsNullOrEmpty(scriptPrefix) == false) {
                if (Utility.IsValidIdentifier(scriptPrefix) == false) {
                    string errorMessage = "The ScriptQualifier attribute referenced an invalid prefix '{0}'. Script prefix must be valid identifiers.";
                    _errorHandler.ReportError(String.Format(errorMessage, scriptPrefix), String.Empty);
                }
            }
            else {
                scriptPrefix = scriptName.Replace(".", String.Empty);
            }
            symbols.ScriptPrefix = scriptPrefix;

            string assemblyScriptNamespace = GetAssemblyScriptNamespace(compilationUnits);
            List<TypeSymbol> types = new List<TypeSymbol>();

            // Build all the types first.
            // Types need to be loaded upfront so that they can be used in resolving types associated
            // with members.
            foreach (CompilationUnitNode compilationUnit in compilationUnits) {
                foreach (NamespaceNode namespaceNode in compilationUnit.Members) {
                    string namespaceName = namespaceNode.Name;

                    NamespaceSymbol namespaceSymbol = symbols.GetNamespace(namespaceName);

                    List<string> imports = null;
                    Dictionary<string, string> aliases = null;

                    ParseNodeList usingClauses = namespaceNode.UsingClauses;
                    if ((usingClauses != null) && (usingClauses.Count != 0)) {
                        foreach (ParseNode usingNode in namespaceNode.UsingClauses) {
                            if (usingNode is UsingNamespaceNode) {
                                if (imports == null) {
                                    imports = new List<string>(usingClauses.Count);
                                }

                                string referencedNamespace = ((UsingNamespaceNode)usingNode).ReferencedNamespace;
                                if (imports.Contains(referencedNamespace) == false) {
                                    imports.Add(referencedNamespace);
                                }
                            }
                            else {
                                Debug.Assert(usingNode is UsingAliasNode);
                                if (aliases == null) {
                                    aliases = new Dictionary<string, string>();
                                }
                                UsingAliasNode aliasNode = (UsingAliasNode)usingNode;
                                aliases[aliasNode.Alias] = aliasNode.TypeName;
                            }
                        }
                    }

                    // Add parent namespaces as imports in reverse order since they
                    // are searched in that fashion.
                    string[] namespaceParts = namespaceName.Split('.');
                    for (int i = namespaceParts.Length - 2; i >= 0; i--) {
                        string partialNamespace;
                        if (i == 0) {
                            partialNamespace = namespaceParts[0];
                        }
                        else {
                            partialNamespace = String.Join(".", namespaceParts, 0, i + 1);
                        }

                        if (imports == null) {
                            imports = new List<string>();
                        }

                        if (imports.Contains(partialNamespace) == false) {
                            imports.Add(partialNamespace);
                        }
                    }

                    // Build type symbols for all user-defined types
                    foreach (TypeNode typeNode in namespaceNode.Members) {
                        UserTypeNode userTypeNode = typeNode as UserTypeNode;
                        if (userTypeNode == null) {
                            continue;
                        }

                        // Check if we have overriding script namespace for this type.
                        string typeScriptNamespace = GetScriptNamespace(userTypeNode.Attributes);
                        if (String.IsNullOrEmpty(typeScriptNamespace)) {
                            typeScriptNamespace = assemblyScriptNamespace;
                        }
                        
                        ClassSymbol partialTypeSymbol = null;
                        bool isPartial = false;

                        if ((userTypeNode.Modifiers & Modifiers.Partial) != 0) {
                            partialTypeSymbol = (ClassSymbol)((ISymbolTable)namespaceSymbol).FindSymbol(userTypeNode.Name, /* context */ null, SymbolFilter.Types);
                            if ((partialTypeSymbol != null) && partialTypeSymbol.IsApplicationType) {
                                // This class will be considered as a partial class
                                isPartial = true;

                                // Merge code model information for the partial class onto the code model node
                                // for the primary partial class. Interesting bits of information include things
                                // such as base class etc. that is yet to be processed.
                                CustomTypeNode partialTypeNode = (CustomTypeNode)partialTypeSymbol.ParseContext;
                                partialTypeNode.MergePartialType((CustomTypeNode)userTypeNode);

                                // Merge interesting bits of information onto the primary type symbol as well
                                // representing this partial class
                                BuildType(partialTypeSymbol, userTypeNode);

                                if (String.IsNullOrEmpty(typeScriptNamespace) == false) {
                                    partialTypeSymbol.ScriptNamespace = typeScriptNamespace;
                                }
                            }
                        }

                        TypeSymbol typeSymbol = BuildType(userTypeNode, namespaceSymbol);
                        if (typeSymbol != null) {
                            typeSymbol.SetParseContext(userTypeNode);
                            typeSymbol.SetParentSymbolTable(symbols);
                            if (imports != null) {
                                typeSymbol.SetImports(imports);
                            }
                            if (aliases != null) {
                                typeSymbol.SetAliases(aliases);
                            }

                            if (String.IsNullOrEmpty(typeScriptNamespace) == false) {
                                typeSymbol.ScriptNamespace = typeScriptNamespace;
                            }

                            if (isPartial == false) {
                                namespaceSymbol.AddType(typeSymbol);
                            }
                            else {
                                // Partial types don't get added to the namespace, so we don't have
                                // duplicated named items. However, they still do get instantiated
                                // and processed as usual.
                                //
                                // The members within partial classes refer to the partial type as their parent,
                                // and hence derive context such as the list of imports scoped to the
                                // particular type.
                                // However, the members will get added to the primary partial type's list of
                                // members so they can be found.
                                // Effectively the partial class here gets created just to hold
                                // context of type-symbol level bits of information such as the list of
                                // imports, that are consumed when generating code for the members defined
                                // within a specific partial class.
                                ((ClassSymbol)typeSymbol).SetPrimaryPartialClass(partialTypeSymbol);
                            }

                            types.Add(typeSymbol);
                        }
                    }
                }
            }

            // Build inheritance chains
            foreach (TypeSymbol typeSymbol in types) {
                if (typeSymbol.Type == SymbolType.Class) {
                    BuildTypeInheritance((ClassSymbol)typeSymbol);
                }
            }

            // Import members
            foreach (TypeSymbol typeSymbol in types) {
                BuildMembers(typeSymbol);
            }

            // Associate interface members with interface member symbols
            foreach (TypeSymbol typeSymbol in types) {
                if (typeSymbol.Type == SymbolType.Class) {
                    BuildInterfaceAssociations((ClassSymbol)typeSymbol);
                }
            }

            // Load resource values
            if (_symbols.HasResources) {
                foreach (TypeSymbol typeSymbol in types) {
                    if (typeSymbol.Type == SymbolType.Resources) {
                        BuildResources((ResourcesSymbol)typeSymbol);
                    }
                }
            }

            // Load documentation
            if (_options.EnableDocComments) {
                Stream docCommentsStream = options.DocCommentFile.GetStream();
                if (docCommentsStream != null) {
                    try {
                        XmlDocument docComments = new XmlDocument();
                        docComments.Load(docCommentsStream);

                        symbols.SetComments(docComments);
                    }
                    finally {
                        options.DocCommentFile.CloseStream(docCommentsStream);
                    }
                }
            }

            return types;
        }
예제 #28
0
 public ImplementationBuilder(CompilerOptions options, IErrorHandler errorHandler)
 {
     _options = options;
     _errorHandler = errorHandler;
 }
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler) {
            string message = String.Empty;
            bool notYetImplemented = false;

            switch (node.NodeType) {
                case ParseNodeType.PointerType:
                    message = "Pointer types";
                    break;
                case ParseNodeType.OperatorDeclaration:
                    message = "Operator overloads";
                    break;
                case ParseNodeType.DestructorDeclaration:
                    message = "Type destructors";
                    break;
                case ParseNodeType.Goto:
                    message = "Goto statements";
                    break;
                case ParseNodeType.Using:
                    message = "Using statements";
                    break;
                case ParseNodeType.Lock:
                    message = "Lock statements";
                    break;
                case ParseNodeType.UnsafeStatement:
                    message = "Unsafe statements";
                    break;
                case ParseNodeType.LabeledStatement:
                    message = "Labeled statements";
                    break;
                case ParseNodeType.YieldReturn:
                    message = "Yield return statements";
                    break;
                case ParseNodeType.YieldBreak:
                    message = "Yield break statements";
                    break;
                case ParseNodeType.Checked:
                    message = "Checked expressions";
                    break;
                case ParseNodeType.Unchecked:
                    message = "Unchecked expressions";
                    break;
                case ParseNodeType.Sizeof:
                    message = "Sizeof expressions";
                    break;
                case ParseNodeType.Fixed:
                    message = "Fixed expressions";
                    break;
                case ParseNodeType.StackAlloc:
                    message = "Stackalloc expressions";
                    break;
                case ParseNodeType.DefaultValueExpression:
                    message = "Default value expressions";
                    break;
                case ParseNodeType.ExternAlias:
                    message = "Extern aliases";
                    break;
                case ParseNodeType.AliasQualifiedName:
                    message = "Alias-qualified identifiers";
                    break;
                case ParseNodeType.TypeParameter:
                    message = "Generic type parameters";
                    break;
                case ParseNodeType.ConstraintClause:
                    message = "Generic type constraints";
                    break;
                case ParseNodeType.GenericName:
                    message = "Generic types";
                    break;
            }

            if (notYetImplemented) {
                message += " are not yet implemented.";
            }
            else {
                message = message + " are not supported.";
            }

            errorHandler.ReportError(message, node.Token.Location);
            return false;
        }