Skip to content

Commit

Permalink
all tests passing
Browse files Browse the repository at this point in the history
  • Loading branch information
Protryon committed Jan 9, 2021
1 parent 8cf46e0 commit f56d869
Show file tree
Hide file tree
Showing 138 changed files with 1,344 additions and 1,243 deletions.
3 changes: 3 additions & 0 deletions asg/src/checks/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

mod return_path;
pub use return_path::*;
76 changes: 76 additions & 0 deletions asg/src/checks/return_path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use crate::{ BoolAnd, MonoidalReducerExpression, MonoidalReducerStatement, Monoid, Expression, statement::*, Span, Node };
use std::sync::Arc;

pub struct ReturnPathReducer {
pub errors: Vec<(Span, String)>,
}

impl ReturnPathReducer {
fn record_error(&mut self, span: Option<&Span>, error: String) {
self.errors.push((span.cloned().unwrap_or_default(), error));
}

pub fn new() -> ReturnPathReducer {
ReturnPathReducer {
errors: vec![],
}
}
}

#[allow(unused_variables)]
impl MonoidalReducerExpression<BoolAnd> for ReturnPathReducer {
fn reduce_expression(&mut self, input: &Arc<Expression>, value: BoolAnd) -> BoolAnd {
BoolAnd(false)
}
}

#[allow(unused_variables)]
impl MonoidalReducerStatement<BoolAnd> for ReturnPathReducer {
fn reduce_assign_access(&mut self, input: &AssignAccess, left: Option<BoolAnd>, right: Option<BoolAnd>) -> BoolAnd {
BoolAnd(false)
}

fn reduce_assign(&mut self, input: &AssignStatement, accesses: Vec<BoolAnd>, value: BoolAnd) -> BoolAnd {
BoolAnd(false)
}

fn reduce_block(&mut self, input: &BlockStatement, statements: Vec<BoolAnd>) -> BoolAnd {
if statements.len() == 0 {
BoolAnd(false)
} else if let Some(index) = statements[..statements.len() - 1].iter().map(|x| x.0).position(|x| x) {
self.record_error(input.statements[index].span(), "dead code due to unconditional early return".to_string());
BoolAnd(true)
} else {
BoolAnd(statements[statements.len() - 1].0)
}
}

fn reduce_conditional_statement(&mut self, input: &ConditionalStatement, condition: BoolAnd, if_true: BoolAnd, if_false: Option<BoolAnd>) -> BoolAnd {
if_true.append(if_false.unwrap_or_else(|| BoolAnd(false)))
}

fn reduce_formatted_string(&mut self, input: &FormattedString, parameters: Vec<BoolAnd>) -> BoolAnd {
BoolAnd(false)
}

fn reduce_console(&mut self, input: &ConsoleStatement, argument: BoolAnd) -> BoolAnd {
BoolAnd(false)
}

fn reduce_definition(&mut self, input: &DefinitionStatement, value: BoolAnd) -> BoolAnd {
BoolAnd(false)
}

fn reduce_expression_statement(&mut self, input: &ExpressionStatement, expression: BoolAnd) -> BoolAnd {
BoolAnd(false)
}

fn reduce_iteration(&mut self, input: &IterationStatement, start: BoolAnd, stop: BoolAnd, body: BoolAnd) -> BoolAnd {
// loops are const defined ranges, so we could probably check if they run one and emit here
BoolAnd(false)
}

fn reduce_return(&mut self, input: &ReturnStatement, value: BoolAnd) -> BoolAnd {
BoolAnd(true)
}
}
24 changes: 24 additions & 0 deletions asg/src/error/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ impl AsgConvertError {
Self::new_from_span(format!("cannot call variable member '{}' of circuit '{}'", name, circuit_name), span)
}

pub fn circuit_static_call_invalid(circuit_name: &str, name: &str, span: &Span) -> Self {
Self::new_from_span(format!("cannot call static function '{}' of circuit '{}' from target", name, circuit_name), span)
}

pub fn circuit_member_mut_call_invalid(circuit_name: &str, name: &str, span: &Span) -> Self {
Self::new_from_span(format!("cannot call mutable member function '{}' of circuit '{}' from immutable context", name, circuit_name), span)
}

