use std::convert::Infallible;
use std::borrow::Borrow;
use smallvec::{smallvec, SmallVec};
use std::hash::Hash;
use super::symbol_table::SymbolTable;
use super::ast::{Expr, Sexpr, Path, Let, Pattern, SimpleAssignment, Scope};
use crate::value::{
ValueDesc, ValId,
error::ValueError,
expr::SexprArgs
};
#[derive(Debug, Clone)]
pub struct Builder<S: Eq + Hash> {
symbols: SymbolTable<S, ValId>
}
#[derive(Debug, Clone)]
pub enum BuilderError<'a> {
ValueError(ValueError),
SymbolUndefined(&'a str),
BuildNotImplemented
}
impl<'a> From<ValueError> for BuilderError<'a> {
fn from(err: ValueError) -> BuilderError<'a> { BuilderError::ValueError(err) }
}
impl<'a> From<Infallible> for BuilderError<'a> {
fn from(err: Infallible) -> BuilderError<'a> { match err {} }
}
impl<'a> BuilderError<'a> {
pub fn val<E: Into<ValueError>>(err: E) -> BuilderError<'a>
{ BuilderError::ValueError(err.into()) }
}
pub const SMALL_DEFINITIONS: usize = 1;
#[derive(Debug, Clone)]
pub struct Definition<'a> {
pub name: &'a str,
pub value: ValId,
pub previous: Option<ValId>
}
impl<'a, S: Eq + Hash + From<&'a str> + Borrow<str>> Builder<S> {
pub fn new() -> Builder<S> {
Builder {
symbols: SymbolTable::new()
}
}
pub fn build_let(&mut self, let_statement: &Let<'a>) ->
Result<SmallVec<[Definition<'a>; SMALL_DEFINITIONS]>, BuilderError<'a>> {
self.assign_pattern(&let_statement.pattern, &let_statement.expr)
}
pub fn assign_pattern(&mut self, pattern: &Pattern<'a>, expr: &Expr<'a>) ->
Result<SmallVec<[Definition<'a>; SMALL_DEFINITIONS]>, BuilderError<'a>> {
match pattern {
Pattern::Simple(simple_assignment) =>
self.build_simple_assign(simple_assignment, expr)
.map(|assigned| smallvec![assigned])
}
}
pub fn build_simple_assign(&mut self, simple: &SimpleAssignment<'a>, expr: &Expr<'a>)
-> Result<Definition<'a>, BuilderError<'a>> {
let name = simple.name;
let value = self.build_expr(expr)?;
let previous = self.symbols.def(S::from(name), value.clone());
Ok(Definition{ name, value, previous })
}
pub fn build_expr(&mut self, expr: &Expr<'a>) -> Result<ValId, BuilderError<'a>> {
use Expr::*;
match expr {
Bool(b) => b.to_node(),
BoolTy(b) => b.to_node(),
LogicalOp(l) => l.to_node(),
Path(p) => self.lookup_path(p),
Sexpr(s) => self.build_sexpr(s),
Scope(s) => self.build_scope(s),
_ => Err(BuilderError::BuildNotImplemented)
}
}
pub fn build_scope(&mut self, scope: &Scope<'a>) -> Result<ValId, BuilderError<'a>> {
self.symbols.push(); for def in scope.definitions.iter() { self.build_let(def)?; }
let res = if let Some(value) = &scope.value {
self.build_expr(value)
} else {
Err(BuilderError::BuildNotImplemented)
};
self.symbols.pop(); res
}
pub fn lookup_path(&self, path: &Path<'a>) -> Result<ValId, BuilderError<'a>> {
if path.names.len() == 1 {
let name = path.names[0];
self.symbols.get(name).cloned().ok_or(BuilderError::SymbolUndefined(name))
} else {
Err(BuilderError::BuildNotImplemented)
}
}
pub fn build_sexpr(&mut self, sexpr: &Sexpr<'a>) -> Result<ValId, BuilderError<'a>> {
let args = self.build_sexpr_args(sexpr)?;
let sexpr = args.normalize().map_err(BuilderError::ValueError)?;
sexpr.to_node()
}
pub fn build_sexpr_args(&mut self, sexpr: &Sexpr<'a>) -> Result<SexprArgs, BuilderError<'a>> {
let mut ops = SmallVec::new();
for op in sexpr.ops.iter().map(|op| self.build_expr(op)) {
match op {
Ok(op) => ops.push(op),
Err(err) => return Err(err)
}
}
Ok(SexprArgs(ops))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::{parse_expr, parse_statement};
#[test]
fn simple_logical_expressions_build_properly() {
let mut builder = Builder::<&str>::new();
let t = &ValId::from(true);
let f = &ValId::from(false);
let logical_expressions = [
("(#and #true #false)", f),
("(#or #true #false)", t),
("(#not #true)", f),
("(#not #false)", t),
("(#xor #true #true)", f),
("(#or (#or #false #true) (#xor #false #false))", t)
];
for (expr, result) in logical_expressions.iter() {
let expr = match parse_expr(expr) {
Ok((rest, expr)) => {
assert_eq!(
rest, "",
"Did not parse all of valid expression \"{}\": remainder = {:?}",
expr, rest
);
expr
},
Err(err) => panic!("Got parse error {:?} for valid expression \"{}\"", err, expr)
};
let built = match builder.build_expr(&expr) {
Ok(built) => built,
Err(err) => panic!("Valid expression \"{}\" gives build error: {:#?}", expr, err)
};
assert_eq!(&built, *result);
}
}
#[test]
fn simple_assignments_build_properly() {
let mut builder = Builder::<&str>::new();
let program = [
"let false = (#or #false #false);",
"let true = (#and #true (#and #true #true));",
"let x = (#xor true false);",
"let y = (#xor true true);"
];
for line in program.iter() {
let l = match parse_statement(line) {
Ok((rest, l)) => {
assert_eq!(
rest, "",
"Unparsed portion {:?} of valid let \"{}\"",
rest, line
);
l
},
Err(err) =>
panic!("Valid let \"{}\" gives parse error: {:#?}", line, err)
};
match builder.build_let(&l) {
Ok(_) => {},
Err(err) => panic!("Valid let \"{}\" gives build error: {:#?}", line, err)
};
}
let t = &ValId::from(true);
let f = &ValId::from(false);
let variables = [
("true", t), ("false", f), ("x", t), ("y", f)
];
for (variable, value) in variables.iter() {
match builder.build_expr(&parse_expr(variable).expect("Valid identifier").1) {
Ok(built) => assert_eq!(
&built, *value,
"Invalid variable assignment {} = {} != {}", variable, built, value),
Err(err) => panic!("Error looking up variable {}: {:#?}", variable, err)
}
}
}
}