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)
- }
-}