// Builds a "class" expression: really could be a class, struct, or module. public static void BuildClass(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { Class c = new Class(parentExpression, currentNode.FindToken().Convert()); parentExpression.ChildExpressions.Add(c); int i = 0; // Interpret the declaration modifiers (abstract, public, internal, etc). InterpretClassModifiers( root, c, currentNode.ChildNodes[i]); i++; // Determine if it's a class, module, or struct. switch(currentNode.ChildNodes[i].Term.ToString()) { case "module": c.IsModule = true; c.IsFinal = true; c.IsPartial = true; break; case "struct": c.IsStruct = true; c.IsModule = false; break; default: c.IsStruct = false; c.IsModule = false; break; } i++; // Class name c.UnqualifiedName = currentNode.ChildNodes[i].FindTokenAndGetText(); i++; // Get the generic type list. if (currentNode.ChildNodes[i].ChildNodes.Count > 0) { var generics = currentNode.ChildNodes[i].ChildNodes[0].ChildNodes[1]; foreach (string s in IronyParser.InterpretList(generics)) c.GenericTypeNames.Add(s); } i++; // Get the base type list. if (currentNode.ChildNodes[i].ChildNodes.Count > 0) { var baseTypes = currentNode.ChildNodes[i].ChildNodes[0].ChildNodes[0]; foreach (string s in IronyParser.InterpretList(baseTypes)) c.BaseTypeNames.Add(s); } i+=1; // Build the child expressions of the class. parser.ConsumeParseTree(root, c, currentNode.ChildNodes[i]); }
public void TestClassFullName() { Namespace n = new Namespace(null, null); n.Name = "foo"; Class c = new Class(null, null); c.UnqualifiedName = "bar"; Console.WriteLine(c.GetQualifiedName()); Assert.AreEqual("foo", n.Name, "namespace name1"); Assert.AreEqual("foo", n.GetFullName(), "namespace full name1"); Assert.AreEqual("bar", c.UnqualifiedName, "class name1"); Assert.AreEqual("bar", c.GetQualifiedName(), "class full name1"); c.ParentExpression = n; Assert.AreEqual("foo", n.Name, "namespace name2"); Assert.AreEqual("foo", n.GetFullName(), "namespace full name2"); Assert.AreEqual("bar", c.UnqualifiedName, "class name2"); Assert.AreEqual("foo.bar", c.GetQualifiedName(), "class full name2"); c.ParentExpression = new Expression(null, null); Assert.AreEqual("foo", n.Name, "namespace name3"); Assert.AreEqual("foo", n.GetFullName(), "namespace full name3"); Assert.AreEqual("bar", c.UnqualifiedName, "class name3"); Assert.AreEqual("bar", c.GetQualifiedName(), "class full name3"); }
public static void Validate(Validator validator, Root root, Class c) { bool validated = true; // As a module, it can't have base types if(c.IsModule) { if(c.BaseTypeNames.Count > 0) root.CompilerErrors.Add(new ModuleInheritanceCompilerError("", c.Token.Line, c.Token.Position)); foreach (var e in c.ChildExpressions) if (e is Constructor) root.CompilerErrors.Add(new ModuleConstructorCompilerError("", c.Token.Line, c.Token.Position)); if (c.IsAbstract) root.CompilerErrors.Add(new ModuleModifierCompilerError("", c.Token.Line, c.Token.Position)); } c.Validated = validated; }
/* All classes produced during a test should be * valiated with this method. Scenarios to test: * * Class with body * Name * Accessibility * Generic parameters * Class inheritance * Interface inheritance * Final (sealed) * Module (static class) * Correct parent expression (root, namespace, class, or module) * If a compiler error is supposed to be thrown, validate it is the correct error. * * */ public static void ValidateClass(Class c, Expression parentExpression, string name, string fullName, Accessibility access, bool module, bool final, bool partial, bool isAbstract, bool isStruct) { // Validate the class Assert.AreEqual(name, c.UnqualifiedName, "class Name"); Assert.AreEqual(module, c.IsModule, "IsModule"); Assert.AreEqual(fullName, c.GetQualifiedName(), "FullName"); Assert.AreEqual(c.Accessibility, access, "Accessibility"); Assert.AreEqual(parentExpression, c.ParentExpression, "ParentExpresion"); Assert.AreEqual(final, c.IsFinal, "IsFinal"); Assert.AreEqual(partial, c.IsPartial, "IsPartial"); Assert.AreEqual(isAbstract, c.IsAbstract, "IsAbstract"); Assert.AreEqual(isStruct, c.IsStruct); }
// Interpret class declaration modifiers: make sure to check for duplicates or conflicting ones. static void InterpretClassModifiers(Root root, Class c, ParseTreeNode node) { bool foundPublic = false; bool foundInternal = false; bool foundFinal = false; bool foundPartial = false; bool foundAbstract = false; foreach (var modifierNode in node.ChildNodes) { string text = modifierNode.FindTokenAndGetText(); if (text == "public") { if (foundPublic || foundInternal) { root.CompilerErrors.Add(new MultipleAccessModifiersCompilerError("", modifierNode.FindToken().Location.Line, modifierNode.FindToken().Location.Position)); } else { c.Accessibility = Accessibility.Public; foundPublic = true; } } if (text == "internal") { if (foundInternal || foundPublic) { root.CompilerErrors.Add(new MultipleAccessModifiersCompilerError("", modifierNode.FindToken().Location.Line, modifierNode.FindToken().Location.Position)); } else { c.Accessibility = Accessibility.Internal; foundInternal = true; } } if (text == "final") { if (foundFinal) { root.CompilerErrors.Add(new DuplicateModifiersCompilerError("", modifierNode.FindToken().Location.Line, modifierNode.FindToken().Location.Position)); } else { if (c.IsModule) root.CompilerErrors.Add(new ModuleModifierCompilerError("", modifierNode.FindToken().Location.Line, modifierNode.FindToken().Location.Position)); c.IsFinal = true; foundFinal = true; } } if (text == "partial") { if (foundPartial) { root.CompilerErrors.Add(new DuplicateModifiersCompilerError("", modifierNode.FindToken().Location.Line, modifierNode.FindToken().Location.Position)); } else { if (c.IsModule) root.CompilerErrors.Add(new ModuleModifierCompilerError("", modifierNode.FindToken().Location.Line, modifierNode.FindToken().Location.Position)); c.IsPartial = true; foundPartial = true; } } if (text == "abstract") { if (foundAbstract) { root.CompilerErrors.Add(new DuplicateModifiersCompilerError("", modifierNode.FindToken().Location.Line, modifierNode.FindToken().Location.Position)); } else { if (c.IsModule) root.CompilerErrors.Add(new ModuleModifierCompilerError("", modifierNode.FindToken().Location.Line, modifierNode.FindToken().Location.Position)); c.IsAbstract = true; foundAbstract = true; } } } }
/* Builds the CodeDOM statement for a class, and attaches it to a * CodeDOM namespace statement. */ public static void Emit(CodeNamespace codeNamespace, Class c) { // CodeTypeDeclaration is the CodeDOM representation of a // class, struct, or enum. var codeTypeDeclaration = new CodeTypeDeclaration(); codeNamespace.Types.Add(codeTypeDeclaration); // Assign the unqualified name (without namespace). codeTypeDeclaration.Name = c.UnqualifiedName; if(c.IsStruct) codeTypeDeclaration.IsStruct = true; else // Flag the type as a class. codeTypeDeclaration.IsClass = true; // Create the enum that sets attributes of the class. var typeAttr = TypeAttributes.Class; // If the class is "final", it is "sealed" in C# terms. if (c.IsFinal) typeAttr |= TypeAttributes.Sealed; if (c.IsAbstract) typeAttr |= TypeAttributes.Abstract; // Assign the partial state of the class. codeTypeDeclaration.IsPartial = c.IsPartial; // Add the list of generic type names of the class. foreach (string s in c.GenericTypeNames) codeTypeDeclaration.TypeParameters.Add(new CodeTypeParameter(s)); // Add the list of base type names of the class. foreach(string s in c.BaseTypeNames) codeTypeDeclaration.BaseTypes.Add(s); // Set the accessibility of the class. switch(c.Accessibility) { case Accessibility.Internal: typeAttr |= TypeAttributes.NestedAssembly; break; case Accessibility.Public: typeAttr |= TypeAttributes.Public; break; } codeTypeDeclaration.TypeAttributes = typeAttr; /* Iterate through and emit the children */ foreach (var e in c.ChildExpressions) { if (e is ClassVariable) ClassVariableEmitter.Emit(codeTypeDeclaration, e as ClassVariable); if (e is MethodDeclaration) MethodEmitter.Emit(codeTypeDeclaration, (MethodDeclaration)e); if (e is Constructor) ConstructorEmitter.Emit(codeTypeDeclaration, (e as Constructor)); if (e is Property) PropertyEmitter.Emit(codeTypeDeclaration, (e as Property)); if (e is Event) EventEmitter.Emit(codeTypeDeclaration, (e as Event)); } }