pub fn circuit_member_call_invalid(circuit_name: &str, name: &str, span: &Span) -> Self {
Self::new_from_span(format!("cannot call member function '{}' of circuit '{}' from static context", name, circuit_name), span)
}

pub fn circuit_function_ref(circuit_name: &str, name: &str, span: &Span) -> Self {
Self::new_from_span(format!("cannot reference function member '{}' of circuit '{}' as value", name, circuit_name), span)
}
Expand Down Expand Up @@ -91,6 +103,18 @@ impl AsgConvertError {
Self::new_from_span(format!("illegal assignment to immutable variable '{}'", name), span)
}

pub fn function_missing_return(name: &str, span: &Span) -> Self {
Self::new_from_span(format!("function '{}' missing return for all paths", name), span)
}

pub fn function_return_validation(name: &str, description: &str, span: &Span) -> Self {
Self::new_from_span(format!("function '{}' failed to validate return path: '{}'", name, description), span)
}

pub fn input_ref_needs_type(category: &str, name: &str, span: &Span) -> Self {
Self::new_from_span(format!("could not infer type for input in '{}': '{}'", category, name), span)
}

pub fn invalid_self_in_global(span: &Span) -> Self {
Self::new_from_span("cannot have `mut self` or `self` arguments in global functions".to_string(), span)
}
Expand Down
4 changes: 4 additions & 0 deletions asg/src/expression/array_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ impl ExpressionNode for ArrayAccessExpression {
}
}

fn is_mut_ref(&self) -> bool {
self.array.is_mut_ref()
}

