예제 #1
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);
        }
예제 #2
0
        private void BuildMembers(TypeSymbol typeSymbol)
        {
            if (typeSymbol.Type == SymbolType.Delegate)
            {
                DelegateTypeNode delegateNode = (DelegateTypeNode)typeSymbol.ParseContext;

                TypeSymbol returnType = typeSymbol.SymbolSet.ResolveType(delegateNode.ReturnType, _symbolTable, typeSymbol);
                Debug.Assert(returnType != null);

                if (returnType != null)
                {
                    MethodSymbol invokeMethod = new MethodSymbol("Invoke", typeSymbol, returnType, MemberVisibility.Public);
                    invokeMethod.SetTransformedName(String.Empty);

                    // Mark the method as abstract, as there is no actual implementation of the method
                    // to be generated
                    invokeMethod.SetImplementationState(SymbolImplementationFlags.Abstract);

                    typeSymbol.AddMember(invokeMethod);
                }
                return;
            }

            CustomTypeNode typeNode = (CustomTypeNode)typeSymbol.ParseContext;

            foreach (MemberNode member in typeNode.Members)
            {
                MemberSymbol memberSymbol = null;
                switch (member.NodeType)
                {
                case ParseNodeType.FieldDeclaration:
                case ParseNodeType.ConstFieldDeclaration:
                    memberSymbol = BuildField((FieldDeclarationNode)member, typeSymbol);
                    break;

                case ParseNodeType.PropertyDeclaration:
                    memberSymbol = BuildPropertyAsField((PropertyDeclarationNode)member, typeSymbol);
                    if (memberSymbol == null)
                    {
                        memberSymbol = BuildProperty((PropertyDeclarationNode)member, typeSymbol);
                    }
                    break;

                case ParseNodeType.IndexerDeclaration:
                    memberSymbol = BuildIndexer((IndexerDeclarationNode)member, typeSymbol);
                    break;

                case ParseNodeType.ConstructorDeclaration:
                case ParseNodeType.MethodDeclaration:
                    if ((member.Modifiers & Modifiers.Extern) != 0)
                    {
                        // Extern methods are there for defining overload signatures, so
                        // we just skip them as far as metadata goes. The validator has
                        // taken care of the requirements/constraints around use of extern methods.
                        continue;
                    }
                    memberSymbol = BuildMethod((MethodDeclarationNode)member, typeSymbol);
                    break;

                case ParseNodeType.EventDeclaration:
                    memberSymbol = BuildEvent((EventDeclarationNode)member, typeSymbol);
                    break;

                case ParseNodeType.EnumerationFieldDeclaration:
                    memberSymbol = BuildEnumField((EnumerationFieldNode)member, typeSymbol);
                    break;
                }

                if (memberSymbol != null)
                {
                    memberSymbol.SetParseContext(member);

                    if ((typeSymbol.IsApplicationType == false) &&
                        ((memberSymbol.Type == SymbolType.Constructor) ||
                         (typeSymbol.GetMember(memberSymbol.Name) != null)))
                    {
                        // If the type is an imported type, then it is allowed to contain
                        // overloads, and we're simply going to ignore its existence, as long
                        // as one overload has been added to the member table.
                        continue;
                    }

                    typeSymbol.AddMember(memberSymbol);

                    if ((typeSymbol.Type == SymbolType.Class) && (memberSymbol.Type == SymbolType.Event))
                    {
                        EventSymbol eventSymbol = (EventSymbol)memberSymbol;
                        if (eventSymbol.DefaultImplementation)
                        {
                            // Add a private field that will serve as the backing member
                            // later on in the conversion (eg. in non-event expressions)
                            MemberVisibility visibility = MemberVisibility.PrivateInstance;
                            if ((eventSymbol.Visibility & MemberVisibility.Static) != 0)
                            {
                                visibility |= MemberVisibility.Static;
                            }

                            FieldSymbol fieldSymbol =
                                new FieldSymbol("__" + Utility.CreateCamelCaseName(eventSymbol.Name), typeSymbol,
                                                eventSymbol.AssociatedType);
                            fieldSymbol.SetVisibility(visibility);
                            fieldSymbol.SetParseContext(((EventDeclarationNode)eventSymbol.ParseContext).Field);

                            typeSymbol.AddMember(fieldSymbol);
                        }
                    }
                }
            }
        }
