use ast::{TransformedNode, AstLocation, Comment};
use ast::transform::{Transform, TransformContext, TransformResult};
use ast::block_statements::*;
use ast::expression::*;
use scope::{ScopeData, ScopeValue};
use std::cell::RefCell;
use std::rc::Rc;
use std::fmt;
use errors::{Result, ErrorKind};
#[derive(Debug, Clone)]
pub struct Mixin {
pub name: String,
pub parameters: Vec<Param>,
pub statements: Vec<BlockStatement>,
pub location: AstLocation,
pub block_comments: Vec<Comment>,
pub inline_comment: Option<Comment>,
}
#[derive(Debug, Clone)]
pub struct PreparedMixin {
pub name: String,
pub parameters: Vec<PlainParam>,
pub statements: Vec<BlockStatement>,
}
impl Transform for Mixin {
fn transform(&self, ctx: TransformContext)
-> Result<Option<TransformedNode>> {
let mut t_params = Vec::new();
for param in &self.parameters {
if let Some(ref default_value) = param.default {
if let Some(t_value) = default_value.transform(ctx.clone())? {
t_params.push(PlainParam {
name: param.name.clone(),
default: Some(t_value.clone()),
})
} else {
return Err(ErrorKind::MissingValue(format!("{:?}", self), self.location.clone()).into())
}
} else {
t_params.push(PlainParam {
name: param.name.clone(),
default: None,
})
}
}
ctx.mut_scope().push_mixin(
self.name.clone(),
PreparedMixin {
name: self.name.clone(),
parameters: t_params,
statements: self.statements.clone(),
}
);
Ok(None)
}
fn location(&self) -> AstLocation {
self.location.clone()
}
}
#[derive(Debug, Clone)]
pub struct Param {
pub name: String,
pub default: Option<ExpressionNode>
}
#[derive(Debug, Clone)]
pub struct PlainParam {
pub name: String,
pub default: Option<TransformedNode>
}
#[derive(Clone)]
pub struct MixinCall {
pub name: String,
pub parameters: Vec<Box<ExpressionNode>>,
pub location: AstLocation,
pub comment: Option<Comment>,
}
impl<'a> fmt::Debug for MixinCall {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "MixinCall +{}(", self.name)?;
for param in &self.parameters {
write!(f, "{:?}, ", param)?;
}
write!(f, ")")
}
}
pub type ResolvedMixin<'a> = Vec<TransformedNode>;
impl Transform for MixinCall {
fn transform(&self, ctx: TransformContext)
-> Result<Option<TransformedNode>> {
if let Some(mixin) = ctx.ref_scope().mixin(&self.name) {
if mixin.parameters.len() != self.parameters.len() {
return Err(ErrorKind::WrongParameterCount(format!("{:?}", self),
mixin.parameters.len(),
self.parameters.len(),
self.location.clone()
).into());
}
let mut t_params: Vec<ScopeValue> = Vec::new();
for param in &self.parameters {
match param.transform(ctx.clone())? {
Some(transformed_param) => t_params.push(transformed_param.return_value()),
None => return Err(
ErrorKind::MissingValue(format!("{:?}", param), param.location().clone()).into()
)
}
}
let mut mixin_inner_scope = ScopeData::new(Some(ctx.scope.clone()));
for (i, item) in t_params.iter().enumerate().take(self.parameters.len()) {
mixin_inner_scope.push_var(mixin.parameters[i].name.clone(), item.return_value())
}
let inner_ctx = TransformContext {
scope: Rc::new(RefCell::new(mixin_inner_scope)),
path: ctx.path.clone(),
};
let mut t_statements: ResolvedMixin = Vec::new();
for statement in &mixin.statements {
if let Some(t_statement) = statement.transform(inner_ctx.clone())? {
t_statements.push(t_statement);
}
}
Ok(Some(
TransformedNode::ExpandedNodes(t_statements)
))
} else {
Err(
ErrorKind::MissingVarRef(self.name.clone(), self.location.clone()).into()
)
}
}
fn location(&self) -> AstLocation {
self.location.clone()
}
}