Create 'def' special form to define global value ( not functions at the moment )

This commit is contained in:
Sameer Rahmani 2020-09-20 22:22:18 +01:00
parent fe1724ce22
commit 40bcb3b16c
11 changed files with 140 additions and 42 deletions

View File

@ -1,3 +1,3 @@
(def a 4)
(def a true)
;; (defn hello! (name)
;; (println "Hello %s" name))

View File

@ -58,7 +58,7 @@ impl Expr {
impl Expression for Expr {
fn eval() {}
fn code_gen<'ctx>(&self, compiler: &'ctx Compiler) -> ExprResult<'ctx> {
fn code_gen<'ctx, 'val: 'ctx>(&self, compiler: &'ctx mut Compiler<'val>) -> ExprResult<'val> {
match self {
Expr::Sym(s) => s.code_gen(compiler),
Expr::Cons(s) => s.code_gen(compiler),

View File

@ -14,11 +14,13 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::ast::Expr;
use crate::compiler::Compiler;
use crate::types::collections::core::Seq;
use crate::types::{ExprResult, List};
use crate::types::{ExprResult, Expression, List};
use crate::values::Value;
pub fn def<'a>(compiler: &'a Compiler, args: List) -> ExprResult<'a> {
pub fn def<'ctx, 'val: 'ctx>(compiler: &'ctx mut Compiler<'val>, args: List) -> ExprResult<'val> {
// TODO: We need to support docstrings for def
if args.length() != 2 {
// TODO: Raise a meaningful error by including the location
@ -28,12 +30,24 @@ pub fn def<'a>(compiler: &'a Compiler, args: List) -> ExprResult<'a> {
));
}
//let def_ = &args.first;1
let name = args.first();
let value = args.rest().first();
let sym = match args.first() {
Some(e) => match e {
Expr::Sym(e) => e,
_ => return Err("First argument of 'def' has to be a symbol".to_string()),
},
_ => return Err("First argument of 'def' has to be a symbol".to_string()),
};
println!("<<<< {:?} \n {:?}", name, value);
// TODO: make sure that `def_` is a symbol and its name is "def"
let value = match args.rest().first() {
Some(e) => {
let generated_code = e.code_gen(compiler);
Value::new(Some(sym.name.clone()), e, generated_code)
}
_ => return Err("Missing the second arugment for 'def'.".to_string()),
};
Err("Is not completed".to_string())
compiler
.current_ns()
.unwrap()
.define(sym.name.clone(), value, true)
}

View File

@ -16,7 +16,7 @@
*/
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::passes::PassManager;
//use inkwell::passes::PassManager;
use inkwell::values::{AnyValueEnum, BasicValue, FloatValue, FunctionValue, PointerValue};
use crate::namespace::Namespace;
@ -35,9 +35,9 @@ pub struct Compiler<'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<&'ctx str, Namespace<'ctx>>,
pub namespaces: HashMap<String, Namespace<'ctx>>,
//pub fpm: &'a PassManager<FunctionValue<'ctx>>,
current_ns_name: Option<&'ctx str>,
current_ns_name: Option<String>,
}
impl<'ctx> Compiler<'ctx> {
@ -64,24 +64,28 @@ impl<'ctx> Compiler<'ctx> {
}
}
pub fn create_ns(&mut self, ns_name: &'ctx str) {
self.namespaces
.insert(ns_name, Namespace::new(&self.context, ns_name));
pub fn create_ns(&mut self, ns_name: String, source_file: Option<&'ctx str>) {
self.namespaces.insert(
ns_name.clone(),
Namespace::new(&self.context, ns_name, None),
);
}
pub fn set_current_ns(&mut self, ns_name: &'ctx str) {
pub fn set_current_ns(&mut self, ns_name: String) {
self.current_ns_name = Some(ns_name);
}
#[inline]
pub fn current_ns(&self) -> Option<&Namespace<'ctx>> {
let ns = self.current_ns_name?;
self.namespaces.get(ns).map(|x| x)
pub fn current_ns(&mut self) -> Option<&mut Namespace<'ctx>> {
match &self.current_ns_name {
Some(ns) => self.namespaces.get_mut(ns).map(|x| x),
_ => None,
}
}
/// Returns the `FunctionValue` representing the function being compiled.
#[inline]
pub fn current_fn(&self) -> FunctionValue<'ctx> {
pub fn current_fn(&mut self) -> FunctionValue<'ctx> {
self.current_ns().unwrap().current_fn()
}
@ -106,16 +110,16 @@ pub fn create_context() -> Context {
/// Compiles the given `ast` using the given `compiler` into
/// LLVM IR.
pub fn compile<'ctx>(
compiler: &'ctx Compiler,
pub fn compile<'ctx, 'val: 'ctx>(
compiler: &'ctx mut Compiler<'val>,
ast: Vec<impl Expression>,
) -> Vec<Result<AnyValueEnum<'ctx>, String>> {
) -> Vec<Result<AnyValueEnum<'val>, String>> {
match compiler.current_ns() {
Some(ns) => ns,
None => panic!("Current namespace is not set."),
};
let mut generated_code = vec![];
let mut generated_code: Vec<Result<AnyValueEnum<'val>, String>> = vec![];
for expr in &ast {
generated_code.push(expr.code_gen(compiler));

View File

@ -39,8 +39,8 @@ fn main() -> io::Result<()> {
let context = compiler::create_context();
let mut compiler = compiler::Compiler::new(&context);
compiler.create_ns("user");
compiler.set_current_ns("user");
compiler.create_ns("user".to_string(), None);
compiler.set_current_ns("user".to_string());
if let Some(input) = args.value_of("INPUT") {
let mut f = File::open(input)?;
@ -51,7 +51,7 @@ fn main() -> io::Result<()> {
Ok(v) => {
println!("AST: {:#?}", v);
let g = compiler::compile(&compiler, v);
let g = compiler::compile(&mut compiler, v);
println!("GEN: {:?}", g)
}
Err(e) => println!(">> error {:?}", e),

View File

@ -15,9 +15,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::scope::Scope;
use crate::types::ExprResult;
use crate::values::Value;
use inkwell::context::Context;
use inkwell::module::Module;
use inkwell::values::FunctionValue;
use inkwell::types::{AnyTypeEnum, BasicType, FunctionType};
use inkwell::values::{AnyValueEnum, FunctionValue};
pub struct Namespace<'ctx> {
/// Each namespace in serene contains it's own LLVM module. You can
@ -36,9 +39,17 @@ pub struct Namespace<'ctx> {
}
impl<'ctx> Namespace<'ctx> {
pub fn new(context: &'ctx Context, name: &str) -> Namespace<'ctx> {
pub fn new(
context: &'ctx Context,
name: String,
source_file: Option<&'ctx str>,
) -> Namespace<'ctx> {
let module = context.create_module(&name);
module.set_source_file_name(source_file.unwrap_or(&name));
Namespace {
module: context.create_module(&name),
module,
//scope: Scope::new(None),
current_fn_opt: None,
scope: Scope::new(None),
@ -56,4 +67,58 @@ impl<'ctx> Namespace<'ctx> {
pub fn current_fn(&self) -> FunctionValue<'ctx> {
self.current_fn_opt.unwrap()
}
fn define_function(
&self,
name: String,
value: Value<'ctx>,
public: bool,
f: FunctionType<'ctx>,
) -> ExprResult<'ctx> {
Err("NotImpelemnted".to_string())
}
fn define_value(
&mut self,
name: String,
value: Value<'ctx>,
public: bool,
t: impl BasicType<'ctx>,
) -> ExprResult<'ctx> {
let c = self.module.add_global(t, None, &name);
match value.llvm_value {
Ok(v) => {
match v {
AnyValueEnum::ArrayValue(a) => c.set_initializer(&a),
AnyValueEnum::IntValue(i) => c.set_initializer(&i),
AnyValueEnum::FloatValue(f) => c.set_initializer(&f),
AnyValueEnum::PointerValue(p) => c.set_initializer(&p),
AnyValueEnum::StructValue(s) => c.set_initializer(&s),
AnyValueEnum::VectorValue(v) => c.set_initializer(&v),
_ => panic!("It shoudn't happen!!!"),
};
self.scope.insert(&name, value, public);
Ok(v)
}
Err(e) => Err(e),
}
}
pub fn define(&mut self, name: String, value: Value<'ctx>, public: bool) -> ExprResult<'ctx> {
match value.llvm_value {
Ok(r) => match r.get_type() {
AnyTypeEnum::FunctionType(f) => self.define_function(name, value, public, f),
AnyTypeEnum::IntType(i) => self.define_value(name, value, public, i),
AnyTypeEnum::ArrayType(a) => self.define_value(name, value, public, a),
AnyTypeEnum::FloatType(f) => self.define_value(name, value, public, f),
AnyTypeEnum::PointerType(p) => self.define_value(name, value, public, p),
AnyTypeEnum::StructType(s) => self.define_value(name, value, public, s),
AnyTypeEnum::VectorType(v) => self.define_value(name, value, public, v),
_ => Err(format!("Data type '{:?}' is not supported", r.get_type())),
},
Err(e) => Err(e),
}
}
}

View File

@ -47,10 +47,11 @@ impl List {
impl Expression for List {
fn eval() {}
fn code_gen<'ctx>(&self, compiler: &'ctx Compiler) -> ExprResult<'ctx> {
fn code_gen<'ctx, 'val: 'ctx>(&self, compiler: &'ctx mut Compiler<'val>) -> ExprResult<'val> {
match self.first() {
Some(e) => match e {
Expr::Sym(s) if s.is_def() => def(compiler, self.rest()),
_ => Err("Not implemented on list".to_string()),
},

View File

@ -15,11 +15,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::compiler::Compiler;
use inkwell::values::AnyValueEnum;
use inkwell::values::{AnyValue, AnyValueEnum};
pub type ExprResult<'a> = Result<AnyValueEnum<'a>, String>;
type ExprResultBase<'a, T: AnyValue<'a>> = Result<T, String>;
pub type ExprResult<'a> = ExprResultBase<'a, AnyValueEnum<'a>>;
pub trait Expression {
fn eval();
fn code_gen<'ctx>(&self, compiler: &'ctx Compiler) -> ExprResult<'ctx>;
fn code_gen<'ctx, 'val: 'ctx>(&self, compiler: &'ctx mut Compiler<'val>) -> ExprResult<'val>;
}

View File

@ -46,7 +46,7 @@ impl Eq for Number {}
impl Expression for Number {
fn eval() {}
fn code_gen<'ctx>(&self, compiler: &'ctx Compiler) -> ExprResult<'ctx> {
fn code_gen<'ctx, 'val: 'ctx>(&self, compiler: &'ctx mut Compiler<'val>) -> ExprResult<'val> {
Err("Not implemented on numbers".to_string())
}
}

View File

@ -16,6 +16,7 @@
*/
use crate::compiler::Compiler;
use crate::types::core::{ExprResult, Expression};
use inkwell::types::IntType;
use inkwell::values::AnyValueEnum;
#[derive(Debug, Clone)]
@ -33,8 +34,8 @@ impl Eq for Symbol {}
impl Expression for Symbol {
fn eval() {}
fn code_gen<'ctx>(&self, compiler: &'ctx Compiler) -> ExprResult<'ctx> {
let bool_t = compiler.context.bool_type();
fn code_gen<'ctx, 'val: 'ctx>(&self, compiler: &'ctx mut Compiler<'val>) -> ExprResult<'val> {
let bool_t: IntType<'val> = compiler.context.bool_type();
if self.name == "true" {
Ok(AnyValueEnum::IntValue(bool_t.const_int(1, false)))
} else if self.name == "false" {

View File

@ -15,10 +15,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::ast::Expr;
use inkwell::values::AnyValueEnum;
use crate::types::ExprResult;
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Value<'a> {
llvm_id: Option<&'a str>,
lllvm_value: AnyValueEnum<'a>,
expr: &'a Expr,
pub llvm_id: Option<String>,
pub llvm_value: ExprResult<'a>,
pub expr: Expr,
}
impl<'a> Value<'a> {
pub fn new(name: Option<String>, expr: Expr, value: ExprResult<'a>) -> Value {
Value {
llvm_id: name,
llvm_value: value,
expr: expr,
}
}
}