예제 #3
0
        bool IParseNodeValidator.Validate(ParseNode node, CompilerOptions options, IErrorHandler errorHandler)
        {
            CustomTypeNode typeNode = (CustomTypeNode)node;

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

            AttributeNode importedTypeAttribute = AttributeNode.FindAttribute(typeNode.Attributes, DSharpStringResources.SCRIPT_IMPORT_ATTRIBUTE);

            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.Modifiers & Modifiers.New) != 0)
            {
                errorHandler.ReportNodeValidationError(DSharpStringResources.NEW_KEYWORD_ON_TYPE_UNSUPPORTED, typeNode);

                return(false);
            }

            if ((typeNode.Modifiers & (Modifiers.Private | Modifiers.Protected)) != 0)
            {
                errorHandler.ReportNodeValidationError(DSharpStringResources.ACCESS_MODIFIER_ON_TYPE_UNSUPPORTED, typeNode);

                return(false);
            }

            if ((typeNode.Modifiers & Modifiers.Partial) != 0 &&
                typeNode.Type != TokenType.Class)
            {
                errorHandler.ReportNodeValidationError(DSharpStringResources.UNSUPPORTED_PARTIAL_TYPE, typeNode);

                return(false);
            }

            if (typeNode.Type == TokenType.Class)
            {
                AttributeNode objectAttribute = AttributeNode.FindAttribute(typeNode.Attributes, DSharpStringResources.SCRIPT_OBJECT_ATTRIBUTE);

                if (objectAttribute != null)
                {
                    if ((typeNode.Modifiers & Modifiers.Sealed) == 0)
                    {
                        errorHandler.ReportNodeValidationError(DSharpStringResources.SCRIPT_OBJECT_ATTRIBUTE_ERROR, typeNode);
                    }

                    if (typeNode.BaseTypes.Count != 0)
                    {
                        errorHandler.ReportNodeValidationError(DSharpStringResources.SCRIPT_OBJECT_CLASS_INHERITENCE_ERROR, typeNode);
                    }

                    recordRestrictions = true;
                }
            }

            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))
                    {
                        continue;
                    }

                    MemberNode memberNode = (MemberNode)genericMemberNode;

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

                    if (recordRestrictions &&
                        ((memberNode.Modifiers & Modifiers.Static) != 0 ||
                         memberNode.NodeType != ParseNodeType.ConstructorDeclaration &&
                         memberNode.NodeType != ParseNodeType.FieldDeclaration))
                    {
                        errorHandler.ReportNodeValidationError(DSharpStringResources.SCRIPT_OBJECT_MEMBER_VIOLATION_ERROR, memberNode);
                    }

                    if (memberNode.NodeType == ParseNodeType.ConstructorDeclaration)
                    {
                        if ((memberNode.Modifiers & Modifiers.Static) == 0)
                        {
                            if (hasCtor)
                            {
                                errorHandler.ReportNodeValidationError(DSharpStringResources.UNSUPPORTED_CONSTRUCTOR_OVERLOAD, memberNode);
                            }

                            hasCtor = true;
                        }

                        continue;
                    }

                    if (memberNode is MethodDeclarationNode methodDeclaration)
                    {
                        if (methodDeclaration.IsExensionMethod && (!methodDeclaration.Modifiers.HasFlag(Modifiers.Static) || !typeNode.Modifiers.HasFlag(Modifiers.Static)))
                        {
                            errorHandler.ReportNodeValidationError(DSharpStringResources.EXTENSION_TYPE_AND_METHOD_SHOULD_BE_STATIC, methodDeclaration);
                        }
                    }

                    if (memberNode.NodeType == ParseNodeType.OperatorDeclaration)
                    {
                        // Operators don't have a name
                        continue;
                    }

                    string        name            = memberNode.Name;
                    AttributeNode ignoreAttribute = AttributeNode.FindAttribute(memberNode.Attributes, DSharpStringResources.SCRIPT_IGNORE_ATTRIBUTE);

                    if (ignoreAttribute == null && memberNames.ContainsKey(name) && typeNode.Type != TokenType.Interface)
                    {
                        errorHandler.ReportNodeValidationError(DSharpStringResources.UNSUPPORTED_METHOD_OVERLOAD, memberNode);
                    }

                    // remember the method overload only if it wasn't ignored
                    if (ignoreAttribute == null)
                    {
                        memberNames[name] = null;
                    }

                    string        nameToValidate = name;
                    bool          preserveCase   = false;
                    AttributeNode nameAttribute  = AttributeNode.FindAttribute(memberNode.Attributes, DSharpStringResources.SCRIPT_NAME_ATTRIBUTE);

                    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.ReportNodeValidationError(DSharpStringResources.RESERVED_KEYWORD_ON_MEMBER_ERROR, memberNode);
                    }

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

            return(true);
        }
