#!/usr/bin/ruby
#
## Boolean type
#
class SBool(Bool val) {
}
#
## String type + methods
#
class SString(String val) {
method +(SString arg) {
SString(val + arg.val);
}
method say() {
self + SString("\n") -> print;
}
method print() {
SBool(Sys.print(val));
}
}
class Interpreter {
#
## Expression executor
#
method execute_expr(statement) {
statement.has_key(:self) || die "Invalid AST!";
var self_obj = statement{:self};
if (self_obj.is_a(Hash)) {
self_obj = self.execute(self_obj);
}
if (statement.has_key(:call)) {
statement{:call}.each { |call|
var meth = call{:method};
if (call.has_key(:arg)) {
var args = call{:arg}.map {|arg|
arg.is_a(Hash) ? self.execute_expr(arg) : arg
};
self_obj = self_obj.(meth)(args...);
}
else {
self_obj = self_obj.(meth);
}
}
};
return self_obj;
}
#
## Parse-tree executor
#
method execute(structure) {
var results = [];
structure.has_key(:main) || die "Invalid AST!";
structure{:main}.each { |statement|
results.append(self.execute_expr(statement));
};
results[-1];
}
}
#
## The AST
#
var ast = Hash.new(
:main => [
Hash.new(
:call => [Hash.new(:method => "print")],
:self => Hash.new(
:main => [
Hash.new(
:call => [Hash.new(:method => "+", :arg => [Hash.new(:self => SString("llo"))])],
:self => SString("he"),
)
],
)
),
Hash.new(
:call => [Hash.new(:method => "say")],
:self => SString(" world!");
),
]
);
#
## Begin execution
#
var intr = Interpreter();
intr.execute(ast);