Make newtype for LLVM code strings

This commit is contained in:
greg 2017-01-23 19:11:50 -08:00
parent 5103f03fa5
commit fd4610e175
4 changed files with 57 additions and 53 deletions

View File

@ -8,6 +8,8 @@ pub struct ParseError {
pub msg: String, pub msg: String,
} }
pub struct LLVMCodeString(pub String);
pub trait ProgrammingLanguage<Evaluator> { pub trait ProgrammingLanguage<Evaluator> {
type Token: Debug; type Token: Debug;
type AST: Debug; type AST: Debug;
@ -15,5 +17,5 @@ pub trait ProgrammingLanguage<Evaluator> {
fn tokenize(input: &str) -> Result<Vec<Self::Token>, TokenError>; fn tokenize(input: &str) -> Result<Vec<Self::Token>, TokenError>;
fn parse(input: Vec<Self::Token>) -> Result<Self::AST, ParseError>; fn parse(input: Vec<Self::Token>) -> Result<Self::AST, ParseError>;
fn evaluate(ast: Self::AST, evaluator: &mut Evaluator) -> Vec<String>; fn evaluate(ast: Self::AST, evaluator: &mut Evaluator) -> Vec<String>;
fn compile(ast: Self::AST) -> String; fn compile(ast: Self::AST) -> LLVMCodeString;
} }

View File

@ -6,13 +6,13 @@ use std::path::Path;
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::process; use std::process;
use std::io::Write;
mod schala_lang; mod schala_lang;
use schala_lang::eval::Evaluator; use schala_lang::eval::Evaluator;
use schala_lang::compilation::compilation_sequence;
use schala_lang::Schala; use schala_lang::Schala;
use language::{ProgrammingLanguage, ParseError, TokenError}; use language::{ProgrammingLanguage, ParseError, TokenError, LLVMCodeString};
mod language; mod language;
mod llvm_wrap; mod llvm_wrap;
@ -168,7 +168,7 @@ impl<'a> Repl<'a> {
} }
if self.show_llvm_ir { if self.show_llvm_ir {
let s = T::compile(ast); let LLVMCodeString(s) = T::compile(ast);
output.push_str(&s); output.push_str(&s);
} else { } else {
// for now only handle last output // for now only handle last output
@ -230,3 +230,49 @@ impl<'a> Repl<'a> {
} }
} }
pub fn compilation_sequence(llvm_code: LLVMCodeString, sourcefile: &str) {
use std::process::Command;
let ll_filename = "out.ll";
let obj_filename = "out.o";
let q: Vec<&str> = sourcefile.split('.').collect();
let bin_filename = match &q[..] {
&[name, "schala"] => name,
_ => panic!("Bad filename {}", sourcefile),
};
let LLVMCodeString(llvm_str) = llvm_code;
println!("Compilation process finished for {}", ll_filename);
File::create(ll_filename)
.and_then(|mut f| f.write_all(llvm_str.as_bytes()))
.expect("Error writing file");
let llc_output = Command::new("llc")
.args(&["-filetype=obj", ll_filename, "-o", obj_filename])
.output()
.expect("Failed to run llc");
if !llc_output.status.success() {
println!("{}", String::from_utf8_lossy(&llc_output.stderr));
}
let gcc_output = Command::new("gcc")
.args(&["-o", bin_filename, &obj_filename])
.output()
.expect("failed to run gcc");
if !gcc_output.status.success() {
println!("{}", String::from_utf8_lossy(&gcc_output.stdout));
println!("{}", String::from_utf8_lossy(&gcc_output.stderr));
}
for filename in [obj_filename].iter() {
Command::new("rm")
.arg(filename)
.output()
.expect(&format!("failed to run rm {}", filename));
}
}

View File

@ -2,59 +2,15 @@ extern crate llvm_sys;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::File; use std::fs::File;
use std::io::Write;
use self::llvm_sys::prelude::*; use self::llvm_sys::prelude::*;
use self::llvm_sys::{LLVMIntPredicate, LLVMRealPredicate}; use self::llvm_sys::{LLVMIntPredicate, LLVMRealPredicate};
use schala_lang::parser::{AST, Statement, Function, Prototype, Expression, BinOp}; use schala_lang::parser::{AST, Statement, Function, Prototype, Expression, BinOp};
use language::LLVMCodeString;
use llvm_wrap as LLVMWrap; use llvm_wrap as LLVMWrap;
pub fn compilation_sequence(llvm_code: String, sourcefile: &str) {
use std::process::Command;
let ll_filename = "out.ll";
let obj_filename = "out.o";
let q: Vec<&str> = sourcefile.split('.').collect();
let bin_filename = match &q[..] {
&[name, "schala"] => name,
_ => panic!("Bad filename {}", sourcefile),
};
println!("Compilation process finished for {}", ll_filename);
File::create(ll_filename)
.and_then(|mut f| f.write_all(llvm_code.as_bytes()))
.expect("Error writing file");
let llc_output = Command::new("llc")
.args(&["-filetype=obj", ll_filename, "-o", obj_filename])
.output()
.expect("Failed to run llc");
if !llc_output.status.success() {
println!("{}", String::from_utf8_lossy(&llc_output.stderr));
}
let gcc_output = Command::new("gcc")
.args(&["-o", bin_filename, &obj_filename])
.output()
.expect("failed to run gcc");
if !gcc_output.status.success() {
println!("{}", String::from_utf8_lossy(&gcc_output.stdout));
println!("{}", String::from_utf8_lossy(&gcc_output.stderr));
}
for filename in [obj_filename].iter() {
Command::new("rm")
.arg(filename)
.output()
.expect(&format!("failed to run rm {}", filename));
}
}
type VariableMap = HashMap<String, LLVMValueRef>; type VariableMap = HashMap<String, LLVMValueRef>;
struct CompilationData { struct CompilationData {
@ -66,7 +22,7 @@ struct CompilationData {
current_function: Option<LLVMValueRef>, current_function: Option<LLVMValueRef>,
} }
pub fn compile_ast(ast: AST) -> String { pub fn compile_ast(ast: AST) -> LLVMCodeString {
println!("Compiling!"); println!("Compiling!");
let names: VariableMap = HashMap::new(); let names: VariableMap = HashMap::new();
@ -100,7 +56,7 @@ pub fn compile_ast(ast: AST) -> String {
LLVMWrap::DisposeBuilder(builder); LLVMWrap::DisposeBuilder(builder);
LLVMWrap::DisposeModule(module); LLVMWrap::DisposeModule(module);
LLVMWrap::ContextDispose(context); LLVMWrap::ContextDispose(context);
ret LLVMCodeString(ret)
} }
trait CodeGen { trait CodeGen {

View File

@ -3,7 +3,7 @@ pub mod parser;
pub mod eval; pub mod eval;
pub mod compilation; pub mod compilation;
use language::{ProgrammingLanguage, ParseError, TokenError}; use language::{ProgrammingLanguage, ParseError, TokenError, LLVMCodeString};
pub struct Schala { } pub struct Schala { }
@ -21,7 +21,7 @@ impl<'a> ProgrammingLanguage<eval::Evaluator<'a>> for Schala {
fn evaluate(ast: Self::AST, evaluator: &mut eval::Evaluator) -> Vec<String> { fn evaluate(ast: Self::AST, evaluator: &mut eval::Evaluator) -> Vec<String> {
evaluator.run(ast) evaluator.run(ast)
} }
fn compile(ast: Self::AST) -> String { fn compile(ast: Self::AST) -> LLVMCodeString {
compilation::compile_ast(ast) compilation::compile_ast(ast)
} }
} }