|
@@ -24,42 +24,47 @@ pub enum Value {
|
|
|
Nil,
|
|
|
}
|
|
|
|
|
|
-impl fmt::Display for Value {
|
|
|
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
- self.with_str(|s| write!(f, "{}", s))
|
|
|
+impl Value {
|
|
|
+ fn to_string(&self, ast: &ASTArena) -> String {
|
|
|
+ self.with_str(ast, |s| s.to_string())
|
|
|
}
|
|
|
}
|
|
|
+// impl fmt::Display for Value {
|
|
|
+// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
|
+// self.with_str(|s| write!(f, "{}", s))
|
|
|
+// }
|
|
|
+// }
|
|
|
|
|
|
impl Value {
|
|
|
/// Convert this value to a Rust integer, failing otherwise
|
|
|
- fn as_num(&self) -> Result<i64, Error> {
|
|
|
+ fn as_num(&self, ast: &ASTArena) -> Result<i64, Error> {
|
|
|
match self {
|
|
|
Value::Lit(Literal::Num(n)) => Ok(*n),
|
|
|
- _ => self.with_str(|s| bail!("Expected number, got {}", s)),
|
|
|
+ _ => self.with_str(ast, |s| bail!("Expected number, got {}", s)),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// Convert this value to a Rust string, failing otherwise
|
|
|
- fn as_str(&self) -> Result<&str, Error> {
|
|
|
+ fn as_str(&self, ast: &ASTArena) -> Result<&str, Error> {
|
|
|
match self {
|
|
|
Value::Lit(Literal::Str(s)) => Ok(s),
|
|
|
- _ => self.with_str(|s| bail!("Expected string, got {}", s)),
|
|
|
+ _ => self.with_str(ast, |s| bail!("Expected string, got {}", s)),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// Convert this value to a Rust slice, failing otherwise
|
|
|
- fn as_tup(&self) -> Result<&[Thunk], Error> {
|
|
|
+ fn as_tup(&self, ast: &ASTArena) -> Result<&[Thunk], Error> {
|
|
|
match self {
|
|
|
Value::Tup(vals) => Ok(vals),
|
|
|
- _ => self.with_str(|s| bail!("Expected tuple, got {}", s)),
|
|
|
+ _ => self.with_str(ast, |s| bail!("Expected tuple, got {}", s)),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// Convert this value to a closure, failing otherwise
|
|
|
- fn as_closure(&self) -> Result<&Closure, Error> {
|
|
|
+ fn as_closure(&self, ast: &ASTArena) -> Result<&Closure, Error> {
|
|
|
match self {
|
|
|
Value::Closure(closure) => Ok(closure),
|
|
|
- _ => self.with_str(|s| bail!("Expected tuple, got {}", s)),
|
|
|
+ _ => self.with_str(ast, |s| bail!("Expected tuple, got {}", s)),
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -68,11 +73,11 @@ impl Value {
|
|
|
/// not completely forced already: indeed, this can't, since it
|
|
|
/// doesn't have access to the `State`. Unevaluated fragments of
|
|
|
/// the value will be printed as `#<unevaluated>`.
|
|
|
- fn with_str<U>(&self, f: impl FnOnce(&str) -> U) -> U {
|
|
|
+ fn with_str<U>(&self, ast: &ASTArena, f: impl FnOnce(&str) -> U) -> U {
|
|
|
match self {
|
|
|
Value::Nil => f(""),
|
|
|
Value::Lit(Literal::Str(s)) => f(s),
|
|
|
- Value::Lit(Literal::Atom(s)) => f(&format!("{:?}", s)),
|
|
|
+ Value::Lit(Literal::Atom(s)) => f(&format!("{}", &ast[s.item])),
|
|
|
Value::Lit(Literal::Num(n)) => f(&format!("{}", n)),
|
|
|
Value::Tup(values) => {
|
|
|
let mut buf = String::new();
|
|
@@ -82,7 +87,7 @@ impl Value {
|
|
|
buf.push_str(", ");
|
|
|
}
|
|
|
match val {
|
|
|
- Thunk::Value(v) => buf.push_str(&v.to_string()),
|
|
|
+ Thunk::Value(v) => buf.push_str(&v.to_string(ast)),
|
|
|
Thunk::Expr(..) => buf.push_str("#<unevaluated>"),
|
|
|
Thunk::Builtin(func) => buf.push_str(&format!("#<builtin {}>", func.name)),
|
|
|
}
|
|
@@ -138,9 +143,9 @@ const BUILTINS: &[BuiltinFunc] = &[
|
|
|
(args[0], args[1])
|
|
|
};
|
|
|
let mut buf = String::new();
|
|
|
- let num = state.eval(rep, env)?.as_num()?;
|
|
|
+ let num = state.eval(rep, env)?.as_num(&state.ast.borrow())?;
|
|
|
for _ in 0..num {
|
|
|
- buf.push_str(&state.eval(expr, env)?.as_str()?.to_string());
|
|
|
+ buf.push_str(&state.eval(expr, env)?.as_str(&state.ast.borrow())?.to_string());
|
|
|
}
|
|
|
Ok(Value::Lit(Literal::Str(buf)))
|
|
|
},
|
|
@@ -159,14 +164,14 @@ const BUILTINS: &[BuiltinFunc] = &[
|
|
|
name: "to-upper",
|
|
|
callback: &|state: &State, expr: ExprRef, env: &Env| -> Result<Value, Error> {
|
|
|
let s = state.eval(expr, env)?;
|
|
|
- Ok(Value::Lit(Literal::Str(s.as_str()?.to_uppercase())))
|
|
|
+ Ok(Value::Lit(Literal::Str(s.as_str(&state.ast.borrow())?.to_uppercase())))
|
|
|
},
|
|
|
},
|
|
|
BuiltinFunc {
|
|
|
name: "capitalize",
|
|
|
callback: &|state: &State, expr: ExprRef, env: &Env| -> Result<Value, Error> {
|
|
|
let s = state.eval(expr, env)?;
|
|
|
- Ok(Value::Lit(Literal::Str(titlecase::titlecase(s.as_str()?))))
|
|
|
+ Ok(Value::Lit(Literal::Str(titlecase::titlecase(s.as_str(&state.ast.borrow())?))))
|
|
|
|
|
|
},
|
|
|
},
|
|
@@ -174,17 +179,17 @@ const BUILTINS: &[BuiltinFunc] = &[
|
|
|
name: "to-lower",
|
|
|
callback: &|state: &State, expr: ExprRef, env: &Env| -> Result<Value, Error> {
|
|
|
let s = state.eval(expr, env)?;
|
|
|
- Ok(Value::Lit(Literal::Str(s.as_str()?.to_lowercase())))
|
|
|
+ Ok(Value::Lit(Literal::Str(s.as_str(&state.ast.borrow())?.to_lowercase())))
|
|
|
},
|
|
|
},
|
|
|
BuiltinFunc {
|
|
|
name: "concat",
|
|
|
callback: &|state: &State, expr: ExprRef, env: &Env| -> Result<Value, Error> {
|
|
|
let val = state.eval(expr, env)?;
|
|
|
- let tup = val.as_tup()?;
|
|
|
+ let tup = val.as_tup(&state.ast.borrow())?;
|
|
|
let mut contents = Vec::new();
|
|
|
for elem in tup {
|
|
|
- for th in state.hnf(elem)?.as_tup()? {
|
|
|
+ for th in state.hnf(elem)?.as_tup(&state.ast.borrow())? {
|
|
|
contents.push(th.clone());
|
|
|
}
|
|
|
}
|
|
@@ -195,15 +200,15 @@ const BUILTINS: &[BuiltinFunc] = &[
|
|
|
name: "tuple-fold",
|
|
|
callback: &|state: &State, expr: ExprRef, env: &Env| -> Result<Value, Error> {
|
|
|
let val = state.eval(expr, env)?;
|
|
|
- let args = val.as_tup()?;
|
|
|
+ let args = val.as_tup(&state.ast.borrow())?;
|
|
|
if let [func, init, tup] = args {
|
|
|
let func = state.hnf(func)?;
|
|
|
let tup = state.hnf(tup)?;
|
|
|
|
|
|
let mut result = init.clone();
|
|
|
- for t in tup.as_tup()? {
|
|
|
- let partial = state.eval_closure(func.as_closure()?, result)?;
|
|
|
- result = Thunk::Value(state.eval_closure(partial.as_closure()?, t.clone())?);
|
|
|
+ for t in tup.as_tup(&state.ast.borrow())? {
|
|
|
+ let partial = state.eval_closure(func.as_closure(&state.ast.borrow())?, result)?;
|
|
|
+ result = Thunk::Value(state.eval_closure(partial.as_closure(&state.ast.borrow())?, t.clone())?);
|
|
|
}
|
|
|
|
|
|
state.hnf(&result)
|
|
@@ -405,7 +410,7 @@ impl State {
|
|
|
if let Ok(expr) = expr {
|
|
|
let val = self.eval(expr, &None)?;
|
|
|
let val = self.force(val)?;
|
|
|
- writeln!(io::stdout(), "{}", val.to_string())?;
|
|
|
+ writeln!(io::stdout(), "{}", val.to_string(&self.ast.borrow()))?;
|
|
|
} else {
|
|
|
bail!("{:?}", err);
|
|
|
}
|
|
@@ -442,7 +447,7 @@ impl State {
|
|
|
Stmt::Puts(expr) => {
|
|
|
let val = self.eval(*expr, &None)?;
|
|
|
let val = self.force(val)?;
|
|
|
- writeln!(output, "{}", val.to_string()).unwrap();
|
|
|
+ writeln!(output, "{}", val.to_string(&self.ast.borrow())).unwrap();
|
|
|
}
|
|
|
|
|
|
// Look up the provided name, and if it's not already
|
|
@@ -577,7 +582,7 @@ impl State {
|
|
|
for expr in cat {
|
|
|
let val = self.eval(*expr, env)?;
|
|
|
let val = self.force(val)?;
|
|
|
- buf.push_str(&val.to_string());
|
|
|
+ buf.push_str(&val.to_string(&self.ast.borrow()));
|
|
|
}
|
|
|
Ok(Value::Lit(Literal::Str(buf)))
|
|
|
}
|
|
@@ -607,8 +612,8 @@ impl State {
|
|
|
// for a range, choose randomly between the start and end
|
|
|
// expressions
|
|
|
Expr::Range(from, to) => {
|
|
|
- let from = self.eval(*from, env)?.as_num()?;
|
|
|
- let to = self.eval(*to, env)?.as_num()?;
|
|
|
+ let from = self.eval(*from, env)?.as_num(&self.ast.borrow())?;
|
|
|
+ let to = self.eval(*to, env)?.as_num(&self.ast.borrow())?;
|
|
|
Ok(Value::Lit(Literal::Num(
|
|
|
self.rand.borrow_mut().gen_range_i64(from, to+1),
|
|
|
)))
|