fn const_value(&self) -> Option<ConstValue> {
let mut array = match self.array.const_value()? {
ConstValue::Array(values) => values,
Expand Down
4 changes: 4 additions & 0 deletions asg/src/expression/array_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ impl ExpressionNode for ArrayInitExpression {
Some(Type::Array(Box::new(self.element.get_type()?), self.len))
}

fn is_mut_ref(&self) -> bool {
false
}

fn const_value(&self) -> Option<ConstValue> {
// not implemented due to performance concerns
None
Expand Down
4 changes: 4 additions & 0 deletions asg/src/expression/array_inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ impl ExpressionNode for ArrayInlineExpression {
Some(Type::Array(Box::new(self.elements.first()?.0.get_type()?), self.len()))
}

fn is_mut_ref(&self) -> bool {
false
}

fn const_value(&self) -> Option<ConstValue> {
let mut const_values = vec![];
for (expr, spread) in self.elements.iter() {
Expand Down
6 changes: 5 additions & 1 deletion asg/src/expression/array_range_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ impl ExpressionNode for ArrayRangeAccessExpression {
Some(Type::Array(element, (const_right - const_left) as usize))
}

fn is_mut_ref(&self) -> bool {
self.array.is_mut_ref()
}

fn const_value(&self) -> Option<ConstValue> {
let mut array = match self.array.const_value()? {
ConstValue::Array(values) => values,
Expand All @@ -86,7 +90,7 @@ impl ExpressionNode for ArrayRangeAccessExpression {
impl FromAst<leo_ast::ArrayRangeAccessExpression> for ArrayRangeAccessExpression {
fn from_ast(scope: &Scope, value: &leo_ast::ArrayRangeAccessExpression, expected_type: Option<PartialType>) -> Result<ArrayRangeAccessExpression, AsgConvertError> {
let expected_array = match expected_type {
Some(PartialType::Array(element, len)) => {
Some(PartialType::Array(element, _len)) => {
Some(PartialType::Array(element, None))
},
None => None,
Expand Down
55 changes: 41 additions & 14 deletions asg/src/expression/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ impl ExpressionNode for BinaryExpression {
}
}

fn is_mut_ref(&self) -> bool {
false
}

fn const_value(&self) -> Option<ConstValue> {
use BinaryOperation::*;
let left = self.left.const_value()?;
Expand All @@ -61,17 +65,17 @@ impl ExpressionNode for BinaryExpression {
_ => return None,
})
},
(ConstValue::Field(left), ConstValue::Field(right)) => {
Some(match self.operation {
Add => ConstValue::Field(left.checked_add(&right)?),
Sub => ConstValue::Field(left.checked_sub(&right)?),
Mul => ConstValue::Field(left.checked_mul(&right)?),
Div => ConstValue::Field(left.checked_div(&right)?),
Eq => ConstValue::Boolean(left == right),
Ne => ConstValue::Boolean(left != right),
_ => return None,
})
},
// (ConstValue::Field(left), ConstValue::Field(right)) => {
// Some(match self.operation {
// Add => ConstValue::Field(left.checked_add(&right)?),
// Sub => ConstValue::Field(left.checked_sub(&right)?),
// Mul => ConstValue::Field(left.checked_mul(&right)?),
// Div => ConstValue::Field(left.checked_div(&right)?),
// Eq => ConstValue::Boolean(left == right),
// Ne => ConstValue::Boolean(left != right),
// _ => return None,
// })
// },
(ConstValue::Boolean(left), ConstValue::Boolean(right)) => {
Some(match self.operation {
Eq => ConstValue::Boolean(left == right),
Expand Down Expand Up @@ -110,9 +114,33 @@ impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
None => None,
}
},
}.map(Type::partial);

// left
let (left, right) = match Arc::<Expression>::from_ast(scope, &*value.left, expected_type.clone()) {
Ok(left) => {
if let Some(left_type) = left.get_type() {
let right = Arc::<Expression>::from_ast(scope, &*value.right, Some(left_type.partial()))?;
(left, right)
} else {
let right = Arc::<Expression>::from_ast(scope, &*value.right, expected_type.clone())?;
if let Some(right_type) = right.get_type() {
(Arc::<Expression>::from_ast(scope, &*value.left, Some(right_type.partial()))?, right)
} else {
(left, right)
}
}
},
Err(e) => {
let right = Arc::<Expression>::from_ast(scope, &*value.right, expected_type.clone())?;
if let Some(right_type) = right.get_type() {
(Arc::<Expression>::from_ast(scope, &*value.left, Some(right_type.partial()))?, right)
} else {
return Err(e);
}
}
};
//todo: would be nice to have bidirectional type drilldown here
let left = Arc::<Expression>::from_ast(scope, &*value.left, expected_type.map(Type::partial))?;

let left_type = left.get_type();
match class {
BinaryOperationClass::Numeric => match left_type {
Expand All @@ -137,7 +165,6 @@ impl FromAst<leo_ast::BinaryExpression> for BinaryExpression {
}
}

let right = Arc::<Expression>::from_ast(scope, &*value.right, left_type.clone().map(Type::partial))?;
let right_type = right.get_type();

match (left_type, right_type) {
Expand Down
24 changes: 21 additions & 3 deletions asg/src/expression/call.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
pub use leo_ast::BinaryOperation;
use crate::Span;
use crate::{ Expression, Function, Node, Type, ExpressionNode, FromAst, Scope, AsgConvertError, CircuitMember, ConstValue, PartialType };
use crate::{ Expression, Function, Node, Type, ExpressionNode, FromAst, Scope, AsgConvertError, CircuitMember, ConstValue, PartialType, FunctionQualifier };
use std::sync::{ Weak, Arc };
use std::cell::RefCell;

Expand Down Expand Up @@ -40,6 +40,10 @@ impl ExpressionNode for CallExpression {
Some(self.function.output.clone().into())
}

fn is_mut_ref(&self) -> bool {
false
}

fn const_value(&self) -> Option<ConstValue> {
// static function const evaluation
None
Expand All @@ -60,7 +64,16 @@ impl FromAst<leo_ast::CallExpression> for CallExpression {
let member = circuit.members.borrow();
let member = member.get(&name.name).ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit.name.name, &name.name, &span))?;
match member {
CircuitMember::Function(body) => (Some(target), body.clone()),
CircuitMember::Function(body) => {
if body.qualifier == FunctionQualifier::Static {
return Err(AsgConvertError::circuit_static_call_invalid(&circuit.name.name, &name.name, &span));
} else if body.qualifier == FunctionQualifier::MutSelfRef {
if !target.is_mut_ref() {
return Err(AsgConvertError::circuit_member_mut_call_invalid(&circuit.name.name, &name.name, &span));
}
}
(Some(target), body.clone())
},
CircuitMember::Variable(_) => return Err(AsgConvertError::circuit_variable_call(&circuit.name.name, &name.name, &span))?,
}
},
Expand All @@ -73,7 +86,12 @@ impl FromAst<leo_ast::CallExpression> for CallExpression {
let member = circuit.members.borrow();
let member = member.get(&name.name).ok_or_else(|| AsgConvertError::unresolved_circuit_member(&circuit.name.name, &name.name, &span))?;
match member {
CircuitMember::Function(body) => (None, body.clone()),
CircuitMember::Function(body) => {
if body.qualifier != FunctionQualifier::Static {
return Err(AsgConvertError::circuit_member_call_invalid(&circuit.name.name, &name.name, &span));
}
(None, body.clone())
},
CircuitMember::Variable(_) => return Err(AsgConvertError::circuit_variable_call(&circuit.name.name, &name.name, &span))?,
}
},
Expand Down
46 changes: 38 additions & 8 deletions asg/src/expression/circuit_access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ impl ExpressionNode for CircuitAccessExpression {
}
}

fn is_mut_ref(&self) -> bool {
if let Some(target) = self.target.as_ref() {
target.is_mut_ref()
} else {
false
}
}

fn const_value(&self) -> Option<ConstValue> {
None
}
Expand All @@ -58,14 +66,36 @@ impl FromAst<leo_ast::CircuitMemberAccessExpression> for CircuitAccessExpression
x => return Err(AsgConvertError::unexpected_type("circuit", x.map(|x| x.to_string()).as_deref(), &value.span)),
};

if let Some(member) = circuit.members.borrow().get(&value.name.name) {
if let Some(expected_type) = expected_type {
if let CircuitMember::Variable(type_) = &member {
let type_: Type = type_.clone().into();
if !expected_type.matches(&type_) {
return Err(AsgConvertError::unexpected_type(&expected_type.to_string(), Some(&type_.to_string()), &value.span));
}
} // used by call expression

// scoping refcell reference
let found_member = {
if let Some(member) = circuit.members.borrow().get(&value.name.name) {
if let Some(expected_type) = &expected_type {
if let CircuitMember::Variable(type_) = &member {
let type_: Type = type_.clone().into();
if !expected_type.matches(&type_) {
return Err(AsgConvertError::unexpected_type(&expected_type.to_string(), Some(&type_.to_string()), &value.span));
}
} // used by call expression
}
true
} else {
false
}
};

if found_member {
// skip
} else if circuit.is_input_psuedo_circuit() { // add new member to implicit input
if let Some(expected_type) = expected_type.map(PartialType::full).flatten() {
circuit.members.borrow_mut().insert(
value.name.name.clone(),
CircuitMember::Variable(
expected_type.into()
)
);
} else {
return Err(AsgConvertError::input_ref_needs_type(&circuit.name.name, &value.name.name, &value.span));
}
} else {
return Err(AsgConvertError::unresolved_circuit_member(&circuit.name.name, &value.name.name, &value.span));
Expand Down
4 changes: 4 additions & 0 deletions asg/src/expression/circuit_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ impl ExpressionNode for CircuitInitExpression {
Some(Type::Circuit(self.circuit.clone()))
}

fn is_mut_ref(&self) -> bool {
false
}

fn const_value(&self) -> Option<ConstValue> {
None
}
Expand Down
4 changes: 4 additions & 0 deletions asg/src/expression/conditional.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ impl ExpressionNode for ConditionalExpression {
self.if_true.get_type()
}

fn is_mut_ref(&self) -> bool {
self.if_true.is_mut_ref() && self.if_false.is_mut_ref()
}

fn const_value(&self) -> Option<ConstValue> {
if let Some(ConstValue::Boolean(switch)) = self.condition.const_value() {
if switch {
Expand Down
Loading

0 comments on commit f56d869

Please sign in to comment.