A simple object-oriented programming language compiler written as an assesment task for MIMUW Compiler Construction course.
To build the compiler one needs stack
program installed. The Makefile
will try to search for it in PATH
and in places that could be used on MIMUW machines. If you don’t have stack
, please navigate to their website.
The make
script will automatically download all dependencies. They can be inspected in the configuration file package.yaml
. Please note that it may require some free disk space and internet connection, as it will download GHC along with required libraries.
Standard stack
style is in use.
Main part of code is settled in the src
folder which is divided to Frontend
and Backend
subfolders. In the former one there is whole logic related to parsing, typechecking, AST optimization and intermediate representation. The latter contains final compiler parts – currently only x86-32bit one.
Directory stdlib
contains standard library implemented in C language. Note that the compiler makes use of the temporary folder (/tmp/
on linux) and therefore it needs access to it. I will use gcc
and assume that it can be found in the PATH
.
In the app
folder there is the Main.hs
file which is the entrypoint to the compiler.
The language supports standard instructions like variable declarations, if-else statements, while loops, first order functions, etc. Uses strict and static type system.
Classes support inheritance and virtual method overriding. The syntax is very similar to the one known from Java. Example:
class Base {
new() { }
new smart(int x) {
if (x == 0) {
Sub1 o;
return o;
} else if (x == 1) {
Sub2 o;
return o;
} else if (x == 2) {
Sub3 o;
return o;
} else return this;
}
public int f(int x) {
printInt(x);
return 21;
}
}
class Sub1 extends Base {
int f(int x) {
printInt(x);
return 42;
}
}
class Sub2 extends Base {
int f(int x) {
printInt(x);
return super.f(x) + 10000;
}
}
class Sub3 extends Base {}
int main() {
printInt(new Base().f(-1));
printInt(new Base.smart(0).f(0));
printInt(new Base.smart(1).f(1));
printInt(new Base.smart(2).f(2));
printInt(new Base.smart(3).f(3));
return 0;
}
One of the features that goes beyond the standard conventions is a more functional approach to constructors. Each of those actually returns the newly created instance (this
if not explicitly stated). This means that they are capable of returning any other arbitrarily constructed object of their subclass. This feature can be treated as a built-in support for the factory design pattern. Moreover, the constructors can have names (awesome, isn’t it?).
The compiler performs some basic expression evaluation and constant propagation (does not inline functions tho). Dead code elimination is also supported. TCO will optimize functions where all self references are in tail positions. As the last thing it does peephole optimization on produced assembly.
TODO: reasonable register allocation, because the current one is bruteforced