※Rust0.7で作成しました。
今回は以下のリファクタリングを行いました。
- copyは使わなくして、cloneを使うようにしました。
- Joinableというトレイトを作って汎用的なJoinを作りました。
- macroを使って複数のimplを1つに纏めました。
use join::Joinable;
use ast::*;
pub mod ast {
#[deriving(Clone,ToStr)]
pub enum E {
ELdc(~T, int),
EBin(~T, ~str, ~E, ~E),
EPrint(~T, ~E),
EBlock(~T, ~[~E]),
}
macro_rules! EOp(
($T:ident, $op:expr) => (
pub fn $T(t: ~T, a: ~E, b: ~E) -> E {
EBin(t, ~$op, a, b)
}
)
)
EOp!(EAdd, "add")
EOp!(ESub, "sub")
EOp!(EMul, "mul")
EOp!(EDiv, "div")
#[deriving(Clone,ToStr)]
pub enum T {
Ti(int),
Tv,
TFun(~T, ~[~T]),
}
#[deriving(Clone,ToStr)]
pub enum R {
pub RG(~T, ~str),
pub RL(~T, ~str),
pub RR(~T, ~str),
pub RN(~T, ~str),
}
#[deriving(Clone,ToStr)]
pub enum LL {
LLCall(Option<~R>, ~R, ~[~R]),
LLBin(Option<~R>, ~str, ~R, ~R),
}
macro_rules! impl_ToStr_for(
($T:ty) => (
impl ToStr for $T {
#[inline]
fn to_str(&self) -> ~str {
fmt!("%?", *self)
}
}
)
)
macro_rules! impl_ToStr_for_Option(
($T:ty) => (
impl ToStr for Option<$T> {
fn to_str(&self) -> ~str {
match *self {
Some(ref r) => fmt!("Some(%?)",r),
None => ~"None",
}
}
}
)
)
impl_ToStr_for!(~E)
impl_ToStr_for!(~T)
impl_ToStr_for!(~R)
impl_ToStr_for!(~LL)
impl_ToStr_for_Option!(~R)
impl Eq for T {
pub fn eq(&self, t:&T) -> bool {
self.to_str() == t.to_str()
}
pub fn ne(&self, t:&T) -> bool {
!(self == t)
}
}
impl R {
pub fn t(&self) -> ~T {
match *self {
RG(ref t, _) => t.clone(),
RL(ref t, _) => t.clone(),
RR(ref t, _) => t.clone(),
RN(ref t, _) => t.clone(),
}
}
}
pub trait P {
fn p(&self) -> ~str;
}
impl P for T {
pub fn p(&self) -> ~str {
match *self {
Ti(ref i) => "i" + i.to_str(),
Tv => ~"void",
TFun(ref t, ref ls) => {
t.p() + "(" + ls.map(|t| t.p()).join(", ") + ")*"
}
}
}
}
impl P for R {
pub fn p(&self) -> ~str {
match *self {
RG(_,ref id) => "@" + *id,
RL(_,ref id) => "%" + *id,
RR(_,ref id) => "%." + *id,
RN(_,ref id) => id.clone(),
}
}
}
}
fn main() {
// println(os::getcwd().to_str());
// println(os::getenv("PATH").unwrap());
// os::setenv("PATH", os::getenv("PATH").unwrap());
// println(readAll("test.rs"));
// writeAll("tes.txt", "hogehoge");
let ast = ~EBlock(~Tv, ~[
~EPrint(~Ti(32), ~ELdc(~Ti(32), 11)),
~EPrint(~Ti(32),
~EAdd(~Ti(32), ~ELdc(~Ti(32), 11), ~ELdc(~Ti(32), 22)))
]);
println("ast=" + ast.to_str());
let ll = kNormal(ast);
println("ll=" + ll.to_str());
emit("e.ll", ll);
println(exec("llc e.ll -o e.s").to_str());
println(exec("llvm-gcc -m64 e.s -o e").to_str());
println(exec("./e").to_str());
}
mod interpreter {
use ast::*;
fn eval(e:&E)->int {
match e {
&ELdc(_, i) => i,
&EBin(_, ~"add", ref a, ref b) => eval(*a) + eval(*b),
&EBin(_, ref op, _, _) => fail!("operator "+*op),
&EPrint(_, ref e) => {
let e = eval(*e);
println(e.to_str());
e
}
&EBlock(_, ref ls) => {
fn f(ls:&[~E],r:int)-> int {
match ls {
[] => r,
[ref a, ..rest] => f(rest,eval(*a))
}
}
f(*ls, 0)
}
}
}
}
mod kNormal {
use ast::*;
use std::vec;
fn gid(t:&T)-> ~R {
~RR(~(*t).clone(),~"")
}
static mut ls:Option<~[~LL]> = None;
fn add(l:~LL) {
unsafe {
ls = Some(vec::append_one(ls.unwrap(), l));
}
}
fn f(a: &E)-> ~R {
match a {
&EBin(ref t,ref op, ref a, ref b) => {
let a = f(*a);
let b = f(*b);
let id = gid(*t);
if (*t != a.t() || *t != b.t()) {fail!(fmt!("type mismatch %?",*t));}
add(~LLBin(Some(id.clone()), op.clone(), a, b));
id
}
&ELdc(ref t, ref i) => ~RN(t.clone(), i.to_str()),
&EPrint(ref t, ref a) => {
let a = f(*a);
if (*t != a.t()) {fail!(fmt!("type mismatch t=%? ta=%?", t, a.t()))}
add(~LLCall(None, ~RG(~TFun(~Tv, ~[t.clone()]), "print_" + t.p()), ~[a.clone()]));
a
}
&EBlock(_,ref ls) => {
fn f2(ls:&[~E],r:&R)-> ~R {
match ls {
[] => ~r.clone(),
[ref e, ..rest] => f2(rest,f(*e)),
}
}
f2(*ls, ~RN(~Tv,~""))
}
}
}
pub fn apply(e: &E) -> ~[~LL] {
unsafe {
ls = Some(~[]);
f(e);
ls.unwrap()
}
}
}
fn kNormal(a: &ast::E) -> ~[~ast::LL] {
kNormal::apply(a)
}
pub mod emit {
use ast::*;
use asm;
fn o(id: &Option<~R>, out: &str) {
match id {
&Some(ref id) =>asm::__(id.p() + " = " + out),
&None => asm::__(out),
}
}
fn emitLL(l: &LL) {
match l {
&LLCall(ref id, ref op, ref prms) => {
let prms:~[~str] = prms.map(|a| a.t().p() + " " + a.p());
o(id, fmt!("call %s %s(%s) nounwind",
op.t().p(), op.p(), prms.join(", ")))
}
&LLBin(ref id, ref op, ref a, ref b) => {
o(id, fmt!("%s %s %s, %s", *op, a.t().p(), a.p(), b.p()))
}
}
}
pub fn apply(file: &str, ls: &[~LL]) {
asm::open(file);
asm("@.str = private constant [4 x i8] c\"%d\\0A\\00\"");
asm("define void @print_i32(i32 %a) nounwind ssp {");
asm("entry:");
asm::__("call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i32 %a) nounwind");
asm::__("ret void");
asm("}");
asm("define void @print_i8(i8 %a) nounwind ssp {");
asm("entry:");
asm::__("call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i64 0, i64 0), i8 %a) nounwind");
asm::__("ret void");
asm("}");
asm("declare i32 @printf(i8*, ...) nounwind");
asm("define i32 @main() nounwind ssp {");
asm("entry:");
ls.map(|l| emitLL(*l));
asm::__("ret i32 0");
asm("}");
asm::close();
}
}
pub fn emit(file: &str, ls: &[~ast::LL]) {
emit::apply(file, ls);
}
pub fn genid(s:&str) -> ~str {
static mut id:int = 0;
unsafe {
id += 1;
s + id.to_str()
}
}
fn readAll(file:&str) -> ~str {
use std::io;
use std::result;
let reader = result::get(&io::file_reader(&Path(file)));
let mut s = ~"";
while !reader.eof() {
s = s + reader.read_line() + "\n";
}
s
}
fn writeAll(file:&str, s:&str) {
use std::io;
use std::result;
let writer = result::get(&io::buffered_file_writer(&Path(file)));
writer.write_str(s);
}
pub mod asm {
use std::io;
use std::result;
pub static mut writer: Option<@Writer> = None;
pub fn open(file:&str) {
unsafe {
writer = Some(result::get(&io::buffered_file_writer(&Path(file))));
}
}
pub fn println(s:&str) {
unsafe {
writer.unwrap().write_str(s + "\n");
}
}
pub fn close() {
unsafe {
writer = None;
}
}
pub fn __(s:&str) {
println(" " + s);
}
}
pub fn asm(s:&str) {
asm::println(s);
}
fn exec(cmd:&str) -> (int, ~str, ~str) {
use std::str;
use std::run;
let mut cmds:~[&str] = cmd.split_str_iter(" ").collect();
let prog:~str = cmds.shift().to_str();
let args:~[~str] = cmds.map(|&s| s.to_str());
let o = run::process_output(prog,args);
unsafe {
(o.status,
str::raw::from_bytes(o.output),
str::raw::from_bytes(o.error),
)
}
}
pub mod join {
pub trait Joinable<T> {
fn join(&self, sep:&str) -> ~str;
}
impl<T:ToStr> Joinable<T> for ~[T] {
fn join(&self, sep:&str) -> ~str {
let mut s:~str = ~"";
for (*self).iter().advance |t| {
match s {
~"" => s = t.to_str(),
_ => s = s + sep + t.to_str(),
}
}
s
}
}
}