diff --git a/bootstrap/src/ast.rs b/bootstrap/src/ast.rs index 4e23359..fd49f76 100644 --- a/bootstrap/src/ast.rs +++ b/bootstrap/src/ast.rs @@ -15,12 +15,14 @@ * along with this program. If not, see . */ use crate::errors::Error; -use crate::runtime::RT; +use crate::runtime; use crate::scope::Scope; use crate::types::collections; -use crate::types::{Number, Symbol}; +use crate::types::{BuiltinFunction, Number, Symbol}; use std::fmt; +pub type AST = Vec; + pub type PossibleExpr = Result; #[derive(Debug, Eq, PartialEq, Clone)] @@ -35,7 +37,7 @@ impl fmt::Display for Location { } } -pub trait Expression { +pub trait Node: fmt::Display { fn location(&self) -> Location { Location { position: 0, @@ -43,27 +45,26 @@ pub trait Expression { } } - fn eval(&self, rt: &RT, scope: &Scope) -> PossibleExpr; + fn get_type_str(&self) -> &str { + "Some type" + } } -/// It differs from the `fmt::Display` in the way that anything that -/// we want to show in a repl as the result of an evaluation and needs -/// the runtime details has to implement this trait. But we use the -/// `fmt::Display` as a formatter and in a way that it doesn't need the -/// runtime. -pub trait StringRepr { - fn string_repr(&self, rt: &RT) -> String; +pub trait Callable { + fn apply(&self, rt: &runtime::Runtime, scope: &Scope, args: collections::List) -> Expr; } #[derive(Debug, Eq, PartialEq, Clone)] pub enum Expr { Sym(Symbol), Str(String), + //Fn(Function), + BuiltinFn(BuiltinFunction), Num(Number), - Comment, Error(String), Cons(collections::List), Nil, + Comment, NoMatch, } @@ -91,25 +92,49 @@ impl Expr { pub fn make_number(n: Number) -> Expr { Expr::Num(n) } + + pub fn get_node(&self) -> Option<&dyn Node> { + match self { + Self::Num(x) => Some(x), + Self::Sym(x) => Some(x), + Self::Cons(x) => Some(x), + Self::BuiltinFn(x) => Some(x), + //Self::Str(x) => x, + // Self:://Fn(Function), + //Self::Error(String), + _ => None, + } + } } impl fmt::Display for Expr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Expr::Num(n) => n.fmt(f), - Expr::Sym(s) => s.fmt(f), - _ => write!(f, "NA"), + match self.get_node() { + Some(n) => n.fmt(f), + _ => match self { + Self::Comment => write!(f, "comment"), + Self::Error(_) => write!(f, "error"), + Self::Nil => write!(f, "nil"), + Self::NoMatch => write!(f, "noMatch"), + _ => write!(f, "Should Not happen"), + }, } } } -impl StringRepr for Expr { - fn string_repr(&self, rt: &RT) -> String { - match self { - Expr::Num(n) => n.string_repr(rt), - Expr::Sym(s) => s.string_repr(rt), - Expr::Cons(c) => c.string_repr(rt), - _ => "NA".to_string(), +impl Node for Expr { + fn get_type_str(&self) -> &str { + match self.get_node() { + Some(x) => x.get_type_str(), + None => match self { + Self::Comment => "comment", + Self::Error(_) => "error", + Self::Nil => "nil", + Self::NoMatch => "noMatch", + _ => { + panic!("This shouldn't happen. Checkout `get_node` and `get_type_str` on Expr") + } + }, } } } diff --git a/bootstrap/src/compiler.rs b/bootstrap/src/compiler.rs index 6a65d21..6518283 100644 --- a/bootstrap/src/compiler.rs +++ b/bootstrap/src/compiler.rs @@ -15,7 +15,7 @@ * along with this program. If not, see . */ use crate::namespace::Namespace; -use crate::types::Expression; +use crate::types::Node; use std::collections::HashMap; pub struct Compiler { diff --git a/bootstrap/src/core.rs b/bootstrap/src/core.rs index bdb9adf..765e8d8 100644 --- a/bootstrap/src/core.rs +++ b/bootstrap/src/core.rs @@ -14,25 +14,77 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -use crate::ast::{Expr, Expression, PossibleExpr, StringRepr}; +use crate::ast::{Callable, Expr, Node, PossibleExpr}; use crate::errors::err; +use crate::namespace; use crate::reader::read_string; -use crate::runtime::RT; +use crate::runtime; use crate::scope::Scope; +use crate::types::collections::Seq; -fn eval_expr(rt: &RT, scope: &Scope, expr: Expr) -> PossibleExpr { +pub fn string_repr(rt: &runtime::Runtime, expr: &Expr) -> String { match expr { - Expr::Num(n) => n.eval(rt, scope), - // TODO: find a better way to attach the ns name to the symbol. This - // is ugly. - Expr::Sym(s) => s - .clone_with_ns(rt.current_ns().name.clone()) - .eval(rt, scope), + Expr::Sym(s) => format!( + "#'{}/{}", + namespace::get_name(runtime::current_ns(rt)), + &s.name + ), + _ => format!("{}", expr), + } +} + +pub fn eval_expr(rt: &runtime::Runtime, scope: &Scope, expr: Expr) -> PossibleExpr { + match &expr { + // ** Number evaluation + Expr::Num(_) => Ok(expr), + + // ** Symbol evaluation + Expr::Sym(s) => { + if s.is_ns_qualified() { + return namespace::lookup_external( + runtime::current_ns(rt), + &s.target_ns.clone().unwrap(), + &s.name, + ); + } + + match scope.lookup(&s.name) { + Some(e) => Ok(e.expr.clone()), + _ => Err(err(format!( + "Undefined binding {} in ns '{}' at {}", + string_repr(rt, &expr), + namespace::get_name(runtime::current_ns(rt)), + s.location() + ))), + } + } + + // ** List evaluation + Expr::Cons(l) => { + if l.count() == 0 { + return Ok(Expr::Nil); + } + + let first = l.first().unwrap(); + let rest = l.rest(); + match eval_expr(rt, scope, first) { + Ok(e) => match e { + //Expr::Fn(f) => f.apply(rt, scope, rest), + Expr::BuiltinFn(b) => Ok(b.apply(rt, scope, rest)), + _ => Err(err(format!( + "Can't cast '{}' to functions at {}", + e.get_type_str(), + l.location(), + ))), + }, + Err(e) => Err(e), + } + } _ => Ok(expr), } } -pub fn eval(rt: &RT, exprs: Vec) -> PossibleExpr { +pub fn eval(rt: &runtime::Runtime, scope: &Scope, exprs: Vec) -> PossibleExpr { if exprs.len() == 0 { return Ok(Expr::NoMatch); } @@ -40,27 +92,31 @@ pub fn eval(rt: &RT, exprs: Vec) -> PossibleExpr { let mut ret: PossibleExpr = Ok(Expr::NoMatch); for expr in exprs.iter() { - ret = eval_expr(rt, rt.current_scope(), expr.clone()); + ret = eval_expr(rt, scope, expr.clone()); } ret } -pub fn read_eval_print(rt: &RT, input: &str) { +pub fn read_eval_print(rt: &runtime::Runtime, input: &str) { match read_string(input) { Ok(exprs) => { - if rt.is_debug() { + if runtime::is_debug(rt) { println!("Read Result: \n{:?}\n", exprs); } - let result_expr = eval(rt, exprs); + let result_expr = eval( + rt, + namespace::get_root_scope(&runtime::current_ns(rt)), + exprs, + ); - if rt.is_debug() { + if runtime::is_debug(rt) { println!("Eval Result: \n{:?}\n", result_expr); } match result_expr { - Ok(expr) => println!("{}", expr.string_repr(rt)), + Ok(expr) => println!("{}", string_repr(rt, &expr)), Err(e) => println!("{}", e), } } diff --git a/bootstrap/src/main.rs b/bootstrap/src/main.rs index 71fe767..535720a 100644 --- a/bootstrap/src/main.rs +++ b/bootstrap/src/main.rs @@ -13,7 +13,19 @@ * * You should have received a copy of the GNU General Public License * along with this program. If not, see . -*/ + */ +#![deny( + missing_docs, + missing_debug_implementations, + missing_copy_implementations, + trivial_casts, + trivial_numeric_casts, + unsafe_code, + unstable_features, + unused_import_braces, + unused_qualifications +)] + use clap::{load_yaml, App, ArgMatches}; use std::io; @@ -35,12 +47,12 @@ fn repl(args: ArgMatches) { debug = true; } - let mut rt = runtime::RT::new(); + let rt = runtime::create_runtime(); - rt.create_ns("user".to_string(), None); - rt.set_current_ns("user".to_string()); - rt.set_debug_mode(debug); - repl::repl(rt); + runtime::create_ns(&rt, "user".to_string(), None); + runtime::set_current_ns(&rt, "user".to_string()); + runtime::set_debug_mode(&rt, debug); + repl::repl(&rt); } fn main() -> io::Result<()> { diff --git a/bootstrap/src/namespace.rs b/bootstrap/src/namespace.rs index 66d4216..071158b 100644 --- a/bootstrap/src/namespace.rs +++ b/bootstrap/src/namespace.rs @@ -16,12 +16,14 @@ */ use crate::ast::{Expr, PossibleExpr}; use crate::scope::Scope; +use std::sync::{Arc, RwLock}; +#[derive(Debug, Clone)] pub struct Namespace { /// Root scope of the namespace pub name: String, pub source_file: Option, - root_scope: Scope, + pub root_scope: Scope, } impl Namespace { @@ -33,11 +35,53 @@ impl Namespace { } } - pub fn current_scope(&self) -> &Scope { - &self.root_scope - } - pub fn lookup_external(&self, target: &str, key: &str) -> PossibleExpr { Ok(Expr::Nil) } + + pub fn define_global(&mut self, name: &str, expr: Expr, public: bool) { + self.root_scope.insert(&name, expr, public); + } +} + +pub fn define_global(ns: &RwLock, name: &str, expr: Expr, public: bool) { + match ns.write() { + Ok(mut n) => n.define_global(name, expr, public), + Err(_) => panic!("Poisoned write lock while defining a global: '{:?}'", ns), + } +} + +pub fn lookup_external(ns: &RwLock, target: &str, key: &str) -> PossibleExpr { + match ns.read() { + Ok(n) => n.lookup_external(target, key), + Err(_) => panic!("Poisoned write lock while defining a global: '{:?}'", ns), + } +} + +pub fn get_name(ns: &RwLock) -> String { + match ns.read() { + Ok(n) => n.name.clone(), + Err(_) => panic!("Poisoned write lock while defining a global: '{:?}'", ns), + } +} + +pub fn get_root_scope(ns: &RwLock) -> &Scope { + match ns.read() { + Ok(n) => &n.root_scope, + Err(_) => panic!( + "Poisoned write lock while getting the root scope: '{:?}'", + ns + ), + } +} + +#[test] +fn test_ns_define_global() { + let mut ns = Namespace::new("ns1".to_string(), None); + assert_eq!(ns.root_scope.lookup("blah").is_none(), true); + + ns.define_global("something", Expr::Nil, true); + let result = ns.root_scope.lookup("something").unwrap(); + assert_eq!(result.expr, Expr::Nil); + assert_eq!(result.public, true); } diff --git a/bootstrap/src/repl.rs b/bootstrap/src/repl.rs index da7af7c..61650bb 100644 --- a/bootstrap/src/repl.rs +++ b/bootstrap/src/repl.rs @@ -15,20 +15,21 @@ * along with this program. If not, see . */ use crate::core::read_eval_print; -use crate::runtime::RT; +use crate::namespace; +use crate::runtime; use rustyline::error::ReadlineError; use rustyline::Editor; -pub fn repl(rt: RT) { +pub fn repl(rt: &runtime::Runtime) { let mut rl = Editor::<()>::new(); - let history = rt.history_file_path(); + let history = runtime::history_file_path(); - if rl.load_history(&history).is_err() && rt.is_debug() { + if rl.load_history(&history).is_err() && runtime::is_debug(&rt) { println!("No previous history."); } loop { - let prompt = format!("{}> ", rt.current_ns().name); + let prompt = format!("{}> ", namespace::get_name(runtime::current_ns(rt))); let readline = rl.readline(&prompt); match readline { Ok(line) => { diff --git a/bootstrap/src/runtime.rs b/bootstrap/src/runtime.rs index 0e58cf6..7ba6a7a 100644 --- a/bootstrap/src/runtime.rs +++ b/bootstrap/src/runtime.rs @@ -13,15 +13,18 @@ * * 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::namespace::Namespace; -use crate::scope::Scope; use std::collections::HashMap; use std::env; use std::path::Path; +use std::sync::{Arc, RwLock}; const SERENE_HISTORY_FILE: &'static str = ".serene.hitory"; +pub type Runtime = Arc>; + pub struct RT { /// This hashmap contains all the namespaces that has to be compiled and /// maps two different keys to the same namespace. Since namespace names @@ -32,68 +35,100 @@ pub struct RT { /// 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, - current_ns_name: Option, - debug: bool, + pub namespaces: HashMap>, + pub current_ns_name: Option, + pub debug: bool, } -impl RT { - pub fn new() -> RT { - RT { - namespaces: HashMap::new(), - current_ns_name: None, - debug: false, - } +pub fn create_runtime() -> Runtime { + Arc::new(RwLock::new(RT { + namespaces: HashMap::new(), + current_ns_name: None, + debug: false, + })) +} + +/// Create a new namespace with the given `ns_name` and add it to the current +/// runtime. +pub fn create_ns(rt: &Runtime, ns_name: String, source_file: Option) { + let mut r = match rt.write() { + Ok(r) => r, + + Err(_) => panic!("Poisoned runtime!"), + }; + + r.namespaces.insert( + ns_name.clone(), + RwLock::new(Namespace::new(ns_name, source_file)), + ); +} + +/// Set the current ns to the given `ns_name`. The `ns_name` has to be +/// part of the runtime already. +pub fn set_current_ns(rt: &Runtime, ns_name: String) { + let mut r = match rt.write() { + Ok(r) => r, + Err(_) => panic!("Poisoned runtime!"), + }; + + match r.namespaces.get(&ns_name) { + Some(_) => r.current_ns_name = Some(ns_name), + None => panic!("The given namespace '{}' doesn't exit", ns_name), } +} - /// Create a new namespace with the given `ns_name` and add it to the current - /// runtime. - pub fn create_ns(&mut self, ns_name: String, source_file: Option) { - self.namespaces - .insert(ns_name.clone(), Namespace::new(ns_name, source_file)); - } - - /// Set the current ns to the given `ns_name`. The `ns_name` has to be - /// part of the runtime already. - pub fn set_current_ns(&mut self, ns_name: String) { - match self.namespaces.get(&ns_name) { - Some(_) => self.current_ns_name = Some(ns_name), - None => panic!("The given namespace '{}' doesn't exit", ns_name), - } - } - - pub fn current_ns(&self) -> &Namespace { - if let None = self.current_ns_name { - // `current_ns_name` has to be not None all the time. - panic!("No namespace has been set to current."); - } - - self.namespaces - .get(&self.current_ns_name.clone().unwrap()) - .unwrap() - } - - pub fn current_scope(&self) -> &Scope { - self.current_ns().current_scope() - } - - #[inline] - pub fn set_debug_mode(&mut self, v: bool) { - self.debug = v; - } - - #[inline] - pub fn is_debug(&self) -> bool { - self.debug - } - - pub fn history_file_path(&self) -> String { - match env::var("HOME") { - Ok(v) => { - let history = Path::new(&v).join(SERENE_HISTORY_FILE).clone(); - history.to_str().unwrap().into() +pub fn current_ns(rt: &Runtime) -> &RwLock { + match rt.read() { + Ok(mut r) => { + let ns_name = r.current_ns_name.clone().unwrap(); + match r.namespaces.get(&ns_name) { + Some(x) => x, + _ => panic!("No namespace has been set to current."), } - Err(_) => SERENE_HISTORY_FILE.into(), } + Err(_) => panic!("Poisoned runtime!"), } } + +#[inline] +pub fn set_debug_mode(rt: &Runtime, v: bool) { + let mut r = match rt.write() { + Ok(r) => r, + Err(_) => panic!("Poisoned runtime!"), + }; + r.debug = v; +} + +#[inline] +pub fn is_debug(rt: &Runtime) -> bool { + match rt.read() { + Ok(r) => r.debug, + Err(_) => panic!("Poisoned runtime!"), + } +} + +// TODO: Move this function to somewhere else +pub fn history_file_path() -> String { + match env::var("HOME") { + Ok(v) => { + let history = Path::new(&v).join(SERENE_HISTORY_FILE).clone(); + history.to_str().unwrap().into() + } + Err(_) => SERENE_HISTORY_FILE.into(), + } +} + +#[test] +fn test_runtime_ns_mutation() { + let rt = create_runtime(); + create_ns(&rt, "user".to_string(), None); + set_current_ns(&rt, "user".to_string()); + let ns = current_ns(&rt).read().unwrap(); + assert_eq!(ns.root_scope.lookup("blah").is_none(), true); + + let ns = current_ns(&rt).write().unwrap(); + ns.define_global("something", Expr::Nil, true); + let result = ns.root_scope.lookup("something").unwrap(); + assert_eq!(result.expr, Expr::Nil); + assert_eq!(result.public, true); +} diff --git a/bootstrap/src/scope.rs b/bootstrap/src/scope.rs index e2d2733..edc3a89 100644 --- a/bootstrap/src/scope.rs +++ b/bootstrap/src/scope.rs @@ -17,7 +17,10 @@ use crate::ast::Expr; use std::collections::HashMap; +pub type Scope = Arc>; + /// This struct describes the values in the scope. +#[derive(Debug, Clone)] pub struct ScopeElement { pub expr: Expr, pub public: bool, @@ -26,19 +29,20 @@ pub struct ScopeElement { /// 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 { - parent: Option>, +#[derive(Debug, Clone)] +pub struct UnSafeScope { + parent: Option, symbol_table: HashMap, } -impl Scope { +impl UnSafeScope { pub fn new(_parent: Option) -> Scope { let p = match _parent { Some(x) => Some(Box::new(x)), None => None, }; - Scope { + UnSafeScope { parent: p, symbol_table: HashMap::new(), } @@ -62,3 +66,11 @@ impl Scope { self.symbol_table.insert(key.to_string(), v); } } + +#[test] +fn test_scope() { + let mut scope = Scope::new(None); + scope.insert("sym1", Expr::Nil, true); + let sym = scope.lookup("sym1").unwrap(); + assert_eq!(sym.expr, Expr::Nil); +} diff --git a/bootstrap/src/types.rs b/bootstrap/src/types.rs index eddf705..6ce43bc 100644 --- a/bootstrap/src/types.rs +++ b/bootstrap/src/types.rs @@ -14,10 +14,12 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ +pub mod builtin_function; pub mod collections; pub mod number; pub mod symbol; +pub use self::builtin_function::BuiltinFunction; pub use self::collections::{List, Seq}; pub use self::number::Number; pub use self::symbol::Symbol; diff --git a/bootstrap/src/types/builtin_function.rs b/bootstrap/src/types/builtin_function.rs new file mode 100644 index 0000000..31752a9 --- /dev/null +++ b/bootstrap/src/types/builtin_function.rs @@ -0,0 +1,67 @@ +/* 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::{Callable, Expr, Node}; +use crate::runtime; +use crate::scope::Scope; +use crate::types::collections::List; + +use std::fmt; + +pub type BuiltinHandler = fn(rt: &runtime::Runtime, scope: &Scope, args: List) -> Expr; + +#[derive(Clone)] +pub struct BuiltinFunction { + pub name: String, + ns: String, + handler_function: BuiltinHandler, +} + +impl PartialEq for BuiltinFunction { + fn eq(&self, other: &Self) -> bool { + (self.name == other.name) && (self.ns == other.ns) + } +} + +impl Eq for BuiltinFunction {} + +impl Node for BuiltinFunction { + fn get_type_str(&self) -> &str { + "Function" + } +} + +impl Callable for BuiltinFunction { + fn apply(&self, rt: &runtime::Runtime, scope: &Scope, args: List) -> Expr { + let f = self.handler_function; + f(rt, scope, args) + } +} + +impl fmt::Display for BuiltinFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}/{}", &self.ns, &self.name) + } +} + +impl fmt::Debug for BuiltinFunction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("BuiltinFunction") + .field("name", &self.name) + .field("ns", &self.ns) + .finish() + } +} diff --git a/bootstrap/src/types/collections/list.rs b/bootstrap/src/types/collections/list.rs index f9108a5..3075233 100644 --- a/bootstrap/src/types/collections/list.rs +++ b/bootstrap/src/types/collections/list.rs @@ -16,12 +16,8 @@ */ //use crate::builtins::def; -use crate::ast::{Expr, Expression, PossibleExpr, StringRepr}; -use crate::errors::err; -use crate::runtime::RT; -use crate::scope::Scope; +use crate::ast::{Expr, Node}; use crate::types::collections::core::Seq; -use crate::types::Symbol; use std::fmt; #[derive(Debug, Eq, PartialEq, Clone)] @@ -68,20 +64,9 @@ impl Seq for List { } } -impl Expression for List { - fn eval(&self, rt: &RT, scope: &Scope) -> PossibleExpr { - if self.count() == 0 { - return Ok(Expr::Nil); - } - - let first = self.first().unwrap(); - let rest = self.rest(); - - Ok(Expr::Cons(self.clone())) - // match first { - // Expr::Sym(sum) => {} - // _ => Err(err("NotImplemented".to_string())), - // } +impl Node for List { + fn get_type_str(&self) -> &str { + "List" } } @@ -97,9 +82,3 @@ impl fmt::Display for List { write!(f, "({})", &elems.join(" ")) } } - -impl StringRepr for List { - fn string_repr(&self, rt: &RT) -> String { - format!("{}", self) - } -} diff --git a/bootstrap/src/types/function.rs b/bootstrap/src/types/function.rs new file mode 100644 index 0000000..ad774f2 --- /dev/null +++ b/bootstrap/src/types/function.rs @@ -0,0 +1,37 @@ +/* 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::Node; +use std::fmt; + +#[derive(Debug, Clone)] +pub struct Function { + pub name: Option, +} + +//impl Eq for Function {} + +impl Node for Function { + fn get_type_str(&self) -> &str { + "Function" + } +} + +// impl fmt::Display for Function { +// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +// write!(f, "{}", &self.name) +// } +// } diff --git a/bootstrap/src/types/number.rs b/bootstrap/src/types/number.rs index 34e15bb..58b43a1 100644 --- a/bootstrap/src/types/number.rs +++ b/bootstrap/src/types/number.rs @@ -14,9 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -use crate::ast::{Expr, Expression, PossibleExpr, StringRepr}; -use crate::runtime::RT; -use crate::scope::Scope; +use crate::ast::Node; use std::fmt; // Note: I kept the number implementation simple for now @@ -47,9 +45,9 @@ impl PartialEq for Number { impl Eq for Number {} -impl Expression for Number { - fn eval(&self, _rt: &RT, _scope: &Scope) -> PossibleExpr { - Ok(Expr::Num(self.clone())) +impl Node for Number { + fn get_type_str(&self) -> &str { + "Number" } } @@ -61,9 +59,3 @@ impl fmt::Display for Number { } } } - -impl StringRepr for Number { - fn string_repr(&self, rt: &RT) -> String { - format!("{}", self) - } -} diff --git a/bootstrap/src/types/symbol.rs b/bootstrap/src/types/symbol.rs index 1c25ea5..2a1fb9b 100644 --- a/bootstrap/src/types/symbol.rs +++ b/bootstrap/src/types/symbol.rs @@ -14,10 +14,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -use crate::ast::{Expr, Expression, Location, PossibleExpr, StringRepr}; -use crate::errors::err; -use crate::runtime::RT; -use crate::scope::Scope; +use crate::ast::Node; use std::fmt; #[derive(Debug, Clone)] @@ -26,24 +23,12 @@ pub struct Symbol { /// This field holds the ns specifier part of the symbol. For example /// in case of `somens/somesym`, this field will hold `somens`. - target_ns: Option, - /// Name of the namespace which this symbol is in. It doesn't mean - /// the namespace which this symbol is defined. For example Let's - /// say we're in ns A, and there is a sumbol `B/x`. This symbol - /// refers to the symbol `x` in ns B and it's not the same as - /// the symbol `x` in ns B. They are two different symbols pointing - /// to the same value. the `ns` value of the one in ns A would be `A` - /// and the one in B would be `B`. - ns: Option, + pub target_ns: Option, } impl Symbol { pub fn new(name: String, target_ns: Option) -> Symbol { - Symbol { - name, - target_ns, - ns: None, - } + Symbol { name, target_ns } } pub fn is_ns_qualified(&self) -> bool { @@ -53,18 +38,6 @@ impl Symbol { pub fn is_def(&self) -> bool { self.name == "def" } - - /// Only clones the symbol if ns isn't set yet. - pub fn clone_with_ns(self, ns_name: String) -> Symbol { - if let Some(_) = self.ns { - return self; - } - - Symbol { - ns: Some(ns_name), - ..self.clone() - } - } } impl PartialEq for Symbol { @@ -75,23 +48,9 @@ impl PartialEq for Symbol { impl Eq for Symbol {} -impl Expression for Symbol { - fn eval(&self, rt: &RT, scope: &Scope) -> PossibleExpr { - if self.is_ns_qualified() { - return rt - .current_ns() - .lookup_external(&self.target_ns.clone().unwrap(), &self.name); - } - - match scope.lookup(&self.name) { - Some(e) => Ok(e.expr.clone()), - _ => Err(err(format!( - "Undefined binding {} in ns '{}' at {}", - self, - self.ns.clone().unwrap(), - self.location() - ))), - } +impl Node for Symbol { + fn get_type_str(&self) -> &str { + "Symbol" } } @@ -100,9 +59,3 @@ impl fmt::Display for Symbol { write!(f, "{}", &self.name) } } - -impl StringRepr for Symbol { - fn string_repr(&self, rt: &RT) -> String { - format!("#'{}/{}", &rt.current_ns().name, &self.name) - } -}