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:

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:

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.