private FieldSymbol BuildPropertyAsField(PropertyDeclarationNode propertyNode, TypeSymbol typeSymbol) { AttributeNode intrinsicPropertyAttribute = AttributeNode.FindAttribute(propertyNode.Attributes, "IntrinsicProperty"); if (intrinsicPropertyAttribute == null) { return(null); } TypeSymbol fieldType = typeSymbol.SymbolSet.ResolveType(propertyNode.Type, _symbolTable, typeSymbol); Debug.Assert(fieldType != null); if (fieldType != null) { FieldSymbol symbol = new FieldSymbol(propertyNode.Name, typeSymbol, fieldType); BuildMemberDetails(symbol, typeSymbol, propertyNode, propertyNode.Attributes); string scriptAlias = GetAttributeValue(propertyNode.Attributes, "ScriptAlias"); if (scriptAlias != null) { symbol.SetAlias(scriptAlias); } return(symbol); } return(null); }
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); }
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, DSharpStringResources.SCRIPT_NAMESPACE_ATTRIBUTE); if (scriptNamespaceNode != null) { string scriptNamespace = (string)((LiteralNode)scriptNamespaceNode.Arguments[0]).Value; if (Utility.IsValidScriptNamespace(scriptNamespace) == false) { errorHandler.ReportNodeValidationError(DSharpStringResources.SCRIPT_NAMESPACE_VIOLATION, scriptNamespaceNode); } } } foreach (ParseNode childNode in compilationUnitNode.Members) { if (!(childNode is NamespaceNode)) { errorHandler.ReportNodeValidationError(DSharpStringResources.SCRIPT_NAMESPACE_TYPE_VIOLATION, childNode); return(false); } } return(true); }
internal static string GetAttributeValue(this ParseNodeList parseNodeList, string attributeName) { AttributeNode node = AttributeNode.FindAttribute(parseNodeList, attributeName); if (node != null && node.Arguments.Count != 0 && node.Arguments[0].NodeType == ParseNodeType.Literal) { Debug.Assert(((LiteralNode)node.Arguments[0]).Value is string); return((string)((LiteralNode)node.Arguments[0]).Value); } return(null); }
private string GetAttributeValue(ParseNodeList attributes, string attributeName) { AttributeNode node = AttributeNode.FindAttribute(attributes, attributeName); if (node != null) { Debug.Assert(node.Arguments[0] is LiteralNode); Debug.Assert(((LiteralNode)node.Arguments[0]).Value is string); return((string)((LiteralNode)node.Arguments[0]).Value); } return(null); }
private IndexerSymbol BuildIndexer(IndexerDeclarationNode indexerNode, TypeSymbol typeSymbol) { TypeSymbol indexerType = typeSymbol.SymbolSet.ResolveType(indexerNode.Type, _symbolTable, typeSymbol); Debug.Assert(indexerType != null); if (indexerType != null) { IndexerSymbol indexer = new IndexerSymbol(typeSymbol, indexerType); BuildMemberDetails(indexer, typeSymbol, indexerNode, indexerNode.Attributes); if (AttributeNode.FindAttribute(indexerNode.Attributes, "IntrinsicProperty") != null) { indexer.SetIntrinsic(); } SymbolImplementationFlags implFlags = SymbolImplementationFlags.Regular; if (indexerNode.SetAccessor == null) { implFlags |= SymbolImplementationFlags.ReadOnly; } if ((indexerNode.Modifiers & Modifiers.Abstract) != 0) { implFlags |= SymbolImplementationFlags.Abstract; } else if ((indexerNode.Modifiers & Modifiers.Override) != 0) { implFlags |= SymbolImplementationFlags.Override; } indexer.SetImplementationState(implFlags); Debug.Assert(indexerNode.Parameters.Count != 0); foreach (ParameterNode parameterNode in indexerNode.Parameters) { ParameterSymbol paramSymbol = BuildParameter(parameterNode, indexer); if (paramSymbol != null) { paramSymbol.SetParseContext(parameterNode); indexer.AddParameter(paramSymbol); } } indexer.AddParameter(new ParameterSymbol("value", indexer, indexerType, ParameterMode.In)); return(indexer); } return(null); }
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 || (AttributeNode.FindAttribute(attributes, "ScriptAllowSystemNamespace") != 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); }
private void BuildMemberDetails(MemberSymbol memberSymbol, TypeSymbol typeSymbol, MemberNode memberNode, ParseNodeList attributes) { if (memberSymbol.Type != SymbolType.EnumerationField) { memberSymbol.SetVisibility(GetVisibility(memberNode, typeSymbol)); } bool preserveCase = (AttributeNode.FindAttribute(attributes, "PreserveCase") != null); memberSymbol.SetNameCasing(preserveCase); string scriptName = GetAttributeValue(attributes, "ScriptName"); if (scriptName != null) { memberSymbol.SetTransformedName(scriptName); } else if (AttributeNode.FindAttribute(attributes, "PreserveName") != null) { memberSymbol.DisableNameTransformation(); } }
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)) { 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); }
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); }
private void BuildType(TypeSymbol typeSymbol, UserTypeNode typeNode) { Debug.Assert(typeSymbol != null); Debug.Assert(typeNode != null); ParseNodeList attributes = typeNode.Attributes; if (AttributeNode.FindAttribute(attributes, "Imported") != null) { typeSymbol.SetImported(/* dependencyName */ null); } if (AttributeNode.FindAttribute(attributes, "IgnoreNamespace") != null) { typeSymbol.SetIgnoreNamespace(); } if (AttributeNode.FindAttribute(attributes, "PreserveName") != null) { typeSymbol.DisableNameTransformation(); } string scriptName = GetAttributeValue(attributes, "ScriptName"); if (scriptName != null) { typeSymbol.SetTransformedName(scriptName); } if (typeNode.Type == TokenType.Class) { bool globalizeMembers = false; string mixinRoot = null; AttributeNode globalMethodsAttribute = AttributeNode.FindAttribute(attributes, "GlobalMethods"); if (globalMethodsAttribute != null) { globalizeMembers = true; } else { AttributeNode mixinAttribute = AttributeNode.FindAttribute(attributes, "Mixin"); if (mixinAttribute != null) { Debug.Assert(mixinAttribute.Arguments[0] is LiteralNode); Debug.Assert(((LiteralNode)mixinAttribute.Arguments[0]).Value is string); mixinRoot = (string)((LiteralNode)mixinAttribute.Arguments[0]).Value; globalizeMembers = true; } } if (globalizeMembers) { ((ClassSymbol)typeSymbol).SetGlobalMethods(mixinRoot); } } if (typeNode.Type == TokenType.Enum) { if (AttributeNode.FindAttribute(attributes, "NamedValues") != null) { ((EnumerationSymbol)typeSymbol).SetNamedValues(); } else if (AttributeNode.FindAttribute(attributes, "NumericValues") != null) { ((EnumerationSymbol)typeSymbol).SetNumericValues(); } } }
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); }
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); }
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); }