예제 #4
0
        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);
        }
예제 #5
0
        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.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.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);
        }
예제 #6
0
        private TypeSymbol BuildType(UserTypeNode typeNode, NamespaceSymbol namespaceSymbol)
        {
            Debug.Assert(typeNode != null);
            Debug.Assert(namespaceSymbol != null);

            TypeSymbol    typeSymbol = null;
            ParseNodeList attributes = typeNode.Attributes;

            if (typeNode.Type == TokenType.Class)
            {
                CustomTypeNode customTypeNode = (CustomTypeNode)typeNode;
                Debug.Assert(customTypeNode != null);

                NameNode baseTypeNameNode = null;
                if (customTypeNode.BaseTypes.Count != 0)
                {
                    baseTypeNameNode = customTypeNode.BaseTypes[0] as NameNode;
                }

                if ((baseTypeNameNode != null) && (String.CompareOrdinal(baseTypeNameNode.Name, "Record") == 0))
                {
                    typeSymbol = new RecordSymbol(typeNode.Name, namespaceSymbol);
                }
                else
                {
                    AttributeNode resourcesAttribute = AttributeNode.FindAttribute(attributes, "Resources");
                    if (resourcesAttribute != null)
                    {
                        typeSymbol = new ResourcesSymbol(typeNode.Name, namespaceSymbol);
                    }
                    else
                    {
                        typeSymbol = new ClassSymbol(typeNode.Name, namespaceSymbol);

                        if ((baseTypeNameNode != null) &&
                            (String.CompareOrdinal(baseTypeNameNode.Name, "TestClass") == 0))
                        {
                            ((ClassSymbol)typeSymbol).SetTestClass();
                        }
                    }
                }
            }
            else if (typeNode.Type == TokenType.Interface)
            {
                typeSymbol = new InterfaceSymbol(typeNode.Name, namespaceSymbol);
            }
            else if (typeNode.Type == TokenType.Enum)
            {
                bool flags = false;

                AttributeNode flagsAttribute = AttributeNode.FindAttribute(typeNode.Attributes, "Flags");
                if (flagsAttribute != null)
                {
                    flags = true;
                }

                typeSymbol = new EnumerationSymbol(typeNode.Name, namespaceSymbol, flags);
            }
            else if (typeNode.Type == TokenType.Delegate)
            {
                typeSymbol = new DelegateSymbol(typeNode.Name, namespaceSymbol);
                typeSymbol.SetTransformedName("Function");
                typeSymbol.SetIgnoreNamespace();
            }

            Debug.Assert(typeSymbol != null, "Unexpected type node " + typeNode.Type);
            if (typeSymbol != null)
            {
                if ((typeNode.Modifiers & Modifiers.Public) != 0)
                {
                    typeSymbol.SetPublic();
                }

                BuildType(typeSymbol, typeNode);

                if (namespaceSymbol.Name.EndsWith(_options.TestsSubnamespace, StringComparison.Ordinal))
                {
                    typeSymbol.SetTestType();
                }
            }

            return(typeSymbol);
        }