Add basic namespace and scope support
This commit is contained in:
parent
04cadf7152
commit
402e267e7c
14
src/ast.rs
14
src/ast.rs
|
@ -1,4 +1,5 @@
|
|||
use crate::types::{Expression, List, Number, Symbol};
|
||||
use crate::namespace::Namespace;
|
||||
use crate::types::{ExprResult, Expression, List, Number, Symbol};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub enum Expr {
|
||||
|
@ -12,7 +13,7 @@ pub enum Expr {
|
|||
NoMatch,
|
||||
}
|
||||
|
||||
impl Expr {
|
||||
impl<'a> Expr {
|
||||
pub fn make_list(first: Expr, rest: Expr) -> Expr {
|
||||
Expr::Cons(List::<Expr>::new(Box::new(first), Box::new(rest)))
|
||||
}
|
||||
|
@ -30,7 +31,12 @@ impl Expr {
|
|||
}
|
||||
}
|
||||
|
||||
impl Expression for Expr {
|
||||
impl<'a> Expression<'a> for Expr {
|
||||
fn eval() {}
|
||||
fn code_gen() {}
|
||||
fn code_gen(&self, ns: &Namespace) -> ExprResult<'a> {
|
||||
match self {
|
||||
Expr::Sym(s) => s.code_gen(ns),
|
||||
_ => Err("NotImplemented".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,9 +7,32 @@ use crate::namespace::Namespace;
|
|||
use crate::types::Expression;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub fn create_compiler<'a, 'ctx>() -> Compiler<'a, 'ctx> {
|
||||
let default_ns_name = "user";
|
||||
let context = Context::create();
|
||||
let builder = context.create_builder();
|
||||
let mut namespaces = HashMap::new();
|
||||
let user_ns = Namespace::new(&context, default_ns_name);
|
||||
namespaces.insert(default_ns_name, &user_ns);
|
||||
let fpm = PassManager::create(&user_ns.module);
|
||||
|
||||
fpm.add_instruction_combining_pass();
|
||||
fpm.add_reassociate_pass();
|
||||
fpm.add_gvn_pass();
|
||||
fpm.add_cfg_simplification_pass();
|
||||
fpm.add_basic_alias_analysis_pass();
|
||||
fpm.add_promote_memory_to_register_pass();
|
||||
fpm.add_instruction_combining_pass();
|
||||
fpm.add_reassociate_pass();
|
||||
|
||||
fpm.initialize();
|
||||
|
||||
Compiler::new(context, builder, fpm, namespaces, Some(&default_ns_name))
|
||||
}
|
||||
|
||||
pub struct Compiler<'a, 'ctx> {
|
||||
pub context: &'ctx Context,
|
||||
pub builder: &'a Builder<'ctx>,
|
||||
pub context: Context,
|
||||
pub builder: Builder<'ctx>,
|
||||
/// This hashmap contains all the namespaces that has to be compiled and
|
||||
/// maps two different keys to the same namespace. Since namespace names
|
||||
/// can not contain `/` char, the keys of this map are the namespace
|
||||
|
@ -19,13 +42,28 @@ pub struct Compiler<'a, 'ctx> {
|
|||
/// two entries in this hashmap. One would be the ns name itself which
|
||||
/// is `abc.xyz` in this case and the otherone would be
|
||||
/// `/path/to/abc/xyz.srn` file that contains the ns.
|
||||
pub namespaces: HashMap<String, &'a Namespace<'a, 'ctx>>,
|
||||
pub namespaces: &'a HashMap<&'a str, &'a Namespace<'a, 'ctx>>,
|
||||
pub fpm: &'a PassManager<FunctionValue<'ctx>>,
|
||||
|
||||
current_ns_name: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl<'a, 'ctx> Compiler<'a, 'ctx> {
|
||||
pub fn new(
|
||||
context: Context,
|
||||
builder: Builder<'ctx>,
|
||||
fpm: PassManager<FunctionValue<'ctx>>,
|
||||
namespaces: HashMap<&'a str, &'a Namespace<'a, 'ctx>>,
|
||||
ns_name: Option<&'a str>,
|
||||
) -> Compiler<'a, 'ctx> {
|
||||
Compiler {
|
||||
context: context,
|
||||
namespaces: &namespaces,
|
||||
fpm: &fpm,
|
||||
builder: builder,
|
||||
current_ns_name: ns_name,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn current_ns(&self) -> Option<&'a Namespace<'a, 'ctx>> {
|
||||
let ns = self.current_ns_name?;
|
||||
|
@ -39,18 +77,35 @@ impl<'a, 'ctx> Compiler<'a, 'ctx> {
|
|||
}
|
||||
|
||||
/// Creates a new stack allocation instruction in the entry block of the function.
|
||||
fn create_entry_block_alloca(&self, name: &str) -> PointerValue<'ctx> {
|
||||
let builder = self.context.create_builder();
|
||||
// fn create_entry_block_alloca(&self, name: &str) -> PointerValue<'ctx> {
|
||||
// let builder = self.context.create_builder();
|
||||
|
||||
let entry = self.current_fn().get_first_basic_block().unwrap();
|
||||
// let entry = self.current_fn().get_first_basic_block().unwrap();
|
||||
|
||||
match entry.get_first_instruction() {
|
||||
Some(first_instr) => builder.position_before(&first_instr),
|
||||
None => builder.position_at_end(entry),
|
||||
// match entry.get_first_instruction() {
|
||||
// Some(first_instr) => builder.position_before(&first_instr),
|
||||
// None => builder.position_at_end(entry),
|
||||
// }
|
||||
|
||||
// builder.build_alloca(self.context.f64_type(), name)
|
||||
// }
|
||||
|
||||
pub fn compile(
|
||||
&self,
|
||||
exprs: Vec<&impl Expression<'ctx>>,
|
||||
) -> Vec<Result<PointerValue<'ctx>, String>> {
|
||||
let current_ns = match self.current_ns() {
|
||||
Some(ns) => ns,
|
||||
None => panic!("Current namespace is not set."),
|
||||
};
|
||||
|
||||
let mut generated_code = vec![];
|
||||
|
||||
for expr in &exprs {
|
||||
let code = expr.code_gen(current_ns);
|
||||
generated_code.push(code);
|
||||
}
|
||||
|
||||
builder.build_alloca(self.context.f64_type(), name)
|
||||
generated_code
|
||||
}
|
||||
|
||||
pub fn compile(exprs: &impl Expression) {}
|
||||
}
|
||||
|
|
|
@ -10,11 +10,15 @@ pub mod ast;
|
|||
pub mod compiler;
|
||||
pub mod namespace;
|
||||
pub mod reader;
|
||||
pub mod scope;
|
||||
pub mod types;
|
||||
|
||||
use crate::compiler::create_compiler;
|
||||
|
||||
fn main() -> io::Result<()> {
|
||||
let yaml = load_yaml!("cli.yml");
|
||||
let args = App::from(yaml).get_matches();
|
||||
let compiler = create_compiler();
|
||||
|
||||
if let Some(input) = args.value_of("INPUT") {
|
||||
let mut f = File::open(input)?;
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
use crate::scope::Scope;
|
||||
use inkwell::context::Context;
|
||||
use inkwell::module::Module;
|
||||
use inkwell::values::{FunctionValue, PointerValue};
|
||||
use std::collections::HashMap;
|
||||
use inkwell::values::FunctionValue;
|
||||
|
||||
pub struct Namespace<'a, 'ctx> {
|
||||
/// Each namespace in serene contains it's own LLVM module. You can
|
||||
/// think of modules as compilation units. Object files if you prefer.
|
||||
/// This way we should be able to hot swap the namespaces.
|
||||
pub module: &'a Module<'ctx>,
|
||||
pub module: Module<'ctx>,
|
||||
|
||||
scope: HashMap<String, PointerValue<'ctx>>,
|
||||
scope: Scope<'a>,
|
||||
|
||||
// The option of the current function being compiled
|
||||
current_fn_opt: Option<FunctionValue<'ctx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'ctx> Namespace<'a, 'ctx> {
|
||||
pub fn new(context: &'ctx Context, name: &str) -> Namespace<'a, 'ctx> {
|
||||
let module = context.create_module(&name);
|
||||
Namespace {
|
||||
module: module,
|
||||
scope: Scope::new(None),
|
||||
current_fn_opt: None,
|
||||
}
|
||||
}
|
||||
/// Gets a defined function given its name.
|
||||
#[inline]
|
||||
pub fn get_function(&self, name: &str) -> Option<FunctionValue<'ctx>> {
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::ast::Expr;
|
|||
use crate::types::Number;
|
||||
use std::io::{BufReader, Read};
|
||||
|
||||
pub type ReadResult = Result<Expr, String>;
|
||||
pub type ReadResult<'a> = Result<Expr, String>;
|
||||
|
||||
pub struct ExprReader {
|
||||
location: i32,
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
use inkwell::values::PointerValue;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub struct Scope<'a> {
|
||||
parent: Option<Box<Scope<'a>>>,
|
||||
symbol_table: HashMap<String, PointerValue<'a>>,
|
||||
}
|
||||
|
||||
impl<'a> Scope<'a> {
|
||||
pub fn new(_parent: Option<Scope>) -> Scope {
|
||||
let p = match _parent {
|
||||
Some(x) => Some(Box::new(x)),
|
||||
None => None,
|
||||
};
|
||||
|
||||
Scope {
|
||||
parent: p,
|
||||
symbol_table: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn lookup(&self, key: &str) -> Option<PointerValue> {
|
||||
self.symbol_table.get(key).map(|x| *x)
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: &str, val: PointerValue<'a>) {
|
||||
self.symbol_table.insert(key.to_string(), val);
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ pub mod list;
|
|||
pub mod number;
|
||||
pub mod symbol;
|
||||
|
||||
pub use self::core::Expression;
|
||||
pub use self::core::{ExprResult, Expression};
|
||||
pub use self::list::List;
|
||||
pub use self::number::Number;
|
||||
pub use self::symbol::Symbol;
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
pub trait Expression {
|
||||
use crate::namespace::Namespace;
|
||||
use inkwell::values::PointerValue;
|
||||
|
||||
pub type ExprResult<'a> = Result<PointerValue<'a>, String>;
|
||||
|
||||
pub trait Expression<'a> {
|
||||
fn eval();
|
||||
fn code_gen();
|
||||
fn code_gen(&self, ns: &Namespace) -> ExprResult<'a>;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,33 @@
|
|||
use crate::types::core::Expression;
|
||||
use crate::namespace::Namespace;
|
||||
use crate::types::core::{ExprResult, Expression};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||
pub struct List<T: Expression> {
|
||||
pub struct List<T>
|
||||
where
|
||||
for<'a> T: Expression<'a>,
|
||||
{
|
||||
first: Box<T>,
|
||||
rest: Box<T>,
|
||||
}
|
||||
|
||||
impl<T: Expression> List<T> {
|
||||
pub fn new<S: Expression>(first: Box<S>, rest: Box<S>) -> List<S> {
|
||||
impl<T> List<T>
|
||||
where
|
||||
for<'a> T: Expression<'a>,
|
||||
{
|
||||
pub fn new<S>(first: Box<S>, rest: Box<S>) -> List<S>
|
||||
where
|
||||
for<'a> S: Expression<'a>,
|
||||
{
|
||||
List { first, rest }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Expression> Expression for List<T> {
|
||||
impl<'a, T> Expression<'a> for List<T>
|
||||
where
|
||||
for<'b> T: Expression<'b>,
|
||||
{
|
||||
fn eval() {}
|
||||
fn code_gen() {}
|
||||
fn code_gen(&self, ns: &Namespace) -> ExprResult<'a> {
|
||||
Err("Not implemented on list".to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::types::Expression;
|
||||
|
||||
use crate::namespace::Namespace;
|
||||
use crate::types::core::{ExprResult, Expression};
|
||||
// Note: I kept the number implementation simple for now
|
||||
// but we need to decide on our approach to numbers, are
|
||||
// we going to only support the 64bit variants? or should
|
||||
|
@ -28,7 +28,9 @@ impl PartialEq for Number {
|
|||
|
||||
impl Eq for Number {}
|
||||
|
||||
impl Expression for Number {
|
||||
impl<'a> Expression<'a> for Number {
|
||||
fn eval() {}
|
||||
fn code_gen() {}
|
||||
fn code_gen(&self, ns: &Namespace) -> ExprResult<'a> {
|
||||
Err("Not implemented on numbers".to_string())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::types::Expression;
|
||||
use crate::namespace::Namespace;
|
||||
use crate::types::core::{ExprResult, Expression};
|
||||
use inkwell::values::PointerValue;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Symbol {
|
||||
|
@ -13,9 +15,11 @@ impl PartialEq for Symbol {
|
|||
|
||||
impl Eq for Symbol {}
|
||||
|
||||
impl Expression for Symbol {
|
||||
impl<'a> Expression<'a> for Symbol {
|
||||
fn eval() {}
|
||||
fn code_gen() {}
|
||||
fn code_gen(&self, ns: &Namespace) -> ExprResult<'a> {
|
||||
Err("Not implemented on symbol".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
impl Symbol {
|
||||
|
|
Loading…
Reference in New Issue