|
@@ -1,5 +1,6 @@
|
|
|
use crate::ast::*;
|
|
|
use rand::Rng;
|
|
|
+use std::cell::RefCell;
|
|
|
use std::collections::HashMap;
|
|
|
use std::fmt;
|
|
|
|
|
@@ -62,7 +63,7 @@ impl fmt::Display for Value {
|
|
|
|
|
|
pub struct BuiltinFunc {
|
|
|
name: &'static str,
|
|
|
- callback: &'static dyn Fn(&mut State, &Expr) -> Result<Value, Error>,
|
|
|
+ callback: &'static dyn Fn(&State, ExprRef) -> Result<Value, Error>,
|
|
|
}
|
|
|
|
|
|
#[derive(Debug)]
|
|
@@ -93,23 +94,31 @@ impl std::error::Error for Error {}
|
|
|
const BUILTINS: &[BuiltinFunc] = &[
|
|
|
BuiltinFunc {
|
|
|
name: "rep",
|
|
|
- callback: &|state: &mut State, expr: &Expr| -> Result<Value, Error> {
|
|
|
- let args = match expr {
|
|
|
- Expr::Tup(tup) => tup,
|
|
|
- _ => bail!("`rep`: expected tuple"),
|
|
|
+ callback: &|state: &State, expr: ExprRef| -> Result<Value, Error> {
|
|
|
+ let (rep, expr) = {
|
|
|
+ let ast = state.ast.borrow();
|
|
|
+ let args = match &ast[expr] {
|
|
|
+ Expr::Tup(tup) => tup,
|
|
|
+ _ => bail!("`rep`: expected tuple"),
|
|
|
+ };
|
|
|
+ if args.len() != 2 {
|
|
|
+ bail!("`rep`: expected two arguments, got {}", args.len())
|
|
|
+ }
|
|
|
+ (args[0], args[1])
|
|
|
};
|
|
|
- if args.len() != 2 {
|
|
|
- bail!("`rep`: expected two arguments, got {}", args.len())
|
|
|
+ let mut buf = String::new();
|
|
|
+ let num = state.eval(rep)?.as_num()?;
|
|
|
+ for _ in 0..num {
|
|
|
+ buf.push_str(&state.eval(expr)?.as_str()?.to_string());
|
|
|
}
|
|
|
- let num = state.eval(&args[0])?.as_num()?;
|
|
|
- let rep = (0..num).map(|_| args[1].clone()).collect();
|
|
|
- state.eval(&Expr::Cat(rep))
|
|
|
+ Ok(Value::Lit(Literal::Str(buf)))
|
|
|
},
|
|
|
},
|
|
|
BuiltinFunc {
|
|
|
name: "length",
|
|
|
- callback: &|_state: &mut State, expr: &Expr| -> Result<Value, Error> {
|
|
|
- let args = match expr {
|
|
|
+ callback: &|state: &State, expr: ExprRef| -> Result<Value, Error> {
|
|
|
+ let ast = state.ast.borrow();
|
|
|
+ let args = match &ast[expr] {
|
|
|
Expr::Tup(tup) => tup,
|
|
|
_ => bail!("`length`: expected tuple"),
|
|
|
};
|
|
@@ -118,14 +127,14 @@ const BUILTINS: &[BuiltinFunc] = &[
|
|
|
},
|
|
|
BuiltinFunc {
|
|
|
name: "to-upper",
|
|
|
- callback: &|state: &mut State, expr: &Expr| -> Result<Value, Error> {
|
|
|
+ callback: &|state: &State, expr: ExprRef| -> Result<Value, Error> {
|
|
|
let s = state.eval(expr)?;
|
|
|
Ok(Value::Lit(Literal::Str(s.as_str()?.to_uppercase())))
|
|
|
},
|
|
|
},
|
|
|
BuiltinFunc {
|
|
|
name: "to-lower",
|
|
|
- callback: &|state: &mut State, expr: &Expr| -> Result<Value, Error> {
|
|
|
+ callback: &|state: &State, expr: ExprRef| -> Result<Value, Error> {
|
|
|
let s = state.eval(expr)?;
|
|
|
Ok(Value::Lit(Literal::Str(s.as_str()?.to_lowercase())))
|
|
|
},
|
|
@@ -139,15 +148,15 @@ impl fmt::Debug for BuiltinFunc {
|
|
|
}
|
|
|
|
|
|
enum NamedItem {
|
|
|
- Expr(Expr),
|
|
|
+ Expr(ExprRef),
|
|
|
Value(Value),
|
|
|
Builtin(&'static BuiltinFunc),
|
|
|
}
|
|
|
|
|
|
pub struct State {
|
|
|
- ast: ASTArena,
|
|
|
- scope: HashMap<Name, NamedItem>,
|
|
|
- rand: rand::rngs::ThreadRng,
|
|
|
+ ast: RefCell<ASTArena>,
|
|
|
+ scope: RefCell<HashMap<Name, NamedItem>>,
|
|
|
+ rand: RefCell<rand::rngs::ThreadRng>,
|
|
|
parser: crate::grammar::StmtsParser,
|
|
|
}
|
|
|
|
|
@@ -159,36 +168,40 @@ impl Default for State {
|
|
|
|
|
|
impl State {
|
|
|
pub fn new() -> State {
|
|
|
- let mut s = State {
|
|
|
- scope: HashMap::new(),
|
|
|
- rand: rand::thread_rng(),
|
|
|
+ let s = State {
|
|
|
+ scope: RefCell::new(HashMap::new()),
|
|
|
+ rand: RefCell::new(rand::thread_rng()),
|
|
|
parser: crate::grammar::StmtsParser::new(),
|
|
|
- ast: ASTArena::new(),
|
|
|
+ ast: RefCell::new(ASTArena::new()),
|
|
|
};
|
|
|
for builtin in BUILTINS {
|
|
|
- let sym = s.ast.add_string(builtin.name);
|
|
|
- s.scope.insert(sym, NamedItem::Builtin(builtin));
|
|
|
+ let sym = s.ast.borrow_mut().add_string(builtin.name);
|
|
|
+ s.scope.borrow_mut().insert(sym, NamedItem::Builtin(builtin));
|
|
|
}
|
|
|
s
|
|
|
}
|
|
|
|
|
|
- pub fn run(&mut self, src: &str) -> Result<(), Error> {
|
|
|
+ pub fn run(&self, src: &str) -> Result<(), Error> {
|
|
|
let lexed = crate::lexer::tokens(src);
|
|
|
- let stmts = self.parser.parse(&mut self.ast, lexed)?;
|
|
|
+ let stmts = self.parser.parse(&mut self.ast.borrow_mut(), lexed)?;
|
|
|
for stmt in stmts {
|
|
|
self.execute(&stmt)?;
|
|
|
}
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
- pub fn run_repl(&mut self, src: &str) -> Result<(), Error> {
|
|
|
+ pub fn run_repl(&self, src: &str) -> Result<(), Error> {
|
|
|
let lexed = crate::lexer::tokens(src);
|
|
|
- let stmts = match self.parser.parse(&mut self.ast, lexed) {
|
|
|
+ let stmts = {
|
|
|
+ let mut ast = self.ast.borrow_mut();
|
|
|
+ self.parser.parse(&mut ast, lexed)
|
|
|
+ };
|
|
|
+ let stmts = match stmts {
|
|
|
Ok(stmts) => stmts,
|
|
|
Err(err) => {
|
|
|
let with_puts = format!("puts {}", src);
|
|
|
let lexed = crate::lexer::tokens(&with_puts);
|
|
|
- if let Ok(stmts) = self.parser.parse(&mut self.ast, lexed) {
|
|
|
+ if let Ok(stmts) = self.parser.parse(&mut self.ast.borrow_mut(), lexed) {
|
|
|
stmts
|
|
|
} else {
|
|
|
return Err(err.into());
|
|
@@ -203,9 +216,9 @@ impl State {
|
|
|
|
|
|
pub fn autocomplete(&self, fragment: &str, at_beginning: bool) -> Vec<String> {
|
|
|
let mut possibilities = Vec::new();
|
|
|
- for name in self.scope.keys() {
|
|
|
- if self.ast[*name].starts_with(fragment) {
|
|
|
- possibilities.push(self.ast[*name].to_string());
|
|
|
+ for name in self.scope.borrow().keys() {
|
|
|
+ if self.ast.borrow()[*name].starts_with(fragment) {
|
|
|
+ possibilities.push(self.ast.borrow()[*name].to_string());
|
|
|
}
|
|
|
}
|
|
|
if at_beginning && "puts".starts_with(fragment) {
|
|
@@ -214,37 +227,37 @@ impl State {
|
|
|
possibilities
|
|
|
}
|
|
|
|
|
|
- pub fn execute(&mut self, stmt: &Stmt) -> Result<(), Error> {
|
|
|
+ pub fn execute(&self, stmt: &Stmt) -> Result<(), Error> {
|
|
|
match stmt {
|
|
|
Stmt::Puts(expr) => {
|
|
|
- let val = self.eval(expr)?;
|
|
|
+ let val = self.eval(*expr)?;
|
|
|
println!("{}", val.to_string());
|
|
|
}
|
|
|
|
|
|
Stmt::Fix(name) => {
|
|
|
- let expr = match self.scope.get(name) {
|
|
|
+ let expr = match self.scope.borrow().get(name) {
|
|
|
None => bail!("no such thing: {:?}", name),
|
|
|
- Some(NamedItem::Expr(e)) => e.clone(),
|
|
|
+ Some(NamedItem::Expr(e)) => *e,
|
|
|
// if it's not an expr, then our work here is done
|
|
|
_ => return Ok(()),
|
|
|
};
|
|
|
- let val = self.eval(&expr)?;
|
|
|
- self.scope.insert(*name, NamedItem::Value(val));
|
|
|
+ let val = self.eval(expr)?;
|
|
|
+ self.scope.borrow_mut().insert(*name, NamedItem::Value(val));
|
|
|
}
|
|
|
|
|
|
Stmt::Assn(fixed, name, expr) => {
|
|
|
if *fixed {
|
|
|
- let val = self.eval(expr)?;
|
|
|
- self.scope.insert(*name, NamedItem::Value(val));
|
|
|
+ let val = self.eval(*expr)?;
|
|
|
+ self.scope.borrow_mut().insert(*name, NamedItem::Value(val));
|
|
|
} else {
|
|
|
- self.scope.insert(*name, NamedItem::Expr(expr.clone()));
|
|
|
+ self.scope.borrow_mut().insert(*name, NamedItem::Expr(expr.clone()));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
Stmt::LitAssn(fixed, name, strs) => {
|
|
|
if *fixed {
|
|
|
- let choice = &strs[self.rand.gen_range(0..strs.len())];
|
|
|
- self.scope.insert(
|
|
|
+ let choice = &strs[self.rand.borrow_mut().gen_range(0..strs.len())];
|
|
|
+ self.scope.borrow_mut().insert(
|
|
|
*name,
|
|
|
NamedItem::Value(Value::Lit(Literal::Str(choice.clone()))),
|
|
|
);
|
|
@@ -255,36 +268,39 @@ impl State {
|
|
|
.iter()
|
|
|
.map(|s| Choice {
|
|
|
weight: None,
|
|
|
- value: Expr::Lit(Literal::Str(s.clone())),
|
|
|
+ value: self.ast.borrow_mut().add_expr(Expr::Lit(Literal::Str(s.clone()))),
|
|
|
})
|
|
|
.collect();
|
|
|
+ let choices = self.ast.borrow_mut().add_expr(Expr::Chc(choices));
|
|
|
self.scope
|
|
|
- .insert(*name, NamedItem::Expr(Expr::Chc(choices)));
|
|
|
+ .borrow_mut()
|
|
|
+ .insert(*name, NamedItem::Expr(choices));
|
|
|
}
|
|
|
}
|
|
|
Ok(())
|
|
|
}
|
|
|
|
|
|
- fn eval(&mut self, expr: &Expr) -> Result<Value, Error> {
|
|
|
+ fn eval(&self, expr: ExprRef) -> Result<Value, Error> {
|
|
|
+ let expr = &self.ast.borrow()[expr];
|
|
|
match expr {
|
|
|
Expr::Lit(l) => Ok(Value::Lit(l.clone())),
|
|
|
Expr::Nil => Ok(Value::Nil),
|
|
|
Expr::Var(v) => {
|
|
|
- let e = match self.scope.get(v) {
|
|
|
- Some(NamedItem::Expr(e)) => e.clone(),
|
|
|
+ let e = match self.scope.borrow().get(&v) {
|
|
|
+ Some(NamedItem::Expr(e)) => *e,
|
|
|
Some(NamedItem::Value(v)) => return Ok(v.clone()),
|
|
|
Some(NamedItem::Builtin(b)) => return Ok(Value::Builtin(b)),
|
|
|
None => bail!("no such thing: {:?}", v),
|
|
|
};
|
|
|
- self.eval(&e)
|
|
|
+ self.eval(e)
|
|
|
}
|
|
|
Expr::Cat(cat) => {
|
|
|
if cat.len() == 1 {
|
|
|
- self.eval(&cat[0])
|
|
|
+ self.eval(cat[0])
|
|
|
} else {
|
|
|
let mut buf = String::new();
|
|
|
for expr in cat {
|
|
|
- let val = self.eval(expr)?;
|
|
|
+ let val = self.eval(*expr)?;
|
|
|
buf.push_str(&val.to_string());
|
|
|
}
|
|
|
Ok(Value::Lit(Literal::Str(buf)))
|
|
@@ -292,36 +308,36 @@ impl State {
|
|
|
}
|
|
|
Expr::Chc(choices) => {
|
|
|
if choices.len() == 1 {
|
|
|
- self.eval(&choices[0].value)
|
|
|
+ self.eval(choices[0].value)
|
|
|
} else {
|
|
|
- self.choose(choices)
|
|
|
+ self.choose(&choices)
|
|
|
}
|
|
|
}
|
|
|
Expr::Tup(values) => Ok(Value::Tup(
|
|
|
values
|
|
|
.iter()
|
|
|
- .map(|v| self.eval(v))
|
|
|
+ .map(|v| self.eval(*v))
|
|
|
.collect::<Result<Vec<Value>, Error>>()?,
|
|
|
)),
|
|
|
- Expr::Ap(fun, arg) => match self.eval(fun)? {
|
|
|
- Value::Builtin(builtin) => (builtin.callback)(self, arg),
|
|
|
+ Expr::Ap(fun, arg) => match self.eval(*fun)? {
|
|
|
+ Value::Builtin(builtin) => (builtin.callback)(self, *arg),
|
|
|
_ => bail!("bad function: {:?}", fun),
|
|
|
},
|
|
|
Expr::Range(from, to) => {
|
|
|
- let from = self.eval(from)?.as_num()?;
|
|
|
- let to = self.eval(to)?.as_num()?;
|
|
|
- Ok(Value::Lit(Literal::Num(self.rand.gen_range(from..=to))))
|
|
|
+ let from = self.eval(*from)?.as_num()?;
|
|
|
+ let to = self.eval(*to)?.as_num()?;
|
|
|
+ Ok(Value::Lit(Literal::Num(self.rand.borrow_mut().gen_range(from..=to))))
|
|
|
}
|
|
|
_ => bail!("unimplemented: {:?}", expr),
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- fn choose(&mut self, choices: &[Choice]) -> Result<Value, Error> {
|
|
|
+ fn choose(&self, choices: &[Choice]) -> Result<Value, Error> {
|
|
|
let max = choices.iter().map(Choice::weight).sum();
|
|
|
- let mut choice = self.rand.gen_range(0..max);
|
|
|
+ let mut choice = self.rand.borrow_mut().gen_range(0..max);
|
|
|
for ch in choices {
|
|
|
if choice < ch.weight() {
|
|
|
- return self.eval(&ch.value);
|
|
|
+ return self.eval(ch.value);
|
|
|
}
|
|
|
choice -= ch.weight();
|
|
|
}
|