use std::rc::Rc;
use sindra::Node;
use sindra::scope::{Stack, Scoped, SymbolStore};
use visitor::State;
use Symbol;
use ast::ast::*;
type Result = ::std::result::Result<(), String>;
pub trait SymbolDefineVisitor {
fn visit(&self, &mut State) -> Result;
}
fn visit_block(block: &Node<Block>, state: &mut State) -> Result {
state.scope = state.scope.push();
block.visit(state)?;
match state.scope.pop() {
Some(parent_scope) => { state.scope = parent_scope; }
None => {
return Err("invalid descoping".to_string());
}
}
Ok(())
}
impl SymbolDefineVisitor for Node<Program> {
fn visit(&self, state: &mut State) -> Result {
visit_block(&self.item.0, state)?;
self.annotation.borrow_mut().set_scope(Some(Rc::clone(&state.scope)));
Ok(())
}
}
impl SymbolDefineVisitor for Node<Block> {
fn visit(&self, state: &mut State) -> Result {
for statement in self.item.0.iter() {
statement.visit(state)?;
}
self.annotation.borrow_mut().set_scope(Some(Rc::clone(&state.scope)));
Ok(())
}
}
impl SymbolDefineVisitor for Node<Statement> {
fn visit(&self, state: &mut State) -> Result {
self.annotation.borrow_mut().set_scope(Some(Rc::clone(&state.scope)));
match self.item {
Statement::Declare(ref id, ref expr) => {
expr.visit(state)?;
let id = id.item.clone();
state.scope.borrow_mut().define(id.clone(),
Symbol::variable(id.clone(), None));
Ok(())
},
Statement::Assign(ref id, ref expr) => {
expr.visit(state)?;
let id = id.item.clone();
let sym: Option<Symbol> = state.scope.borrow().resolve(&id);
match sym {
Some(_) => {
Ok(())
},
None => {
state.logger.error(format!("symbol '{}' does not exist in scope",
id));
Ok(())
}
}
},
Statement::Expression(ref expr) => {
expr.visit(state)
},
Statement::FnDefine(FunctionDef { ref name, ref body, ref params, .. }) => {
let parent = state.scope.peek();
if parent.is_some() && Rc::ptr_eq(&parent.unwrap(), &state.global) {
let prev_scope = Rc::clone(&state.scope);
state.scope = state.global.push();
for param in params.iter() {
let param_name = param.item.name.item.clone();
state.scope.borrow_mut().define(param_name.clone(),
Symbol::variable(param_name.clone(), None));
}
body.visit(state)?;
state.scope = prev_scope;
state.scope.borrow_mut().define(name.item.clone(),
Symbol::function(name.item.clone(), None, body.clone(),
params.clone()));
Ok(())
} else {
state.logger.error(format!("function definition '{}' only allowed at \
global scope", name.item));
Ok(())
}
},
Statement::Return(ref expr) | Statement::Break(ref expr) => {
expr.visit(state)?;
Ok(())
},
Statement::Print(ref exprs) => {
for expr in exprs {
expr.visit(state)?;
}
Ok(())
}
}
}
}
impl SymbolDefineVisitor for Node<Expression> {
fn visit(&self, state: &mut State) -> Result {
self.annotation.borrow_mut().set_scope(Some(Rc::clone(&state.scope)));
match self.item {
Expression::Literal(_) => {
Ok(())
},
Expression::Identifier(ref id) => {
let sym: Option<Symbol> = state.scope.borrow().resolve(&id.item);
match sym {
Some(_) => Ok(()),
None => {
state.logger.error(format!("symbol '{}' does not exist in scope",
id.item));
Ok(())
}
}
},
Expression::Infix { ref left, ref right, .. } => {
left.visit(state)?;
right.visit(state)?;
Ok(())
},
Expression::Prefix { ref right, .. } => {
right.visit(state)?;
Ok(())
},
Expression::Postfix { ref left, .. } => {
left.visit(state)?;
Ok(())
},
Expression::Block(ref block) => {
visit_block(block, state)
},
Expression::FnCall { name: ref ident, ref args } => {
for ref arg in args.iter() {
arg.visit(state)?;
}
let id = ident.item.clone();
match state.scope.borrow().resolve(&id) {
Some(Symbol::Function { ref params, .. }) => {
if args.len() != params.len() {
state.logger.error(format!("invalid number of arguments for function \
'{}': expected {}, found {}", id, params.len(),
args.len()));
}
Ok(())
},
Some(_) => {
state.logger.error(format!("attempt to call non-function '{}' as function",
id));
Ok(())
}
None => {
state.logger.error(format!("function '{}' does not exist in scope",
id));
Ok(())
}
}
},
Expression::IfElse { ref cond, ref if_block, ref else_block } => {
cond.visit(state)?;
visit_block(if_block, state)?;
if let Some(ref else_block) = *else_block {
visit_block(else_block, state)?;
}
Ok(())
},
Expression::Loop { ref variant, ref set, ref body } => {
state.scope = state.scope.push();
set.visit(state)?;
match *variant {
Some(ref var) => {
state.scope.borrow_mut().define(var.item.clone(),
Symbol::variable(var.item.clone(), None));
},
None => {}
}
body.visit(state)?;
match state.scope.pop() {
Some(parent_scope) => { state.scope = parent_scope; }
None => {
return Err("invalid descoping".to_string());
}
}
Ok(())
}
}
}
}
impl SymbolDefineVisitor for Node<Set> {
fn visit(&self, state: &mut State) -> Result {
self.annotation.borrow_mut().set_scope(Some(Rc::clone(&state.scope)));
match self.item {
Set::Interval { ref start, ref end, ref step, .. } => {
start.visit(state)?;
end.visit(state)?;
step.visit(state)?;
Ok(())
}
}
}
}