From ee47410d49a1b3a992cbb666bd8646b77f17c4d5 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Sun, 13 Sep 2020 19:29:17 +0100 Subject: [PATCH] Improve scope to support builtins --- Cargo.lock | 25 +++++++++++++++++++++++ Cargo.toml | 6 ++++++ src/ast.rs | 2 +- src/builtins.rs | 29 +++++++++++++++++++++++++++ src/builtins/def.rs | 24 ++++++++++++++++++++++ src/compiler.rs | 6 ++++-- src/main.rs | 2 ++ src/namespace.rs | 5 +++-- src/scope.rs | 49 ++++++++++++++++++++++++++++++++++++++------- src/values.rs | 24 ++++++++++++++++++++++ 10 files changed, 160 insertions(+), 12 deletions(-) create mode 100644 src/builtins.rs create mode 100644 src/builtins/def.rs create mode 100644 src/values.rs diff --git a/Cargo.lock b/Cargo.lock index 8455bfd..f58e2cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -265,6 +265,24 @@ dependencies = [ "winapi", ] +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_shared", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher", +] + [[package]] name = "proc-macro-error" version = "0.4.12" @@ -378,9 +396,16 @@ version = "0.1.0" dependencies = [ "clap", "inkwell", + "phf", "rusty-hook", ] +[[package]] +name = "siphasher" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" + [[package]] name = "smallvec" version = "1.4.0" diff --git a/Cargo.toml b/Cargo.toml index 870b7fc..b976287 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,14 @@ license-file = "LICENSE" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +# CLI library clap = { version = "3.0.0-beta.1", features = ["yaml"] } + +# LLVM Binding inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "llvm10-0" } +# Static compile time hashing generator +phf = { version = "0.8", default-features = false } + [dev-dependencies] rusty-hook = "^0.11.2" \ No newline at end of file diff --git a/src/ast.rs b/src/ast.rs index a3cfc2f..06733d0 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -29,7 +29,7 @@ pub enum Expr { NoMatch, } -impl<'a> Expr { +impl Expr { pub fn make_list(first: Expr, rest: Expr) -> Expr { Expr::Cons(List::::new(Box::new(first), Box::new(rest))) } diff --git a/src/builtins.rs b/src/builtins.rs new file mode 100644 index 0000000..70786a9 --- /dev/null +++ b/src/builtins.rs @@ -0,0 +1,29 @@ +/** Serene --- Yet an other Lisp +* +* Copyright (c) 2020 Sameer Rahmani +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . + */ +pub mod def; + +pub use self::def::def; +use crate::ast::Expr; +use crate::compiler::Compiler; +use crate::types::list::List; + +use phf::phf_map; + +pub type BuiltInFn = Fn(&Compiler, &List) -> ExprResult; +pub static BUILTINS: phf::Map<&'static str, BuiltInFn> = phf_map! { + "def" => &def +}; diff --git a/src/builtins/def.rs b/src/builtins/def.rs new file mode 100644 index 0000000..67fcbd8 --- /dev/null +++ b/src/builtins/def.rs @@ -0,0 +1,24 @@ +/** Serene --- Yet an other Lisp +* +* Copyright (c) 2020 Sameer Rahmani +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . + */ +use crate::ast::Expr; +use crate::compiler::Compiler; +use crate::types::{ExprResult, List}; + +pub fn def<'ctx>(compiler: &'ctx Compiler, args: &'ctx List) -> ExprResult<'ctx> { + //compiler.current_ns().ins + Ok(()) +} diff --git a/src/compiler.rs b/src/compiler.rs index 01b13aa..196e69c 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -104,9 +104,11 @@ pub fn create_context() -> Context { return Context::create(); } +/// Compiles the given `ast` using the given `compiler` into +/// LLVM IR. pub fn compile<'ctx>( compiler: &'ctx Compiler, - exprs: Vec, + ast: Vec, ) -> Vec, String>> { match compiler.current_ns() { Some(ns) => ns, @@ -115,7 +117,7 @@ pub fn compile<'ctx>( let mut generated_code = vec![]; - for expr in &exprs { + for expr in &ast { generated_code.push(expr.code_gen(compiler)); } diff --git a/src/main.rs b/src/main.rs index 67c7513..222331f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,11 +23,13 @@ use std::io::prelude::*; use std::string::String; pub mod ast; +pub mod builtins; pub mod compiler; pub mod namespace; pub mod reader; pub mod scope; pub mod types; +pub mod values; fn main() -> io::Result<()> { let yaml = load_yaml!("cli.yml"); diff --git a/src/namespace.rs b/src/namespace.rs index d149d04..42ab358 100644 --- a/src/namespace.rs +++ b/src/namespace.rs @@ -14,7 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -//use crate::scope::Scope; +use crate::scope::Scope; use inkwell::context::Context; use inkwell::module::Module; use inkwell::values::FunctionValue; @@ -24,7 +24,7 @@ pub struct Namespace<'ctx> { /// think of modules as compilation units. Object files if you prefer. /// This way we should be able to hot swap the namespaces. pub module: Module<'ctx>, - //scope: Scope<'ctx>, + scope: Scope<'ctx>, // The option of the current function being compiled current_fn_opt: Option>, @@ -36,6 +36,7 @@ impl<'ctx> Namespace<'ctx> { module: context.create_module(&name), //scope: Scope::new(None), current_fn_opt: None, + scope: Scope::new(None), } } /// Get a defined function given its name. diff --git a/src/scope.rs b/src/scope.rs index b71a00a..818d858 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -13,16 +13,46 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ -use inkwell::values::PointerValue; + */ +use crate::builtins::{BuiltInFn, BUILTINS}; +use crate::values; + use std::collections::HashMap; +/// This enum describes the type of the values in the scope. +/// Most values are LLVMValue's which are just some LLVM IR +/// representation. +/// But sometimes we're going to have lookups for build in symbols +/// like `def`, `if`, `fn` and so on. +pub enum ScopeElementType<'a> { + Value(values::Value<'a>), + BuiltinCall(BuiltInFn), +} + +/// This struct describes the values in the scope. +struct ScopeElement<'a> { + element_type: ScopeElementType<'a>, + public: bool, +} + +/// Lookup the given key `k` in the builtins and return a +/// ScopeElement from it +fn builtin_lookup<'a>(k: &'a str) -> Option> { + match BUILTINS.get(k) { + Some(v) => Some(ScopeElement { + element_type: ScopeElementType::BuiltinCall(v), + public: true, + }), + None => None, + } +} + /// Scopes in **Serene** are simply represented by hashmaps. Each /// Scope optionally has a parent scope that lookups fallback to /// if the lookup key is missing from the current scope. pub struct Scope<'a> { parent: Option>>, - symbol_table: HashMap>, + symbol_table: HashMap>, } impl<'a> Scope<'a> { @@ -40,19 +70,24 @@ impl<'a> Scope<'a> { /// Lookup the given `key` in the scope and if it is not in the current /// scope look it up in the `parent` scope. - pub fn lookup(&self, key: &str) -> Option { + pub fn lookup(&self, key: &'a str) -> Option> { let v = self.symbol_table.get(key); if let None = v { return match &self.parent { Some(x) => x.lookup(key), - None => None, + None => builtin_lookup(key), }; } + v.map(|x| *x) } - pub fn insert(&mut self, key: &str, val: PointerValue<'a>) { - self.symbol_table.insert(key.to_string(), val); + pub fn insert(&mut self, key: &str, val: Value<'a>, public: bool) { + let v = ScopeElement { + public, + element_type: ScopeElementType::Value(val), + }; + self.symbol_table.insert(key.to_string(), v); } } diff --git a/src/values.rs b/src/values.rs new file mode 100644 index 0000000..4b5c32e --- /dev/null +++ b/src/values.rs @@ -0,0 +1,24 @@ +/** Serene --- Yet an other Lisp +* +* Copyright (c) 2020 Sameer Rahmani +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 2 of the License. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see . + */ +use crate::ast::Expr; +use inkwell::values::AnyValueEnum; + +pub struct Value<'a> { + llvm_id: Option<&'a str>, + lllvm_value: AnyValueEnum<'a>, + expr: &'a Expr, +}