Create 'def' special form to define global value ( not functions at the moment )
This commit is contained in:
parent
fe1724ce22
commit
40bcb3b16c
|
@ -1,3 +1,3 @@
|
||||||
(def a 4)
|
(def a true)
|
||||||
;; (defn hello! (name)
|
;; (defn hello! (name)
|
||||||
;; (println "Hello %s" name))
|
;; (println "Hello %s" name))
|
||||||
|
|
|
@ -58,7 +58,7 @@ impl Expr {
|
||||||
|
|
||||||
impl Expression for Expr {
|
impl Expression for Expr {
|
||||||
fn eval() {}
|
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 {
|
match self {
|
||||||
Expr::Sym(s) => s.code_gen(compiler),
|
Expr::Sym(s) => s.code_gen(compiler),
|
||||||
Expr::Cons(s) => s.code_gen(compiler),
|
Expr::Cons(s) => s.code_gen(compiler),
|
||||||
|
|
|
@ -14,11 +14,13 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
use crate::ast::Expr;
|
||||||
use crate::compiler::Compiler;
|
use crate::compiler::Compiler;
|
||||||
use crate::types::collections::core::Seq;
|
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
|
// TODO: We need to support docstrings for def
|
||||||
if args.length() != 2 {
|
if args.length() != 2 {
|
||||||
// TODO: Raise a meaningful error by including the location
|
// 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 sym = match args.first() {
|
||||||
let name = args.first();
|
Some(e) => match e {
|
||||||
let value = args.rest().first();
|
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);
|
let value = match args.rest().first() {
|
||||||
// TODO: make sure that `def_` is a symbol and its name is "def"
|
Some(e) => {
|
||||||
|
let generated_code = e.code_gen(compiler);
|
||||||
Err("Is not completed".to_string())
|
Value::new(Some(sym.name.clone()), e, generated_code)
|
||||||
|
}
|
||||||
|
_ => return Err("Missing the second arugment for 'def'.".to_string()),
|
||||||
|
};
|
||||||
|
|
||||||
|
compiler
|
||||||
|
.current_ns()
|
||||||
|
.unwrap()
|
||||||
|
.define(sym.name.clone(), value, true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*/
|
*/
|
||||||
use inkwell::builder::Builder;
|
use inkwell::builder::Builder;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use inkwell::passes::PassManager;
|
//use inkwell::passes::PassManager;
|
||||||
use inkwell::values::{AnyValueEnum, BasicValue, FloatValue, FunctionValue, PointerValue};
|
use inkwell::values::{AnyValueEnum, BasicValue, FloatValue, FunctionValue, PointerValue};
|
||||||
|
|
||||||
use crate::namespace::Namespace;
|
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
|
// /// two entries in this hashmap. One would be the ns name itself which
|
||||||
// /// is `abc.xyz` in this case and the otherone would be
|
// /// is `abc.xyz` in this case and the otherone would be
|
||||||
// /// `/path/to/abc/xyz.srn` file that contains the ns.
|
// /// `/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>>,
|
//pub fpm: &'a PassManager<FunctionValue<'ctx>>,
|
||||||
current_ns_name: Option<&'ctx str>,
|
current_ns_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> Compiler<'ctx> {
|
impl<'ctx> Compiler<'ctx> {
|
||||||
|
@ -64,24 +64,28 @@ impl<'ctx> Compiler<'ctx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_ns(&mut self, ns_name: &'ctx str) {
|
pub fn create_ns(&mut self, ns_name: String, source_file: Option<&'ctx str>) {
|
||||||
self.namespaces
|
self.namespaces.insert(
|
||||||
.insert(ns_name, Namespace::new(&self.context, ns_name));
|
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);
|
self.current_ns_name = Some(ns_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_ns(&self) -> Option<&Namespace<'ctx>> {
|
pub fn current_ns(&mut self) -> Option<&mut Namespace<'ctx>> {
|
||||||
let ns = self.current_ns_name?;
|
match &self.current_ns_name {
|
||||||
self.namespaces.get(ns).map(|x| x)
|
Some(ns) => self.namespaces.get_mut(ns).map(|x| x),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `FunctionValue` representing the function being compiled.
|
/// Returns the `FunctionValue` representing the function being compiled.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn current_fn(&self) -> FunctionValue<'ctx> {
|
pub fn current_fn(&mut self) -> FunctionValue<'ctx> {
|
||||||
self.current_ns().unwrap().current_fn()
|
self.current_ns().unwrap().current_fn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,16 +110,16 @@ pub fn create_context() -> Context {
|
||||||
|
|
||||||
/// Compiles the given `ast` using the given `compiler` into
|
/// Compiles the given `ast` using the given `compiler` into
|
||||||
/// LLVM IR.
|
/// LLVM IR.
|
||||||
pub fn compile<'ctx>(
|
pub fn compile<'ctx, 'val: 'ctx>(
|
||||||
compiler: &'ctx Compiler,
|
compiler: &'ctx mut Compiler<'val>,
|
||||||
ast: Vec<impl Expression>,
|
ast: Vec<impl Expression>,
|
||||||
) -> Vec<Result<AnyValueEnum<'ctx>, String>> {
|
) -> Vec<Result<AnyValueEnum<'val>, String>> {
|
||||||
match compiler.current_ns() {
|
match compiler.current_ns() {
|
||||||
Some(ns) => ns,
|
Some(ns) => ns,
|
||||||
None => panic!("Current namespace is not set."),
|
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 {
|
for expr in &ast {
|
||||||
generated_code.push(expr.code_gen(compiler));
|
generated_code.push(expr.code_gen(compiler));
|
||||||
|
|
|
@ -39,8 +39,8 @@ fn main() -> io::Result<()> {
|
||||||
let context = compiler::create_context();
|
let context = compiler::create_context();
|
||||||
let mut compiler = compiler::Compiler::new(&context);
|
let mut compiler = compiler::Compiler::new(&context);
|
||||||
|
|
||||||
compiler.create_ns("user");
|
compiler.create_ns("user".to_string(), None);
|
||||||
compiler.set_current_ns("user");
|
compiler.set_current_ns("user".to_string());
|
||||||
|
|
||||||
if let Some(input) = args.value_of("INPUT") {
|
if let Some(input) = args.value_of("INPUT") {
|
||||||
let mut f = File::open(input)?;
|
let mut f = File::open(input)?;
|
||||||
|
@ -51,7 +51,7 @@ fn main() -> io::Result<()> {
|
||||||
Ok(v) => {
|
Ok(v) => {
|
||||||
println!("AST: {:#?}", v);
|
println!("AST: {:#?}", v);
|
||||||
|
|
||||||
let g = compiler::compile(&compiler, v);
|
let g = compiler::compile(&mut compiler, v);
|
||||||
println!("GEN: {:?}", g)
|
println!("GEN: {:?}", g)
|
||||||
}
|
}
|
||||||
Err(e) => println!(">> error {:?}", e),
|
Err(e) => println!(">> error {:?}", e),
|
||||||
|
|
|
@ -15,9 +15,12 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
|
use crate::types::ExprResult;
|
||||||
|
use crate::values::Value;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
use inkwell::module::Module;
|
use inkwell::module::Module;
|
||||||
use inkwell::values::FunctionValue;
|
use inkwell::types::{AnyTypeEnum, BasicType, FunctionType};
|
||||||
|
use inkwell::values::{AnyValueEnum, FunctionValue};
|
||||||
|
|
||||||
pub struct Namespace<'ctx> {
|
pub struct Namespace<'ctx> {
|
||||||
/// Each namespace in serene contains it's own LLVM module. You can
|
/// Each namespace in serene contains it's own LLVM module. You can
|
||||||
|
@ -36,9 +39,17 @@ pub struct Namespace<'ctx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> 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 {
|
Namespace {
|
||||||
module: context.create_module(&name),
|
module,
|
||||||
//scope: Scope::new(None),
|
//scope: Scope::new(None),
|
||||||
current_fn_opt: None,
|
current_fn_opt: None,
|
||||||
scope: Scope::new(None),
|
scope: Scope::new(None),
|
||||||
|
@ -56,4 +67,58 @@ impl<'ctx> Namespace<'ctx> {
|
||||||
pub fn current_fn(&self) -> FunctionValue<'ctx> {
|
pub fn current_fn(&self) -> FunctionValue<'ctx> {
|
||||||
self.current_fn_opt.unwrap()
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,10 +47,11 @@ impl List {
|
||||||
|
|
||||||
impl Expression for List {
|
impl Expression for List {
|
||||||
fn eval() {}
|
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() {
|
match self.first() {
|
||||||
Some(e) => match e {
|
Some(e) => match e {
|
||||||
Expr::Sym(s) if s.is_def() => def(compiler, self.rest()),
|
Expr::Sym(s) if s.is_def() => def(compiler, self.rest()),
|
||||||
|
|
||||||
_ => Err("Not implemented on list".to_string()),
|
_ => Err("Not implemented on list".to_string()),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -15,11 +15,13 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
use crate::compiler::Compiler;
|
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 {
|
pub trait Expression {
|
||||||
fn eval();
|
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>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ impl Eq for Number {}
|
||||||
|
|
||||||
impl Expression for Number {
|
impl Expression for Number {
|
||||||
fn eval() {}
|
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())
|
Err("Not implemented on numbers".to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
*/
|
*/
|
||||||
use crate::compiler::Compiler;
|
use crate::compiler::Compiler;
|
||||||
use crate::types::core::{ExprResult, Expression};
|
use crate::types::core::{ExprResult, Expression};
|
||||||
|
use inkwell::types::IntType;
|
||||||
use inkwell::values::AnyValueEnum;
|
use inkwell::values::AnyValueEnum;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -33,8 +34,8 @@ impl Eq for Symbol {}
|
||||||
|
|
||||||
impl Expression for Symbol {
|
impl Expression for Symbol {
|
||||||
fn eval() {}
|
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> {
|
||||||
let bool_t = compiler.context.bool_type();
|
let bool_t: IntType<'val> = compiler.context.bool_type();
|
||||||
if self.name == "true" {
|
if self.name == "true" {
|
||||||
Ok(AnyValueEnum::IntValue(bool_t.const_int(1, false)))
|
Ok(AnyValueEnum::IntValue(bool_t.const_int(1, false)))
|
||||||
} else if self.name == "false" {
|
} else if self.name == "false" {
|
||||||
|
|
|
@ -15,10 +15,21 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
use crate::ast::Expr;
|
use crate::ast::Expr;
|
||||||
use inkwell::values::AnyValueEnum;
|
use crate::types::ExprResult;
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
||||||
pub struct Value<'a> {
|
pub struct Value<'a> {
|
||||||
llvm_id: Option<&'a str>,
|
pub llvm_id: Option<String>,
|
||||||
lllvm_value: AnyValueEnum<'a>,
|
pub llvm_value: ExprResult<'a>,
|
||||||
expr: &'a Expr,
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue