This is the ninth part of the YAUL series. For your convenience you can find other parts in the table of contents in Part 1 — Introduction
Today we are going to describe standard library for YAUL.
Introduction
Every language has it’s own set of common functions. This is probably the most important part of language — programmers do not want to implement basic stuff and they want to use existing API. This is why we should provide common functions for manipulating numbers, strings, arrays. Consider LINQ — it is very powerful part of C#, without it we would need to write boring loops over and over again. However, having LINQ we can simply compose functions invocations and quickly transform collections.
Code
Let’s see the implementation:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace Compiler { public class StandardLibrary { public static IEnumerable< PreparedFunction> GetDeclarations() { var libraryFunctions = GetFunctions(); return libraryFunctions.Select(function => function.GetPreparedFunction()); } public static IEnumerable< Expression> GetDefinitions(IEnumerable< PreparedFunction> declarations) { var libraryFunctions = GetFunctions(); return declarations.Zip(libraryFunctions, (declaration, definition) => Expression.Assign(declaration.Function, definition.Expression)); } private static IEnumerable< StandardLibraryFunction> GetFunctions() { return new List< StandardLibraryFunction> { new StdMax(), new StdPrint(), new StdCos(), new StdMin(), new StdPow() }; } } public abstract class StandardLibraryFunction { public abstract Expression Expression { get; } public abstract String Name { get; } public PreparedFunction GetPreparedFunction() { return new PreparedFunction() { Function = Expression.Variable(Expression.Type, Name), Name = Name }; } } public class StdMax : StandardLibraryFunction { public override Expression Expression { get { Expression< Func< SimpleObject, SimpleObject, SimpleObject>> expression = (obj1, obj2) => obj1 > obj2 ? new SimpleObject(obj1) : new SimpleObject(obj2); return expression; } } public override string Name { get { return "_max"; } } } public class StdMin : StandardLibraryFunction { public override Expression Expression { get { Expression< Func< SimpleObject, SimpleObject, SimpleObject>> expression = (obj1, obj2) => obj1 < obj2 ? new SimpleObject(obj1) : new SimpleObject(obj2); return expression; } } public override string Name { get { return "_min"; } } } public class StdPow : StandardLibraryFunction { public override Expression Expression { get { Expression< Func< SimpleObject, SimpleObject, SimpleObject>> expression = (obj1, obj2) => new SimpleObject(Math.Pow((int) obj1.Value, (int) obj2.Value)); return expression; } } public override string Name { get { return "_pow"; } } } public class StdPrint : StandardLibraryFunction { public static SimpleObject Print(SimpleObject obj) { Console.WriteLine(obj.Value); return new SimpleObject("null"); } public override Expression Expression { get { Expression< Func< SimpleObject, SimpleObject>> expression = obj => Print(obj); return expression; } } public override string Name { get { return "_print"; } } } public class StdCos : StandardLibraryFunction { public override Expression Expression { get { Expression< Func< SimpleObject, SimpleObject>> expression = obj => new SimpleObject((int)Math.Cos((int)obj.Value)); return expression; } } public override string Name { get { return "_cos"; } } } } |
We represent every library function as simple expression, so we can implement them using lambdas. As you can see, it is pretty straightforward. Please also notice that we have a function for printing. We can handle it directly in our parser in this way:
1 2 3 4 5 6 7 8 |
def p_print(p): """ print : PRINT expr ';' """ call = Compiler.FunctionCall() call.Name = "_print" call.Arguments = System.Collections.Generic.List[Compiler.IExpression] ([p[2]]) p[0] = Compiler.ProdecureCall() p[0].FunctionCall = call |
It is just a direct call to function provided in a standard library.
Summary
Well, our language is almost complete. Next time we will finish our parser and try to handle parsing errors. In the last part we will see how to compile YAUL programs to binaries and store them on the hard drive.