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) { 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; }
public MetadataImporter(CompilerOptions options, IErrorHandler errorHandler) { Debug.Assert(options != null); Debug.Assert(errorHandler != null); _options = options; _errorHandler = errorHandler; }
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; }
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; }
public SimpleCompilation(string outputPath) { _references = new List<string>(); _sources = new List<IStreamSource>(); _output = new FileStreamSource(outputPath, writable: true); _options = new CompilerOptions(); _options.Minimize = false; }
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>(); }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
public CodeModelBuilder(CompilerOptions options, IErrorHandler errorHandler) { _options = options; _errorHandler = errorHandler; }
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; }
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; }
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; }