Moving the eval function to the core module

This commit is contained in:
Sameer Rahmani 2020-11-10 20:14:30 +00:00
parent 5c6518f7d6
commit cff76ac5a5
14 changed files with 424 additions and 209 deletions

View File

@ -15,12 +15,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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<Expr>;
pub type PossibleExpr = Result<Expr, Error>;
#[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")
}
},
}
}
}

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
use crate::namespace::Namespace;
use crate::types::Expression;
use crate::types::Node;
use std::collections::HashMap;
pub struct Compiler {

View File

@ -14,25 +14,77 @@
* 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, 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<Expr>) -> PossibleExpr {
pub fn eval(rt: &runtime::Runtime, scope: &Scope, exprs: Vec<Expr>) -> PossibleExpr {
if exprs.len() == 0 {
return Ok(Expr::NoMatch);
}
@ -40,27 +92,31 @@ pub fn eval(rt: &RT, exprs: Vec<Expr>) -> 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),
}
}

View File

@ -13,7 +13,19 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
*/
#![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<()> {

View File

@ -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<String>,
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<Namespace>, 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<Namespace>, 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<Namespace>) -> 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<Namespace>) -> &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);
}

View File

@ -15,20 +15,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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) => {

View File

@ -13,15 +13,18 @@
*
* 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::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<RwLock<RT>>;
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<String, Namespace>,
current_ns_name: Option<String>,
debug: bool,
pub namespaces: HashMap<String, RwLock<Namespace>>,
pub current_ns_name: Option<String>,
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<String>) {
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<String>) {
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<Namespace> {
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);
}

View File

@ -17,7 +17,10 @@
use crate::ast::Expr;
use std::collections::HashMap;
pub type Scope = Arc<RwLock<UnSafeScope>>;
/// 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<Box<Scope>>,
#[derive(Debug, Clone)]
pub struct UnSafeScope {
parent: Option<Scope>,
symbol_table: HashMap<String, ScopeElement>,
}
impl Scope {
impl UnSafeScope {
pub fn new(_parent: Option<Scope>) -> 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);
}

View File

@ -14,10 +14,12 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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;

View File

@ -0,0 +1,67 @@
/* Serene --- Yet an other Lisp
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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()
}
}

View File

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

View File

@ -0,0 +1,37 @@
/* Serene --- Yet an other Lisp
*
* Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
use crate::ast::Node;
use std::fmt;
#[derive(Debug, Clone)]
pub struct Function {
pub name: Option<String>,
}
//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)
// }
// }

View File

@ -14,9 +14,7 @@
* 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, 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)
}
}

View File

@ -14,10 +14,7 @@
* 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, 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<String>,
/// 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<String>,
pub target_ns: Option<String>,
}
impl Symbol {
pub fn new(name: String, target_ns: Option<String>) -> 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)
}
}