public void ParseBinaryOperatorPrecedence() { string code = @" module bar: int foo(): boo = 1 || 1 && 1 | 1 ^ 1 & 1 == 1 < 1 << 1 + 1 * 1 "; var parser = Pie.Parser.Create(); var root = new Root(); parser.Parse(root, code); // Check that no errors were produced. Assert.AreEqual(root.CompilerErrors.Count, 0, "no errors"); var assignment = root.ChildExpressions[0].ChildExpressions[0].ChildExpressions[0] as Assignment; Assert.AreEqual(BinaryOperatorType.LogicalOr, (assignment.ChildExpressions[1] as BinaryOperator).OperatorType); Assert.AreEqual(BinaryOperatorType.LogicalAnd, (assignment.ChildExpressions[1].ChildExpressions[1] as BinaryOperator).OperatorType); Assert.AreEqual(BinaryOperatorType.BitwiseOr, (assignment.ChildExpressions[1].ChildExpressions[1].ChildExpressions[1] as BinaryOperator).OperatorType); Assert.AreEqual(BinaryOperatorType.BitwiseXor, (assignment.ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1] as BinaryOperator).OperatorType); Assert.AreEqual(BinaryOperatorType.BitwiseAnd, (assignment.ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1] as BinaryOperator).OperatorType); Assert.AreEqual(BinaryOperatorType.Equal, (assignment.ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1] as BinaryOperator).OperatorType); Assert.AreEqual(BinaryOperatorType.Less, (assignment.ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1] as BinaryOperator).OperatorType); Assert.AreEqual(BinaryOperatorType.BitwiseShiftLeft, (assignment.ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1] as BinaryOperator).OperatorType); Assert.AreEqual(BinaryOperatorType.Add, (assignment.ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1] as BinaryOperator).OperatorType); Assert.AreEqual(BinaryOperatorType.Multiply, (assignment.ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1].ChildExpressions[1] as BinaryOperator).OperatorType); }
// Build an instantiation expression "new foo()" public static void BuildInstantiation(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var ist = new Instantiation(parentExpression, currentNode.Token.Convert()); parentExpression.ChildExpressions.Add(ist); // A non-array instantiation if (currentNode.ChildNodes[1].ChildNodes[0].Term.ToString() == "new_instantiate") { ist.Name = parser.CheckAlias(currentNode.ChildNodes[1].ChildNodes[0].FindTokenAndGetText()); if (currentNode.ChildNodes[1].ChildNodes[0].ChildNodes[1].ChildNodes.Count > 0) foreach (var n in currentNode.ChildNodes[1].ChildNodes[0].ChildNodes[1].ChildNodes[0].ChildNodes[1].ChildNodes) { ist.GenericTypes.Add(parser.CheckAlias(n.FindTokenAndGetText())); } foreach (var n in currentNode.ChildNodes[1].ChildNodes[0].ChildNodes[2].ChildNodes) { parser.ConsumeParseTree(root, ist.Parameters, n); } } else // An array instantiation { ist.IsArray = true; ist.Name = parser.CheckAlias(currentNode.ChildNodes[1].ChildNodes[0].ChildNodes[0].FindTokenAndGetText()); parser.ConsumeParseTree(root, ist.Parameters, currentNode.ChildNodes[1].ChildNodes[0].ChildNodes[2]); } }
// Build a constructor expression. public static void BuildConstructor(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var ctor = new Constructor(parentExpression, currentNode.Token.Convert()); parentExpression.ChildExpressions.Add(ctor); // Interpret the declaration modifiers. InterpretModifiers(root, ctor, currentNode.ChildNodes[0]); // Interpret the arguments of the constructor. if (currentNode.ChildNodes[2].ChildNodes.Count > 0) { foreach (var n in currentNode.ChildNodes[2].ChildNodes) { BuildArgument(parser, ctor, n.ChildNodes[0]); } } // Build the "this" or "base" constructors called, if any. if(currentNode.ChildNodes[3].ChildNodes.Count > 0) { if(currentNode.ChildNodes[3].ChildNodes[0].ChildNodes[0].Term.ToString() == "this") { ctor.Sub = true; } foreach (var n in currentNode.ChildNodes[3].ChildNodes[0].ChildNodes[1].ChildNodes) { parser.ConsumeParseTree(root, ctor.SubParameters, n); } } // Build the expressions in the method body of the constructor. parser.ConsumeParseTree(root, ctor, currentNode.ChildNodes[4]); }
public void ParseEnumSimple() { string code = @" enum Birds: Raven Swallow Robin Eagle "; var parser = Pie.Parser.Create(); var root = new Root(); parser.Parse(root, code); // Check that no error was produced. Assert.AreEqual(root.CompilerErrors.Count, 0); // Check that an enum was produced Assert.IsTrue(root.ChildExpressions[0] is Pie.Expressions.Enum); // Check the values in the enum var e = root.ChildExpressions[0] as Pie.Expressions.Enum; Assert.AreEqual("Birds", e.UnqualifiedName); Assert.AreEqual("Raven", e.Constants[0].Name); Assert.AreEqual(0, e.Constants[0].Value); Assert.AreEqual("Swallow", e.Constants[1].Name); Assert.AreEqual(1, e.Constants[1].Value); Assert.AreEqual("Robin", e.Constants[2].Name); Assert.AreEqual(2, e.Constants[2].Value); Assert.AreEqual("Eagle", e.Constants[3].Name); Assert.AreEqual(3, e.Constants[3].Value); }
// Emit byte code for the expression tree owned by this root. // Accepts the compiler parameters that were given to PieCodeProvider // since it will be needed for the CSharpCodeProvider. public CompilerResults Emit(CompilerParameters compilerParams, Root root) { // Emit the code compile unit, the top of the codedom tree. // This method will cal emit method for all child expressions // until all expressions have had byte code emitted. var codeCompileUnit = RootEmitter.Emit(root); // Create the C# compiler. var csProvider = new Microsoft.CSharp.CSharpCodeProvider(); CodeGeneratorOptions options = new CodeGeneratorOptions(); options.BracingStyle = "C"; // Compile the codedom tree into an assembly var sw = new StringWriter(); csProvider.GenerateCodeFromCompileUnit(codeCompileUnit, sw, options); // Display the C# code for debugging purposes. string ccode = sw.GetStringBuilder().ToString(); Console.WriteLine(ccode); // Get the results of the compilation: the assembly and error list CompilerResults results = csProvider.CompileAssemblyFromSource(compilerParams, ccode); // Store all C# compiler errors, so that they can be included with Pie compiler errors.. foreach (CompilerError e in root.CompilerErrors) results.Errors.Add(e); root.CompilerErrors.Clear(); return results; }
public void ParseClassAbstract() { string code = @" abstract class foo:"; var parser = Pie.Parser.Create(); var root = new Root(); parser.Parse(root, code); // Check that no errors were produced. Assert.AreEqual(root.CompilerErrors.Count, 0, "Compiler errors"); // Check that the only child of root is a class Assert.AreEqual(root.ChildExpressions.Count, 1, "Root: 1 child"); Assert.IsTrue(root.ChildExpressions[0] is Class, "Root: child is class"); ValidateClass((Class)root.ChildExpressions[0], root, "foo", "foo", Accessibility.Public, false, false, false, true, false); }
// Build an assembly from a list of source strings. public override CompilerResults CompileAssemblyFromSource(CompilerParameters options, params string[] sources) { var root = new Root(); foreach(string code in sources) parser.Parse(root, code); if(root.CompilerErrors.Count > 0) { var results = new CompilerResults(null); foreach(var e in root.CompilerErrors) results.Errors.Add(e); return results; } validator.Validate(options, root); if (root.CompilerErrors.Count > 0) { var results = new CompilerResults(null); foreach (var e in root.CompilerErrors) results.Errors.Add(e); return results; } var codeDomEmitter = new CodeDomEmitter(); return codeDomEmitter.Emit(options, root); }
// Build an interface method declaration. public static void BuildInterfaceMethod(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var method = new MethodDeclaration(parentExpression, currentNode.Token.Convert()); parentExpression.ChildExpressions.Add(method); // Build the return type of the interface method. method.ReturnTypeName = parser.CheckAlias(currentNode.ChildNodes[0].ChildNodes[0].FindTokenAndGetText()); // The name of the interface method. method.Name = currentNode.ChildNodes[0].ChildNodes[1].FindTokenAndGetText(); // Build the list of generic type names. if (currentNode.ChildNodes[1].ChildNodes.Count > 0) { var generics = currentNode.ChildNodes[1].ChildNodes[0].ChildNodes[1]; foreach (string s in IronyParser.InterpretList(generics)) method.GenericTypeNames.Add(parser.CheckAlias(s)); } // Build the arguments of the method if (currentNode.ChildNodes[2].ChildNodes.Count > 0) { foreach (var n in currentNode.ChildNodes[2].ChildNodes) { MethodDeclarationBuilder.BuildArgument(parser, method, n.ChildNodes[0]); } } }
// 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 ParseMethodArgs() { string code = @" module bar: void boo(int i, int b, out int a, ref int b): foo(1) "; var parser = Pie.Parser.Create(); var root = new Root(); parser.Parse(root, code); // Check that no errors were produced. Assert.AreEqual(root.CompilerErrors.Count, 0, "no errors"); // Check that the class has one member: a method Assert.AreEqual(1, root.ChildExpressions[0].ChildExpressions.Count, " child count"); Assert.IsTrue(root.ChildExpressions[0].ChildExpressions[0] is MethodDeclaration, "child is method"); // Check for the invocation Assert.IsTrue(root.ChildExpressions[0].ChildExpressions[0].ChildExpressions[0] is MethodInvocation, "invocation"); var i = root.ChildExpressions[0].ChildExpressions[0].ChildExpressions[0] as MethodInvocation; // Assert.AreEqual("foo", i.Name, "invoke name"); // Assert.AreEqual(1, (i.Parameters.ChildExpressions[0] as Literal).Value, "invoke value"); }
// Build a number, string, or character literal: v = 1234 public static void BuildLiteral(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var e = new Literal(parentExpression, currentNode.FindToken().Convert()); parentExpression.ChildExpressions.Add(e); e.ParentExpression = parentExpression; e.Value = currentNode.Token.Value; }
// Build a namespace expression public static void BuildNamespace(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { Namespace n = new Namespace(parentExpression, currentNode.FindToken().Convert()); n.Name = currentNode.ChildNodes[1].FindTokenAndGetText(); parentExpression.ChildExpressions.Add(n); parser.ConsumeParseTree(root, n, currentNode.ChildNodes[2]); }
// Build an interface property declaration public static void BuildInterfaceProperty(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var property = new Property(parentExpression, currentNode.Token.Convert()); parentExpression.ChildExpressions.Add(property); property.TypeName = parser.CheckAlias(currentNode.ChildNodes[0].ChildNodes[0].FindTokenAndGetText()); property.Name = currentNode.ChildNodes[0].ChildNodes[1].FindTokenAndGetText(); }
void ValidateRecursive(Root root, Expression expression) { if (expression is Class) ClassValidator.Validate(this, root, expression as Class); foreach (var child in expression.ChildExpressions) ValidateRecursive(root, child); }
public void Validate(CompilerParameters options, Root root) { this.options = options; PrepareValidation(root, root, null); ValidateRecursive(root, root); }
// Build an indexed identifier expression (foo[0]) public static void BuildIndexedIdentifier(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var indexedIdentifier = new IndexedIdentifier(parentExpression, currentNode.Token.Convert()); parentExpression.ChildExpressions.Add(indexedIdentifier); indexedIdentifier.Name = currentNode.ChildNodes[0].FindTokenAndGetText(); parser.ConsumeParseTree(root, indexedIdentifier, currentNode.ChildNodes[2]); }
void PrepareValidation(Root root, Expression expression, Import import) { if (import != null) { expression.Imports.Add(import); foreach (var c in expression.ChildExpressions) PrepareValidation(root, c, import); } }
// Build an import expression: one for each name imported. public static void BuildImport(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { foreach (var node in currentNode.ChildNodes[1].ChildNodes) { var i = new Import(parentExpression, currentNode.FindToken().Convert()); parentExpression.ChildExpressions.Add(i); i.ParentExpression = parentExpression; i.Name = node.FindTokenAndGetText(); } }
// Build a boolean literal: v = true public static void BuildBoolLiteral(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var e = new Literal(parentExpression, currentNode.FindToken().Convert()); parentExpression.ChildExpressions.Add(e); e.ParentExpression = parentExpression; if (currentNode.ChildNodes[0].FindTokenAndGetText() == "true") e.Value = true; else e.Value = false; }
public void ParseEmptySource() { string code = @""; var parser = Pie.Parser.Create(); var root = new Root(); parser.Parse(root, code); // Check that no errors were produced. Assert.AreEqual(root.CompilerErrors.Count, 0, "no errors"); }
// Build a while loop statement (a for loop with just the conditional) public static void BuildWhileLoop(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var whileLoop = new WhileLoop(parentExpression, currentNode.Token.Convert()); parentExpression.ChildExpressions.Add(whileLoop); // Build the conditional expressoin parser.ConsumeParseTree(root, whileLoop.Condition, currentNode.ChildNodes[1]); // Build the statements that make up the body of the while loop parser.ConsumeParseTree(root, whileLoop, currentNode.ChildNodes[2]); }
// Build a case block statement public static void BuildCaseBlock(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var caseBlock = new CaseBlock(parentExpression, currentNode.Token.Convert()); parentExpression.ChildExpressions.Add(caseBlock); // Get the expression being tested against parser.ConsumeParseTree(root, caseBlock.Variable, currentNode.ChildNodes[1]); // Build the expressions in the body of the case block foreach (var e in currentNode.ChildNodes[2].ChildNodes) parser.ConsumeParseTree(root, caseBlock, e); }
// Build a switch block statement public static void BuildSwitchBlock(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var s = new SwitchBlock(parentExpression, currentNode.Token.Convert()); parentExpression.ChildExpressions.Add(s); // Get the expression being tested parser.ConsumeParseTree(root, s.Variable, currentNode.ChildNodes[1]); // Build each case block if(currentNode.ChildNodes[2].ChildNodes.Count > 0) foreach(var node in currentNode.ChildNodes[2].ChildNodes[0].ChildNodes) BuildCaseBlock(parser, root, s, node); }
// Build property declaration statement public static void BuildProperty(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var property = new Property(parentExpression, currentNode.Token.Convert()); parentExpression.ChildExpressions.Add(property); // If the parent is a module, make the property shared var c = parentExpression as Class; if (c.IsModule) { property.IsShared = true; } // Interpret the modifiers for the property declaration InterpretModifiers(root, property, currentNode.ChildNodes[0].ChildNodes[0]); // Check for conflicting/invalid property modifiers if (property.IsShared && (property.IsFinal || property.IsOverride)) root.CompilerErrors.Add(new IncompatibleModifiersCompilerError("", currentNode.FindToken().Location.Line, currentNode.FindToken().Location.Position)); // Find the return type for the property: check if it's generic or an array var typeNode = currentNode.ChildNodes[0].ChildNodes[1].ChildNodes[0]; if(typeNode.ChildNodes[0].Term.ToString() == "array") { property.Name = currentNode.ChildNodes[0].ChildNodes[1].ChildNodes[1].FindTokenAndGetText(); property.TypeName = parser.CheckAlias(typeNode.ChildNodes[0].ChildNodes[0].FindTokenAndGetText()) + "[]"; } else if (typeNode.ChildNodes[0].Term.ToString() == "generic_identifier") { property.Name = currentNode.ChildNodes[0].ChildNodes[1].ChildNodes[1].FindTokenAndGetText(); property.TypeName = typeNode.ChildNodes[0].ChildNodes[0].FindTokenAndGetText() + "<"; for(int i = 0; i < typeNode.ChildNodes[0].ChildNodes[2].ChildNodes.Count; i++) { property.TypeName += typeNode.ChildNodes[0].ChildNodes[2].ChildNodes[i].FindTokenAndGetText(); if (i < typeNode.ChildNodes[0].ChildNodes[2].ChildNodes.Count - 1) property.TypeName += ","; } property.TypeName += ">"; } else { property.Name = currentNode.ChildNodes[0].ChildNodes[1].ChildNodes[1].FindTokenAndGetText(); property.TypeName = parser.CheckAlias(currentNode.ChildNodes[0].ChildNodes[1].ChildNodes[0].FindTokenAndGetText()); } // Build the get block for the property parser.ConsumeParseTree(root, property.GetBlock, currentNode.ChildNodes[1]); // Build the set block for the property parser.ConsumeParseTree(root, property.SetBlock, currentNode.ChildNodes[2]); }
public void ParseBodiedForLoop7() { string code = @" module bar: void boo(): for i in 10 to x step a: return"; var parser = Pie.Parser.Create(); var root = new Root(); parser.Parse(root, code); // Check that no errors were produced. Assert.AreEqual(root.CompilerErrors.Count, 0, "no errors"); }
public void ParseEnumNoName() { string code = @" enum"; var parser = Pie.Parser.Create(); var root = new Root(); parser.Parse(root, code); // Check that one error was produced. Assert.AreEqual(root.CompilerErrors.Count, 1, "1 error"); // Check that the correct error was generated Assert.IsTrue(root.CompilerErrors[0] is ParserCompilerError, "correct error"); }
public void ParseBinaryOperatorIndented() { string code = @" module bar: int foo(): int boo = boo + 2"; var parser = Pie.Parser.Create(); var root = new Root(); parser.Parse(root, code); // Check that no errors were produced. Assert.AreEqual(root.CompilerErrors.Count, 0, "no errors"); }
// Build a method invocation statement (foo(1)) public static void BuildMethodInvocation(IronyParser parser, Root root, Expression parentExpression, ParseTreeNode currentNode) { var methodInvocation = new MethodInvocation(parentExpression, currentNode.FindToken().Convert()); methodInvocation.Name = currentNode.ChildNodes[0].FindTokenAndGetText(); parentExpression.ChildExpressions.Add(methodInvocation); // interpret the expressions that are passed to the invocation as arguments if (currentNode.ChildNodes[1].ChildNodes.Count > 0) { foreach (var n in currentNode.ChildNodes[1].ChildNodes) { parser.ConsumeParseTree(root, methodInvocation.Parameters, n); } } }
public void ParseGenericMethodInvocation() { string code = @" module bar: void boo(): boo{foo}() "; var parser = Pie.Parser.Create(); var root = new Root(); parser.Parse(root, code); // Check that no errors were produced. Assert.AreEqual(root.CompilerErrors.Count, 0, "no errors"); }
public void ParseIncorrectLiteral() { string code = @" module bar: def void boo(): b = 9999999999999999s "; var parser = Pie.Parser.Create(); var root = new Root(); parser.Parse(root, code); // Check that no errors were produced. Assert.AreEqual(root.CompilerErrors.Count, 1, "no errors"); Assert.IsTrue(root.CompilerErrors[0] is ParserCompilerError); }