diff --git a/zokrates_cli/src/bin.rs b/zokrates_cli/src/bin.rs index 7ab00892..8e955a33 100644 --- a/zokrates_cli/src/bin.rs +++ b/zokrates_cli/src/bin.rs @@ -233,7 +233,7 @@ fn main() { match matches.subcommand() { ("compile", Some(sub_matches)) => { - println!("Compiling {}", sub_matches.value_of("input").unwrap()); + println!("Compiling {}\n", sub_matches.value_of("input").unwrap()); let path = PathBuf::from(sub_matches.value_of("input").unwrap()); @@ -258,7 +258,10 @@ fn main() { let program_flattened: ir::Prog = match compile(&mut reader, Some(location), Some(fs_resolve)) { Ok(p) => p, - Err(why) => panic!("Compilation failed: {}", why), + Err(why) => { + println!("Compilation failed:\n\n{}", why); + std::process::exit(1); + } }; // number of constraints the flattened program will translate to. diff --git a/zokrates_core/src/absy/mod.rs b/zokrates_core/src/absy/mod.rs index 94cb9031..710d6331 100644 --- a/zokrates_core/src/absy/mod.rs +++ b/zokrates_core/src/absy/mod.rs @@ -9,21 +9,21 @@ mod node; pub mod parameter; pub mod variable; -pub use absy::node::Node; -pub use absy::parameter::Parameter; +pub use absy::node::{Node, NodeValue}; +pub use absy::parameter::{Parameter, ParameterNode}; pub use absy::variable::{Variable, VariableNode}; use types::Signature; use flat_absy::*; -use imports::Import; +use imports::ImportNode; use std::fmt; use zokrates_field::field::Field; #[derive(Clone, PartialEq)] pub struct Prog { /// Functions of the program - pub functions: Vec>, - pub imports: Vec, + pub functions: Vec>, + pub imports: Vec, pub imported_functions: Vec>, } @@ -81,13 +81,15 @@ pub struct Function { /// Name of the program pub id: String, /// Arguments of the function - pub arguments: Vec, + pub arguments: Vec, /// Vector of statements that are executed when running the function - pub statements: Vec>, + pub statements: Vec>, /// function signature pub signature: Signature, } +pub type FunctionNode = Node>; + impl fmt::Display for Function { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( @@ -176,10 +178,12 @@ pub enum Statement { Declaration(VariableNode), Definition(AssigneeNode, ExpressionNode), Condition(ExpressionNode, ExpressionNode), - For(VariableNode, T, T, Vec>), + For(VariableNode, T, T, Vec>), MultipleDefinition(Vec>, ExpressionNode), } +pub type StatementNode = Node>; + impl fmt::Display for Statement { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { diff --git a/zokrates_core/src/absy/node.rs b/zokrates_core/src/absy/node.rs index f73a79c0..a5cfa9ac 100644 --- a/zokrates_core/src/absy/node.rs +++ b/zokrates_core/src/absy/node.rs @@ -1,7 +1,7 @@ use parser::Position; use std::fmt; -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Node { pub start: Position, pub end: Position, @@ -16,7 +16,7 @@ impl Node { impl fmt::Display for Node { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} ({}:{})", self.value, self.start, self.end) + write!(f, "{}", self.value) } } @@ -25,3 +25,38 @@ impl Node { Node { start, end, value } } } + +pub trait NodeValue: fmt::Display + Sized + PartialEq { + fn at(self, line: usize, col: usize, delta: isize) -> Node { + let start = Position { col, line }; + Node::new(start, start.col(delta), self) + } +} + +#[cfg(test)] +impl From for Node { + fn from(v: V) -> Node { + let mock_position = Position { col: 42, line: 42 }; + Node::new(mock_position, mock_position, v) + } +} + +use absy::*; +use imports::*; +use zokrates_field::field::Field; + +impl NodeValue for Expression {} +impl NodeValue for ExpressionList {} +impl NodeValue for Assignee {} +impl NodeValue for Statement {} +impl NodeValue for Function {} +impl NodeValue for Prog {} +impl NodeValue for Variable {} +impl NodeValue for Parameter {} +impl NodeValue for Import {} + +impl std::cmp::PartialEq for Node { + fn eq(&self, other: &Node) -> bool { + self.value.eq(&other.value) + } +} diff --git a/zokrates_core/src/absy/parameter.rs b/zokrates_core/src/absy/parameter.rs index 8a1f10de..fda05c34 100644 --- a/zokrates_core/src/absy/parameter.rs +++ b/zokrates_core/src/absy/parameter.rs @@ -1,32 +1,40 @@ -use absy::Variable; +use absy::{Node, VariableNode}; use std::fmt; #[derive(Clone, PartialEq, Serialize, Deserialize)] pub struct Parameter { - pub id: Variable, + pub id: VariableNode, pub private: bool, } impl Parameter { - pub fn public(v: Variable) -> Self { - Parameter { - id: v, - private: true, - } - } - - pub fn private(v: Variable) -> Self { + pub fn public(v: VariableNode) -> Self { Parameter { id: v, private: false, } } + + pub fn private(v: VariableNode) -> Self { + Parameter { + id: v, + private: true, + } + } } +pub type ParameterNode = Node; + impl fmt::Display for Parameter { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let visibility = if self.private { "private " } else { "" }; - write!(f, "{}{} {}", visibility, self.id.get_type(), self.id.id) + write!( + f, + "{}{} {}", + visibility, + self.id.value.get_type(), + self.id.value.id + ) } } diff --git a/zokrates_core/src/compile.rs b/zokrates_core/src/compile.rs index af869b83..258fc56f 100644 --- a/zokrates_core/src/compile.rs +++ b/zokrates_core/src/compile.rs @@ -18,44 +18,106 @@ use std::io::BufRead; use zokrates_field::field::Field; #[derive(Debug)] -pub enum CompileError { +pub struct CompileErrors(Vec>); + +impl From> for CompileErrors { + fn from(e: CompileError) -> CompileErrors { + CompileErrors(vec![e]) + } +} + +impl fmt::Display for CompileErrors { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "{}", + self.0 + .iter() + .map(|e| format!("{}", e)) + .collect::>() + .join("\n\n") + ) + } +} + +#[derive(Debug)] +pub enum CompileErrorInner { ParserError(parser::Error), ImportError(imports::Error), SemanticError(semantics::Error), ReadError(io::Error), } -impl From> for CompileError { - fn from(error: parser::Error) -> Self { - CompileError::ParserError(error) +impl CompileErrorInner { + pub fn with_context(self, context: &Option) -> CompileError { + CompileError { + value: self, + context: context.clone(), + } } } -impl From for CompileError { - fn from(error: imports::Error) -> Self { - CompileError::ImportError(error) - } +#[derive(Debug)] +pub struct CompileError { + context: Option, + value: CompileErrorInner, } -impl From for CompileError { - fn from(error: io::Error) -> Self { - CompileError::ReadError(error) - } -} - -impl From for CompileError { - fn from(error: semantics::Error) -> Self { - CompileError::SemanticError(error) +impl CompileErrors { + pub fn with_context(self, context: Option) -> Self { + CompileErrors( + self.0 + .into_iter() + .map(|e| CompileError { + context: context.clone(), + ..e + }) + .collect(), + ) } } impl fmt::Display for CompileError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let context = match self.context { + Some(ref x) => x.clone(), + None => "???".to_string(), + }; + write!(f, "{}:{}", context, self.value) + } +} + +impl From> for CompileErrorInner { + fn from(error: parser::Error) -> Self { + CompileErrorInner::ParserError(error) + } +} + +impl From for CompileErrorInner { + fn from(error: imports::Error) -> Self { + CompileErrorInner::ImportError(error) + } +} + +impl From for CompileErrorInner { + fn from(error: io::Error) -> Self { + CompileErrorInner::ReadError(error) + } +} + +impl From for CompileErrorInner { + fn from(error: semantics::Error) -> Self { + CompileErrorInner::SemanticError(error) + } +} + +impl fmt::Display for CompileErrorInner { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let res = match *self { - CompileError::ParserError(ref e) => format!("Syntax error: {}", e), - CompileError::SemanticError(ref e) => format!("Semantic error: \n{}\n", e), - CompileError::ReadError(ref e) => format!("Read error: {}", e), - CompileError::ImportError(ref e) => format!("Import error: {}", e), + CompileErrorInner::ParserError(ref e) => format!("{}", e), + CompileErrorInner::SemanticError(ref e) => format!("{}", e), + CompileErrorInner::ReadError(ref e) => format!("{}", e), + CompileErrorInner::ImportError(ref e) => format!("{}", e), }; write!(f, "{}", res) } @@ -65,7 +127,7 @@ pub fn compile>( reader: &mut R, location: Option, resolve_option: Option, &String) -> Result<(S, String, String), E>>, -) -> Result, CompileError> { +) -> Result, CompileErrors> { let compiled = compile_aux(reader, location, resolve_option)?; Ok(ir::Prog::from(Optimizer::new().optimize_program(compiled))) } @@ -74,8 +136,9 @@ pub fn compile_aux>( reader: &mut R, location: Option, resolve_option: Option, &String) -> Result<(S, String, String), E>>, -) -> Result, CompileError> { - let program_ast_without_imports: Prog = parse_program(reader)?; +) -> Result, CompileErrors> { + let program_ast_without_imports: Prog = parse_program(reader) + .map_err(|e| CompileErrors::from(CompileErrorInner::from(e).with_context(&location)))?; let program_ast = Importer::new().apply_imports( program_ast_without_imports, @@ -84,7 +147,16 @@ pub fn compile_aux>( )?; // check semantics - let typed_ast = Checker::new().check_program(program_ast)?; + let typed_ast = Checker::new() + .check_program(program_ast) + .map_err(|errors| { + CompileErrors( + errors + .into_iter() + .map(|e| CompileErrorInner::from(e).with_context(&location)) + .collect(), + ) + })?; // analyse (unroll and constant propagation) let typed_ast = typed_ast.analyse(); @@ -114,7 +186,7 @@ mod test { "# .as_bytes(), ); - let res: Result, CompileError> = compile( + let res: Result, CompileErrors> = compile( &mut r, Some(String::from("./path/to/file")), None::< @@ -124,10 +196,11 @@ mod test { ) -> Result<(BufReader, String, String), io::Error>, >, ); - assert_eq!( - format!("{}", res.unwrap_err()), - "Import error: Can't resolve import without a resolver".to_string() - ); + + assert!(res + .unwrap_err() + .to_string() + .contains(&"Can't resolve import without a resolver")); } #[test] @@ -139,7 +212,7 @@ mod test { "# .as_bytes(), ); - let res: Result, CompileError> = compile( + let res: Result, CompileErrors> = compile( &mut r, Some(String::from("./path/to/file")), None::< diff --git a/zokrates_core/src/flatten/mod.rs b/zokrates_core/src/flatten/mod.rs index 8c0f2cf1..1f29c937 100644 --- a/zokrates_core/src/flatten/mod.rs +++ b/zokrates_core/src/flatten/mod.rs @@ -5,8 +5,6 @@ //! @author Jacob Eberhardt //! @date 2017 -use absy::parameter::Parameter; -use absy::variable::Variable; use bimap::BiMap; use flat_absy::*; use helpers::{DirectiveStatement, Helper, RustHelper}; @@ -1396,6 +1394,7 @@ impl Flattener { let mut arguments_flattened: Vec = Vec::new(); let mut statements_flattened: Vec> = Vec::new(); + // push parameters for arg in &funct.arguments { let arg_type = arg.id.get_type(); @@ -1508,7 +1507,6 @@ impl Flattener { #[cfg(test)] mod tests { use super::*; - use absy::variable::Variable; use types::Signature; use types::Type; use zokrates_field::field::FieldPrime; diff --git a/zokrates_core/src/imports.rs b/zokrates_core/src/imports.rs index d09a9ae6..4e77705d 100644 --- a/zokrates_core/src/imports.rs +++ b/zokrates_core/src/imports.rs @@ -6,8 +6,9 @@ use absy::*; use compile::compile_aux; -use compile::CompileError; +use compile::{CompileErrorInner, CompileErrors}; use flat_absy::*; +use parser::Position; use std::fmt; use std::io; use std::io::BufRead; @@ -33,27 +34,38 @@ impl CompiledImport { #[derive(PartialEq, Debug)] pub struct Error { + pos: Option<(Position, Position)>, message: String, } impl Error { pub fn new>(message: T) -> Error { Error { + pos: None, message: message.into(), } } + + fn with_pos(self, pos: Option<(Position, Position)>) -> Error { + Error { pos, ..self } + } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.message) + let location = self + .pos + .map(|p| format!("{}", p.0)) + .unwrap_or("?".to_string()); + write!(f, "{}\n\t{}", location, self.message) } } impl From for Error { fn from(error: io::Error) -> Self { Error { - message: format!("I/O Error: {:?}", error), + pos: None, + message: format!("I/O Error: {}", error), } } } @@ -64,6 +76,8 @@ pub struct Import { alias: Option, } +pub type ImportNode = Node; + impl Import { pub fn new(source: String) -> Import { Import { @@ -118,72 +132,83 @@ impl Importer { destination: Prog, location: Option, resolve_option: Option, &String) -> Result<(S, String, String), E>>, - ) -> Result, CompileError> { + ) -> Result, CompileErrors> { let mut origins: Vec> = vec![]; for import in destination.imports.iter() { + let pos = import.pos(); + let import = &import.value; // handle the case of special libsnark and packing imports - if import.source.starts_with("LIBSNARK") { - #[cfg(feature = "libsnark")] - { - use helpers::LibsnarkGadgetHelper; - use libsnark::{get_ethsha256_constraints, get_sha256_constraints}; - use serde_json::from_str; - use standard::{DirectiveR1CS, R1CS}; - use std::io::BufReader; + #[cfg(feature = "libsnark")] + { + if import.source.starts_with("LIBSNARK") { + { + use helpers::LibsnarkGadgetHelper; + use libsnark::{get_ethsha256_constraints, get_sha256_constraints}; + use serde_json::from_str; + use standard::{DirectiveR1CS, R1CS}; + use std::io::BufReader; - match import.source.as_ref() { - "LIBSNARK/sha256" => { - let r1cs: R1CS = from_str(&get_ethsha256_constraints()).unwrap(); - let dr1cs: DirectiveR1CS = DirectiveR1CS { - r1cs, - directive: LibsnarkGadgetHelper::Sha256Ethereum, - }; - let compiled = FlatProg::from(dr1cs); - let alias = match import.alias { - Some(ref alias) => alias.clone(), - None => String::from("sha256"), - }; - origins.push(CompiledImport::new(compiled, alias)); - } - "LIBSNARK/sha256compression" => { - let r1cs: R1CS = from_str(&get_sha256_constraints()).unwrap(); - let dr1cs: DirectiveR1CS = DirectiveR1CS { - r1cs, - directive: LibsnarkGadgetHelper::Sha256Compress, - }; - let compiled = FlatProg::from(dr1cs); - let alias = match import.alias { - Some(ref alias) => alias.clone(), - None => String::from("sha256compression"), - }; - origins.push(CompiledImport::new(compiled, alias)); - } - "LIBSNARK/sha256packed" => { - let source = sha_packed_typed(); - let mut reader = BufReader::new(source.as_bytes()); - let compiled = compile_aux( - &mut reader, - None::, - None::< - fn(&Option, &String) -> Result<(S, String, String), E>, - >, - )?; - let alias = match import.alias { - Some(ref alias) => alias.clone(), - None => String::from("sha256packed"), - }; - origins.push(CompiledImport::new(compiled, alias)); - } - s => { - return Err(CompileError::ImportError(Error::new(format!( - "Gadget {} not found", - s - )))); + match import.source.as_ref() { + "LIBSNARK/sha256" => { + let r1cs: R1CS = from_str(&get_ethsha256_constraints()).unwrap(); + let dr1cs: DirectiveR1CS = DirectiveR1CS { + r1cs, + directive: LibsnarkGadgetHelper::Sha256Ethereum, + }; + let compiled = FlatProg::from(dr1cs); + let alias = match import.alias { + Some(ref alias) => alias.clone(), + None => String::from("sha256"), + }; + origins.push(CompiledImport::new(compiled, alias)); + } + "LIBSNARK/sha256compression" => { + let r1cs: R1CS = from_str(&get_sha256_constraints()).unwrap(); + let dr1cs: DirectiveR1CS = DirectiveR1CS { + r1cs, + directive: LibsnarkGadgetHelper::Sha256Compress, + }; + let compiled = FlatProg::from(dr1cs); + let alias = match import.alias { + Some(ref alias) => alias.clone(), + None => String::from("sha256compression"), + }; + origins.push(CompiledImport::new(compiled, alias)); + } + "LIBSNARK/sha256packed" => { + let source = sha_packed_typed(); + let mut reader = BufReader::new(source.as_bytes()); + let compiled = compile_aux( + &mut reader, + None::, + None::< + fn( + &Option, + &String, + ) + -> Result<(S, String, String), E>, + >, + )?; + let alias = match import.alias { + Some(ref alias) => alias.clone(), + None => String::from("sha256packed"), + }; + origins.push(CompiledImport::new(compiled, alias)); + } + s => { + return Err(CompileErrorInner::ImportError( + Error::new(format!("Gadget {} not found", s)) + .with_pos(Some(pos)), + ) + .with_context(&location) + .into()); + } } } } - } else if import.source.starts_with("PACKING") { + } + if import.source.starts_with("PACKING") { use types::conversions::{pack, unpack}; match import.source.as_ref() { @@ -204,10 +229,12 @@ impl Importer { origins.push(CompiledImport::new(compiled, alias)); } s => { - return Err(CompileError::ImportError(Error::new(format!( - "Packing helper {} not found", - s - )))); + return Err(CompileErrorInner::ImportError( + Error::new(format!("Packing helper {} not found", s)) + .with_pos(Some(pos)), + ) + .with_context(&location) + .into()); } } } else { @@ -215,18 +242,28 @@ impl Importer { match resolve_option { Some(resolve) => match resolve(&location, &import.source) { Ok((mut reader, location, auto_alias)) => { - let compiled = - compile_aux(&mut reader, Some(location), resolve_option)?; + let compiled = compile_aux(&mut reader, Some(location), resolve_option) + .map_err(|e| e.with_context(Some(import.source.clone())))?; let alias = match import.alias { Some(ref alias) => alias.clone(), None => auto_alias, }; origins.push(CompiledImport::new(compiled, alias)); } - Err(err) => return Err(CompileError::ImportError(err.into())), + Err(err) => { + return Err(CompileErrorInner::ImportError( + err.into().with_pos(Some(pos)), + ) + .with_context(&location) + .into()); + } }, None => { - return Err(Error::new("Can't resolve import without a resolver").into()); + return Err(CompileErrorInner::from(Error::new( + "Can't resolve import without a resolver", + )) + .with_context(&location) + .into()); } } } diff --git a/zokrates_core/src/parser/error.rs b/zokrates_core/src/parser/error.rs index 99c3d19c..cc3064a3 100644 --- a/zokrates_core/src/parser/error.rs +++ b/zokrates_core/src/parser/error.rs @@ -14,7 +14,7 @@ impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, - "Error at {}: Expected one of {:?}, got {:?}", + "{}\n\tExpected one of {:?}, got {:?}", self.pos.col(-(self.got.to_string().len() as isize)), self.expected, self.got diff --git a/zokrates_core/src/parser/parse/expression.rs b/zokrates_core/src/parser/parse/expression.rs index f9e53695..beaa333f 100644 --- a/zokrates_core/src/parser/parse/expression.rs +++ b/zokrates_core/src/parser/parse/expression.rs @@ -334,14 +334,18 @@ pub fn parse_term1( match next_token::(&input, &pos) { (Token::Mult, s1, p1) => match parse_term(&s1, &p1) { Ok((e, s2, p2)) => Ok(( - Node::new(pos, p2, Expression::Mult(box expr, box e)), + Node::new(expr.start, p2, Expression::Mult(box expr, box e)), s2, p2, )), Err(err) => Err(err), }, (Token::Div, s1, p1) => match parse_term(&s1, &p1) { - Ok((e, s2, p2)) => Ok((Node::new(pos, p2, Expression::Div(box expr, box e)), s2, p2)), + Ok((e, s2, p2)) => Ok(( + Node::new(expr.start, p2, Expression::Div(box expr, box e)), + s2, + p2, + )), Err(err) => Err(err), }, _ => Ok((expr, input, pos)), @@ -400,6 +404,12 @@ pub fn parse_function_call( input: String, pos: Position, ) -> Result<(ExpressionNode, String, Position), Error> { + // backtrack to the beginning of the function identifier, plus one because we're after the `(` + let start_pos = Position { + col: pos.col - ide.len() - 1, + ..pos + }; + // function call can have 0 .. n args let mut args = Vec::new(); let mut s: String = input; @@ -410,7 +420,7 @@ pub fn parse_function_call( // no arguments (Token::Close, s1, p1) => { return parse_term1( - Node::new(pos, p1, Expression::FunctionCall(ide, args)), + Node::new(start_pos, p1, Expression::FunctionCall(ide, args)), s1, p1, ); @@ -426,7 +436,7 @@ pub fn parse_function_call( } (Token::Close, s2, p2) => { return parse_term1( - Node::new(pos, p2, Expression::FunctionCall(ide, args)), + Node::new(start_pos, p2, Expression::FunctionCall(ide, args)), s2, p2, ); @@ -507,10 +517,11 @@ pub fn parse_array_select( input: String, pos: Position, ) -> Result<(ExpressionNode, String, Position), Error> { - let ide_initial_pos = Position { - col: pos.col - ide.len(), + let start_pos = Position { + col: pos.col - ide.len() - 1, ..pos }; + // array select can have exactly one arg match next_token::(&input, &pos) { (_, _, _) => match parse_expr(&input, &pos) { @@ -520,7 +531,7 @@ pub fn parse_array_select( pos, p2, Expression::Select( - box Node::new(pos, p1, Expression::Identifier(ide)), + box Node::new(start_pos, p1, Expression::Identifier(ide)), box e1, ), ), @@ -594,11 +605,13 @@ mod tests { let string = String::from("1 + 2 + 3"); let expr = Expression::Add( box Expression::Add( - box Expression::Number(FieldPrime::from(1)), - box Expression::Number(FieldPrime::from(2)), - ), - box Expression::Number(FieldPrime::from(3)), - ); + box Expression::Number(FieldPrime::from(1)).into(), + box Expression::Number(FieldPrime::from(2)).into(), + ) + .into(), + box Expression::Number(FieldPrime::from(3)).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expr(&string, &pos) @@ -611,11 +624,13 @@ mod tests { let string = String::from("1 - 2 - 3"); let expr = Expression::Sub( box Expression::Sub( - box Expression::Number(FieldPrime::from(1)), - box Expression::Number(FieldPrime::from(2)), - ), - box Expression::Number(FieldPrime::from(3)), - ); + box Expression::Number(FieldPrime::from(1)).into(), + box Expression::Number(FieldPrime::from(2)).into(), + ) + .into(), + box Expression::Number(FieldPrime::from(3)).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expr(&string, &pos) @@ -627,12 +642,14 @@ mod tests { let pos = Position { line: 45, col: 121 }; let string = String::from("1 - f(a)"); let expr = Expression::Sub( - box Expression::Number(FieldPrime::from(1)), + box Expression::Number(FieldPrime::from(1)).into(), box Expression::FunctionCall( String::from("f"), - vec![Expression::Identifier(String::from("a"))], - ), - ); + vec![Expression::Identifier(String::from("a")).into()], + ) + .into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expr(&string, &pos) @@ -645,11 +662,13 @@ mod tests { let string = String::from("1 - f() - 3"); let expr = Expression::Sub( box Expression::Sub( - box Expression::Number(FieldPrime::from(1)), - box Expression::FunctionCall(String::from("f"), vec![]), - ), - box Expression::Number(FieldPrime::from(3)), - ); + box Expression::Number(FieldPrime::from(1)).into(), + box Expression::FunctionCall(String::from("f"), vec![]).into(), + ) + .into(), + box Expression::Number(FieldPrime::from(3)).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expr(&string, &pos) @@ -662,11 +681,13 @@ mod tests { let string = String::from("1 + f() + 3"); let expr = Expression::Add( box Expression::Add( - box Expression::Number(FieldPrime::from(1)), - box Expression::FunctionCall(String::from("f"), vec![]), - ), - box Expression::Number(FieldPrime::from(3)), - ); + box Expression::Number(FieldPrime::from(1)).into(), + box Expression::FunctionCall(String::from("f"), vec![]).into(), + ) + .into(), + box Expression::Number(FieldPrime::from(3)).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expr(&string, &pos) @@ -679,14 +700,17 @@ mod tests { let string = String::from("1 - f[2] - 3"); let expr = Expression::Sub( box Expression::Sub( - box Expression::Number(FieldPrime::from(1)), + box Expression::Number(FieldPrime::from(1)).into(), box Expression::Select( - box Expression::Identifier(String::from("f")), - box Expression::Number(FieldPrime::from(2)), - ), - ), - box Expression::Number(FieldPrime::from(3)), - ); + box Expression::Identifier(String::from("f")).into(), + box Expression::Number(FieldPrime::from(2)).into(), + ) + .into(), + ) + .into(), + box Expression::Number(FieldPrime::from(3)).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expr(&string, &pos) @@ -699,14 +723,17 @@ mod tests { let string = String::from("1 + f[2] + 3"); let expr = Expression::Add( box Expression::Add( - box Expression::Number(FieldPrime::from(1)), + box Expression::Number(FieldPrime::from(1)).into(), box Expression::Select( - box Expression::Identifier(String::from("f")), - box Expression::Number(FieldPrime::from(2)), - ), - ), - box Expression::Number(FieldPrime::from(3)), - ); + box Expression::Identifier(String::from("f")).into(), + box Expression::Number(FieldPrime::from(2)).into(), + ) + .into(), + ) + .into(), + box Expression::Number(FieldPrime::from(3)).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expr(&string, &pos) @@ -719,11 +746,13 @@ mod tests { let string = String::from("1 - f - 3"); let expr = Expression::Sub( box Expression::Sub( - box Expression::Number(FieldPrime::from(1)), - box Expression::Identifier(String::from("f")), - ), - box Expression::Number(FieldPrime::from(3)), - ); + box Expression::Number(FieldPrime::from(1)).into(), + box Expression::Identifier(String::from("f")).into(), + ) + .into(), + box Expression::Number(FieldPrime::from(3)).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expr(&string, &pos) @@ -736,11 +765,13 @@ mod tests { let string = String::from("1 + f + 3"); let expr = Expression::Add( box Expression::Add( - box Expression::Number(FieldPrime::from(1)), - box Expression::Identifier(String::from("f")), - ), - box Expression::Number(FieldPrime::from(3)), - ); + box Expression::Number(FieldPrime::from(1)).into(), + box Expression::Identifier(String::from("f")).into(), + ) + .into(), + box Expression::Number(FieldPrime::from(3)).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expr(&string, &pos) @@ -754,12 +785,14 @@ mod tests { let string = String::from("if a < b then c else d fi"); let expr = Expression::IfElse::( box Expression::Lt( - box Expression::Identifier(String::from("a")), - box Expression::Identifier(String::from("b")), - ), - box Expression::Identifier(String::from("c")), - box Expression::Identifier(String::from("d")), - ); + box Expression::Identifier(String::from("a")).into(), + box Expression::Identifier(String::from("b")).into(), + ) + .into(), + box Expression::Identifier(String::from("c")).into(), + box Expression::Identifier(String::from("d")).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_if_then_else(&string, &pos) @@ -774,26 +807,33 @@ mod tests { let expr = Expression::IfElse::( box Expression::And( box Expression::Lt( - box Expression::Identifier(String::from("a")), - box Expression::Identifier(String::from("b")), - ), + box Expression::Identifier(String::from("a")).into(), + box Expression::Identifier(String::from("b")).into(), + ) + .into(), box Expression::And( box Expression::Gt( box Expression::Mult( - box Expression::Number(FieldPrime::from(2)), - box Expression::Identifier(String::from("a")), - ), - box Expression::Identifier(String::from("b")), - ), + box Expression::Number(FieldPrime::from(2)).into(), + box Expression::Identifier(String::from("a")).into(), + ) + .into(), + box Expression::Identifier(String::from("b")).into(), + ) + .into(), box Expression::Gt( - box Expression::Identifier(String::from("b")), - box Expression::Identifier(String::from("a")), - ), - ), - ), - box Expression::Identifier(String::from("c")), - box Expression::Identifier(String::from("d")), - ); + box Expression::Identifier(String::from("b")).into(), + box Expression::Identifier(String::from("a")).into(), + ) + .into(), + ) + .into(), + ) + .into(), + box Expression::Identifier(String::from("c")).into(), + box Expression::Identifier(String::from("d")).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), @@ -809,12 +849,14 @@ mod tests { let pos = Position { line: 45, col: 121 }; let string = String::from("foo[42 + 33]"); let expr = Expression::Select::( - box Expression::Identifier(String::from("foo")), + box Expression::Identifier(String::from("foo")).into(), box Expression::Add( - box Expression::Number(FieldPrime::from(42)), - box Expression::Number(FieldPrime::from(33)), - ), - ); + box Expression::Number(FieldPrime::from(42)).into(), + box Expression::Number(FieldPrime::from(33)).into(), + ) + .into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expr(&string, &pos) @@ -843,20 +885,25 @@ mod tests { let expr = Expression::IfElse::( box Expression::Or( box Expression::Lt( - box Expression::Identifier(String::from("a")), - box Expression::Identifier(String::from("b")), - ), + box Expression::Identifier(String::from("a")).into(), + box Expression::Identifier(String::from("b")).into(), + ) + .into(), box Expression::Gt( box Expression::Mult( - box Expression::Number(FieldPrime::from(2)), - box Expression::Identifier(String::from("a")), - ), - box Expression::Identifier(String::from("b")), - ), - ), - box Expression::Identifier(String::from("c")), - box Expression::Identifier(String::from("d")), - ); + box Expression::Number(FieldPrime::from(2)).into(), + box Expression::Identifier(String::from("a")).into(), + ) + .into(), + box Expression::Identifier(String::from("b")).into(), + ) + .into(), + ) + .into(), + box Expression::Identifier(String::from("c")).into(), + box Expression::Identifier(String::from("d")).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_if_then_else(&string, &pos) @@ -870,20 +917,25 @@ mod tests { let string = String::from("2 == 3 || 4 == 5 && 6 == 7"); let expr = Or::( box Eq( - box Number(FieldPrime::from(2)), - box Number(FieldPrime::from(3)), - ), + box Number(FieldPrime::from(2)).into(), + box Number(FieldPrime::from(3)).into(), + ) + .into(), box And( box Eq( - box Number(FieldPrime::from(4)), - box Number(FieldPrime::from(5)), - ), + box Number(FieldPrime::from(4)).into(), + box Number(FieldPrime::from(5)).into(), + ) + .into(), box Eq( - box Number(FieldPrime::from(6)), - box Number(FieldPrime::from(7)), - ), - ), - ); + box Number(FieldPrime::from(6)).into(), + box Number(FieldPrime::from(7)).into(), + ) + .into(), + ) + .into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_bexpr(&string, &pos) @@ -899,33 +951,43 @@ mod tests { box And( box Eq( box Add( - box Identifier(String::from("a")), - box Number(FieldPrime::from(2)), - ), - box Number(FieldPrime::from(3)), - ), + box Identifier(String::from("a")).into(), + box Number(FieldPrime::from(2)).into(), + ) + .into(), + box Number(FieldPrime::from(3)).into(), + ) + .into(), box Or( box Eq( box Add( box Mult( - box Identifier(String::from("a")), - box Number(FieldPrime::from(2)), - ), - box Number(FieldPrime::from(3)), - ), - box Number(FieldPrime::from(2)), - ), + box Identifier(String::from("a")).into(), + box Number(FieldPrime::from(2)).into(), + ) + .into(), + box Number(FieldPrime::from(3)).into(), + ) + .into(), + box Number(FieldPrime::from(2)).into(), + ) + .into(), box Lt( - box Identifier(String::from("a")), - box Number(FieldPrime::from(3)), - ), - ), - ), + box Identifier(String::from("a")).into(), + box Number(FieldPrime::from(3)).into(), + ) + .into(), + ) + .into(), + ) + .into(), box Lt( - box Number(FieldPrime::from(1)), - box Number(FieldPrime::from(2)), - ), - ); + box Number(FieldPrime::from(1)).into(), + box Number(FieldPrime::from(2)).into(), + ) + .into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_bexpr(&string, &pos) @@ -940,12 +1002,14 @@ mod tests { let string = String::from("if a < b then c else d fi"); let expr = Expression::IfElse::( box Expression::Lt( - box Expression::Identifier(String::from("a")), - box Expression::Identifier(String::from("b")), - ), - box Expression::Identifier(String::from("c")), - box Expression::Identifier(String::from("d")), - ); + box Expression::Identifier(String::from("a")).into(), + box Expression::Identifier(String::from("b")).into(), + ) + .into(), + box Expression::Identifier(String::from("c")).into(), + box Expression::Identifier(String::from("d")).into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_factor(&string, &pos) @@ -956,12 +1020,14 @@ mod tests { let pos = Position { line: 45, col: 121 }; let string = String::from("(5 + a * 6)"); let expr = Expression::Add( - box Expression::Number(FieldPrime::from(5)), + box Expression::Number(FieldPrime::from(5)).into(), box Expression::Mult( - box Expression::Identifier(String::from("a")), - box Expression::Number(FieldPrime::from(6)), - ), - ); + box Expression::Identifier(String::from("a")).into(), + box Expression::Number(FieldPrime::from(6)).into(), + ) + .into(), + ) + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_factor(&string, &pos) @@ -971,7 +1037,7 @@ mod tests { fn ide() { let pos = Position { line: 45, col: 121 }; let string = String::from("a"); - let expr = Expression::Identifier::(String::from("a")); + let expr = Expression::Identifier::(String::from("a")).into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_factor(&string, &pos) @@ -981,7 +1047,7 @@ mod tests { fn num() { let pos = Position { line: 45, col: 121 }; let string = String::from("234"); - let expr = Expression::Number(FieldPrime::from(234)); + let expr = Expression::Number(FieldPrime::from(234)).into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_factor(&string, &pos) diff --git a/zokrates_core/src/parser/parse/expression_list.rs b/zokrates_core/src/parser/parse/expression_list.rs index 75da319d..d127a8d6 100644 --- a/zokrates_core/src/parser/parse/expression_list.rs +++ b/zokrates_core/src/parser/parse/expression_list.rs @@ -44,8 +44,8 @@ mod tests { fn parse_comma_separated_list( input: String, pos: Position, - ) -> Result<(ExpressionList, String, Position), Error> { - let mut res = ExpressionList::new(); + ) -> Result<(ExpressionListNode, String, Position), Error> { + let mut res = ExpressionList::new().into(); parse_comma_separated_expression_list_rec(input, pos, &mut res) } @@ -55,10 +55,11 @@ mod tests { let string = String::from("b, c"); let expr = ExpressionList:: { expressions: vec![ - Expression::Identifier(String::from("b")), - Expression::Identifier(String::from("c")), + Expression::Identifier(String::from("b")).into(), + Expression::Identifier(String::from("c")).into(), ], - }; + } + .into(); assert_eq!( Ok((expr, String::from(""), pos.col(string.len() as isize))), parse_expression_list(string, pos) @@ -70,8 +71,9 @@ mod tests { let pos = Position { line: 45, col: 121 }; let string = String::from("a"); let exprs = ExpressionList { - expressions: vec![Expression::Identifier(String::from("a"))], - }; + expressions: vec![Expression::Identifier(String::from("a")).into()], + } + .into(); assert_eq!( Ok((exprs, String::from(""), pos.col(string.len() as isize))), parse_comma_separated_list::(string, pos) @@ -84,11 +86,12 @@ mod tests { let string = String::from("a, b, c"); let exprs = ExpressionList { expressions: vec![ - Expression::Identifier(String::from("a")), - Expression::Identifier(String::from("b")), - Expression::Identifier(String::from("c")), + Expression::Identifier(String::from("a")).into(), + Expression::Identifier(String::from("b")).into(), + Expression::Identifier(String::from("c")).into(), ], - }; + } + .into(); assert_eq!( Ok((exprs, String::from(""), pos.col(string.len() as isize))), parse_comma_separated_list::(string, pos) diff --git a/zokrates_core/src/parser/parse/function.rs b/zokrates_core/src/parser/parse/function.rs index 6bae8c78..42b40e86 100644 --- a/zokrates_core/src/parser/parse/function.rs +++ b/zokrates_core/src/parser/parse/function.rs @@ -8,7 +8,9 @@ use parser::Error; use super::statement::parse_statement; -use absy::{Function, Parameter, Statement, Variable}; +use absy::{ + Function, FunctionNode, Node, Parameter, ParameterNode, Statement, Variable, VariableNode, +}; use types::{Signature, Type}; fn parse_function_identifier( @@ -28,7 +30,7 @@ fn parse_function_identifier( fn parse_function_header( input: &String, pos: &Position, -) -> Result<(String, Vec, Signature), Error> { +) -> Result<(String, Vec, Signature), Error> { // parse function identifier let (id, s, p) = parse_function_identifier(input, pos)?; @@ -90,7 +92,7 @@ fn parse_function_header( }?; let sig = Signature { - inputs: args.iter().map(|a| a.id.get_type()).collect(), + inputs: args.iter().map(|a| a.value.id.value.get_type()).collect(), outputs: return_types, }; @@ -119,13 +121,13 @@ fn parse_function_header( fn parse_function_argument_variable( input: &String, pos: &Position, -) -> Result<(Variable, String, Position), Error> { +) -> Result<(VariableNode, String, Position), Error> { let s4 = input; let p4 = pos; match next_token::(&s4, &p4) { (Token::Type(t), s5, p5) => match next_token(&s5, &p5) { - (Token::Ide(x), s6, p6) => Ok((Variable::new(x, t), s6, p6)), + (Token::Ide(x), s6, p6) => Ok((Node::new(*pos, p6, Variable::new(x, t)), s6, p6)), (t6, _, p6) => Err(Error { expected: vec![Token::Ide(String::from("identifier"))], got: t6, @@ -143,7 +145,7 @@ fn parse_function_argument_variable( fn parse_function_arguments( input: String, pos: Position, -) -> Result<(Vec, String, Position), Error> { +) -> Result<(Vec, String, Position), Error> { let mut args = Vec::new(); let mut s = input; let mut p = pos; @@ -152,10 +154,7 @@ fn parse_function_arguments( match next_token(&s, &p) { (Token::Private, s1, p1) => { let (var, s2, p2) = parse_function_argument_variable::(&s1, &p1)?; - args.push(Parameter { - id: var, - private: true, - }); + args.push(Node::new(p, p1, Parameter::private(var))); match next_token::(&s2, &p2) { (Token::Comma, s3, p3) => { s = s3; @@ -173,10 +172,7 @@ fn parse_function_arguments( } (Token::Type(_), _, _) => { let (var, s2, p2) = parse_function_argument_variable::(&s, &p)?; - args.push(Parameter { - id: var, - private: false, - }); + args.push(Node::new(p, p2, Parameter::public(var))); match next_token::(&s2, &p2) { (Token::Comma, s3, p3) => { s = s3; @@ -255,7 +251,7 @@ pub fn parse_function( mut lines: &mut Lines, input: &String, pos: &Position, -) -> Result<(Function, Position), Error> { +) -> Result<(FunctionNode, Position), Error> { let mut current_line = pos.line; let (id, args, sig) = parse_function_header(input, pos)?; @@ -279,7 +275,7 @@ pub fn parse_function( for stat in statements { stats.push(stat.clone()); } - match statements[0] { + match statements[0].value { Statement::Return(_) => { break; } @@ -296,22 +292,27 @@ pub fn parse_function( current_line += 1; } - match stats.last() { - Some(&Statement::Return(_)) => {} - Some(x) => panic!("Last function statement not Return: {}", x), - None => panic!("Error while checking last function statement"), + match stats.last().clone().unwrap().value { + Statement::Return(_) => {} + ref x => panic!("Last function statement not Return: {}", x), } + let next_pos = Position { + line: current_line, + col: 1, + }; + Ok(( - Function { - id: id, - arguments: args, - statements: stats, - signature: sig, - }, - Position { - line: current_line, - col: 1, - }, + Node::new( + *pos, + next_pos, + Function { + id: id, + arguments: args, + statements: stats, + signature: sig, + }, + ), + next_pos, )) } diff --git a/zokrates_core/src/parser/parse/import.rs b/zokrates_core/src/parser/parse/import.rs index 1b109601..352aab2a 100644 --- a/zokrates_core/src/parser/parse/import.rs +++ b/zokrates_core/src/parser/parse/import.rs @@ -5,18 +5,22 @@ use parser::Error; use parser::tokenize::parse_quoted_path; -use imports::Import; +use absy::Node; +use imports::{Import, ImportNode}; pub fn parse_import( input: &String, pos: &Position, -) -> Result<(Import, Position), Error> { +) -> Result<(ImportNode, Position), Error> { match next_token(input, pos) { (Token::DoubleQuote, s1, p1) => match parse_quoted_path(&s1, &p1) { (Token::Path(code_path), s2, p2) => match next_token::(&s2, &p2) { (Token::As, s3, p3) => match next_token(&s3, &p3) { (Token::Ide(id), _, p4) => { - return Ok((Import::new_with_alias(code_path, &id), p4)); + return Ok(( + Node::new(*pos, p4, Import::new_with_alias(code_path, &id)), + p4, + )); } (t4, _, p4) => { return Err(Error { @@ -26,7 +30,9 @@ pub fn parse_import( }); } }, - (Token::Unknown(_), _, p3) => return Ok((Import::new(code_path), p3)), + (Token::Unknown(_), _, p3) => { + return Ok((Node::new(*pos, p3, Import::new(code_path)), p3)); + } (t3, _, p3) => { return Err(Error { expected: vec![ @@ -83,7 +89,7 @@ mod tests { fn parse_import_test() { let pos = Position { line: 45, col: 121 }; let string = String::from("\"./foo.code\""); - let import = Import::new("./foo.code".to_string()); + let import = Import::new("./foo.code".to_string()).into(); let position = Position { line: 45, col: pos.col + 1 + "./foo.code".len() + 1, @@ -99,7 +105,7 @@ mod tests { let pos = Position { line: 45, col: 121 }; let string = String::from("\"./foo.code\" as myalias"); let alias = "myalias".to_string(); - let import = Import::new_with_alias("./foo.code".to_string(), &alias); + let import = Import::new_with_alias("./foo.code".to_string(), &alias).into(); let position = Position { line: 45, col: pos.col + string.len(), diff --git a/zokrates_core/src/parser/parse/statement.rs b/zokrates_core/src/parser/parse/statement.rs index dd3f8035..ba09d8aa 100644 --- a/zokrates_core/src/parser/parse/statement.rs +++ b/zokrates_core/src/parser/parse/statement.rs @@ -13,14 +13,16 @@ use super::expression::{ }; use super::expression_list::parse_expression_list; -use absy::{Assignee, AssigneeNode, Expression, Node, Statement, Variable, VariableNode}; +use absy::{ + Assignee, AssigneeNode, Expression, Node, Statement, StatementNode, Variable, VariableNode, +}; use types::Type; pub fn parse_statement( lines: &mut Lines, input: &String, pos: &Position, -) -> Result<(Vec>, String, Position), Error> { +) -> Result<(Vec>, String, Position), Error> { match next_token::(input, pos) { (Token::Type(t), s1, p1) => parse_declaration_definition(t, s1, p1), (Token::Ide(x1), s1, p1) => parse_statement1(x1, s1, p1), @@ -30,11 +32,19 @@ pub fn parse_statement( Ok((e4, s4, p4)) => match next_token(&s4, &p4) { (Token::InlineComment(_), ref s5, _) => { assert_eq!(s5, ""); - Ok((vec![Statement::Condition(e2, e4)], s4, p4)) + Ok(( + vec![Node::new(*pos, p4, Statement::Condition(e2, e4))], + s4, + p4, + )) } (Token::Unknown(ref t5), ref s5, _) if t5 == "" => { assert_eq!(s5, ""); - Ok((vec![Statement::Condition(e2, e4)], s4, p4)) + Ok(( + vec![Node::new(*pos, p4, Statement::Condition(e2, e4))], + s4, + p4, + )) } (t5, _, p5) => Err(Error { expected: vec![Token::Unknown("".to_string())], @@ -109,11 +119,11 @@ pub fn parse_statement( match next_token(&s8, &p8) { (Token::InlineComment(_), ref s9, _) => { assert_eq!(s9, ""); - return Ok((vec![Statement::For(Node::new(p1, p3, Variable::new(x2, t)), x4, x6, statements)], s8, p8)) + return Ok((vec![Node::new(*pos, p8, Statement::For(Node::new(p1, p3, Variable::new(x2, t)), x4, x6, statements))], s8, p8)) } (Token::Unknown(ref t9), ref s9, _) if t9 == "" => { assert_eq!(s9, ""); - return Ok((vec![Statement::For(Node::new(p1, p3, Variable::new(x2, t)), x4, x6, statements)], s8, p8)) + return Ok((vec![Node::new(*pos, p8, Statement::For(Node::new(p1, p3, Variable::new(x2, t)), x4, x6, statements))], s8, p8)) }, (t9, _, p9) => return Err(Error { expected: vec![Token::Unknown("".to_string())], got: t9 , pos: p9 }), } @@ -184,11 +194,11 @@ pub fn parse_statement( Ok((e2, s2, p2)) => match next_token(&s2, &p2) { (Token::InlineComment(_), ref s3, _) => { assert_eq!(s3, ""); - Ok((vec![Statement::Return(e2)], s2, p2)) + Ok((vec![Node::new(*pos, p2, Statement::Return(e2))], s2, p2)) } (Token::Unknown(ref t3), ref s3, _) if t3 == "" => { assert_eq!(s3, ""); - Ok((vec![Statement::Return(e2)], s2, p2)) + Ok((vec![Node::new(*pos, p2, Statement::Return(e2))], s2, p2)) } (t3, _, p3) => Err(Error { expected: vec![Token::Unknown("".to_string())], @@ -221,22 +231,27 @@ fn parse_definition1( x: AssigneeNode, input: String, pos: Position, -) -> Result<(Vec>, String, Position), Error> { +) -> Result<(Vec>, String, Position), Error> { match parse_expr(&input, &pos) { Ok((e1, s1, p1)) => match next_token(&s1, &p1) { (Token::InlineComment(_), ref s2, _) => { assert_eq!(s2, ""); match e1.value { e @ Expression::FunctionCall(..) => Ok(( - vec![Statement::MultipleDefinition( - vec![x], - Node::new(pos, p1, e), + vec![Node::new( + x.start, + p1, + Statement::MultipleDefinition(vec![x], Node::new(pos, p1, e)), )], s1, p1, )), e => Ok(( - vec![Statement::Definition(x, Node::new(pos, p1, e))], + vec![Node::new( + x.start, + p1, + Statement::Definition(x, Node::new(pos, p1, e)), + )], s1, p1, )), @@ -246,15 +261,20 @@ fn parse_definition1( assert_eq!(s2, ""); match e1.value { e @ Expression::FunctionCall(..) => Ok(( - vec![Statement::MultipleDefinition( - vec![x], - Node::new(pos, p1, e), + vec![Node::new( + x.start, + p1, + Statement::MultipleDefinition(vec![x], Node::new(pos, p1, e)), )], s1, p1, )), e => Ok(( - vec![Statement::Definition(x, Node::new(pos, p1, e))], + vec![Node::new( + x.start, + p1, + Statement::Definition(x, Node::new(pos, p1, e)), + )], s1, p1, )), @@ -274,7 +294,7 @@ fn parse_declaration_definition( t: Type, input: String, pos: Position, -) -> Result<(Vec>, String, Position), Error> { +) -> Result<(Vec>, String, Position), Error> { match next_token::(&input, &pos) { (Token::Ide(x), s0, p0) => match next_token(&s0, &p0) { (Token::Eq, s1, p1) => match parse_expr(&s1, &p1) { @@ -284,14 +304,22 @@ fn parse_declaration_definition( match e2.value { e @ Expression::FunctionCall(..) => Ok(( vec![ - Statement::Declaration(Node::new( + Node::new( pos, p0, - Variable::new(x.clone(), t), - )), - Statement::MultipleDefinition( - vec![Node::new(pos, p1, Assignee::Identifier(x))], - Node::new(p1, p2, e), + Statement::Declaration(Node::new( + pos, + p0, + Variable::new(x.clone(), t), + )), + ), + Node::new( + pos, + p2, + Statement::MultipleDefinition( + vec![Node::new(pos, p1, Assignee::Identifier(x))], + Node::new(p1, p2, e), + ), ), ], s2, @@ -299,14 +327,22 @@ fn parse_declaration_definition( )), e => Ok(( vec![ - Statement::Declaration(Node::new( + Node::new( pos, p0, - Variable::new(x.clone(), t), - )), - Statement::Definition( - Node::new(pos, p1, Assignee::Identifier(x)), - Node::new(p1, p2, e), + Statement::Declaration(Node::new( + pos, + p0, + Variable::new(x.clone(), t), + )), + ), + Node::new( + pos, + p2, + Statement::Definition( + Node::new(pos, p1, Assignee::Identifier(x)), + Node::new(p1, p2, e), + ), ), ], s2, @@ -319,14 +355,22 @@ fn parse_declaration_definition( match e2.value { e @ Expression::FunctionCall(..) => Ok(( vec![ - Statement::Declaration(Node::new( + Node::new( pos, p0, - Variable::new(x.clone(), t), - )), - Statement::MultipleDefinition( - vec![Node::new(pos, p1, Assignee::Identifier(x))], - Node::new(p1, p2, e), + Statement::Declaration(Node::new( + pos, + p0, + Variable::new(x.clone(), t), + )), + ), + Node::new( + pos, + p2, + Statement::MultipleDefinition( + vec![Node::new(pos, p1, Assignee::Identifier(x))], + Node::new(p1, p2, e), + ), ), ], s2, @@ -334,14 +378,22 @@ fn parse_declaration_definition( )), e => Ok(( vec![ - Statement::Declaration(Node::new( + Node::new( pos, p0, - Variable::new(x.clone(), t), - )), - Statement::Definition( - Node::new(pos, p1, Assignee::Identifier(x)), - Node::new(p1, p2, e), + Statement::Declaration(Node::new( + pos, + p0, + Variable::new(x.clone(), t), + )), + ), + Node::new( + pos, + p2, + Statement::Definition( + Node::new(pos, p1, Assignee::Identifier(x)), + Node::new(p1, p2, e), + ), ), ], s2, @@ -370,21 +422,16 @@ fn parse_declaration_definition( // then we should have an equal sign (Token::Eq, s3, p3) => match parse_expr(&s3, &p3) { Ok((e4, s4, p4)) => { - let mut statements: Vec> = d2 + let mut statements: Vec<_> = d2 .iter() - .map(|v| Statement::Declaration(v.clone())) + .map(|v| { + Node::new(v.start, v.end, Statement::Declaration(v.clone())) + }) .collect(); - statements.push(Statement::MultipleDefinition( - d2.iter() - .map(|v| { - Node::new( - v.start, - v.end, - Assignee::Identifier(v.value.id.clone()), - ) - }) - .collect(), - e4, + statements.push(Node::new( + pos, + p4, + Statement::MultipleDefinition(e2, e4), )); Ok((statements, s4, p4)) // output a multipledefinition with the destructure and the expression } @@ -417,9 +464,9 @@ fn parse_statement1( ide: String, input: String, pos: Position, -) -> Result<(Vec>, String, Position), Error> { +) -> Result<(Vec>, String, Position), Error> { let ide_start_position = Position { - line: pos.line - ide.len(), + col: pos.col - ide.len(), ..pos }; match next_token::(&input, &pos) { @@ -434,22 +481,11 @@ fn parse_statement1( // then we should have an equal sign (Token::Eq, s3, p3) => match parse_expr(&s3, &p3) { Ok((e4, s4, p4)) => { - let mut statements: Vec> = d2 + let mut statements: Vec<_> = d2 .iter() - .map(|v| Statement::Declaration(v.clone())) + .map(|v| Node::new(v.start, v.end, Statement::Declaration(v.clone()))) .collect(); - statements.push(Statement::MultipleDefinition( - d2.iter() - .map(|v| { - Node::new( - v.start, - v.end, - Assignee::Identifier(v.value.id.clone()), - ) - }) - .collect(), - e4, - )); + statements.push(Node::new(pos, p4, Statement::MultipleDefinition(e2, e4))); Ok((statements, s4, p4)) // output a multipledefinition with the destructure and the expression } Err(err) => Err(err), @@ -469,11 +505,19 @@ fn parse_statement1( Ok((e6, s6, p6)) => match next_token(&s6, &p6) { (Token::InlineComment(_), ref s7, _) => { assert_eq!(s7, ""); - Ok((vec![Statement::Condition(e4, e6)], s6, p6)) + Ok(( + vec![Node::new(pos, p6, Statement::Condition(e4, e6))], + s6, + p6, + )) } (Token::Unknown(ref t7), ref s7, _) if t7 == "" => { assert_eq!(s7, ""); - Ok((vec![Statement::Condition(e4, e6)], s6, p6)) + Ok(( + vec![Node::new(pos, p6, Statement::Condition(e4, e6))], + s6, + p6, + )) } (t7, _, p7) => Err(Error { expected: vec![ @@ -507,11 +551,19 @@ fn parse_statement1( Ok((e6, s6, p6)) => match next_token(&s6, &p6) { (Token::InlineComment(_), ref s7, _) => { assert_eq!(s7, ""); - Ok((vec![Statement::Condition(e4, e6)], s6, p6)) + Ok(( + vec![Node::new(pos, p6, Statement::Condition(e4, e6))], + s6, + p6, + )) } (Token::Unknown(ref t7), ref s7, _) if t7 == "" => { assert_eq!(s7, ""); - Ok((vec![Statement::Condition(e4, e6)], s6, p6)) + Ok(( + vec![Node::new(pos, p6, Statement::Condition(e4, e6))], + s6, + p6, + )) } (t7, _, p7) => Err(Error { expected: vec![ @@ -550,11 +602,19 @@ fn parse_statement1( Ok((e5, s5, p5)) => match next_token(&s5, &p5) { (Token::InlineComment(_), ref s6, _) => { assert_eq!(s6, ""); - Ok((vec![Statement::Condition(e3, e5)], s5, p5)) + Ok(( + vec![Node::new(pos, p5, Statement::Condition(e3, e5))], + s5, + p5, + )) } (Token::Unknown(ref t6), ref s6, _) if t6 == "" => { assert_eq!(s6, ""); - Ok((vec![Statement::Condition(e3, e5)], s5, p5)) + Ok(( + vec![Node::new(pos, p5, Statement::Condition(e3, e5))], + s5, + p5, + )) } (t6, _, p6) => Err(Error { expected: vec![ @@ -590,17 +650,23 @@ pub fn parse_identifier_list1( _type: Option, input: String, pos: Position, -) -> Result<(Vec, Vec, String, Position), Error> { +) -> Result<(Vec>, Vec, String, Position), Error> { let mut res = Vec::new(); let mut decl = Vec::new(); - res.push(head.clone()); + + let start_pos = Position { + col: pos.col - head.len(), + ..pos + }; + + res.push(Node::new( + start_pos, + pos, + Assignee::Identifier(head.clone()), + )); match _type { Some(t) => { - let pos_before = Position { - col: pos.col - head.len(), - ..pos - }; - decl.push(Node::new(pos_before, pos, Variable::new(head, t))); + decl.push(Node::new(start_pos, pos, Variable::new(head, t))); } _ => {} }; @@ -610,13 +676,13 @@ pub fn parse_identifier_list1( fn parse_comma_separated_identifier_list_rec( input: String, pos: Position, - mut acc: &mut Vec, + mut acc: &mut Vec>, mut decl: &mut Vec, -) -> Result<(Vec, Vec, String, Position), Error> { +) -> Result<(Vec>, Vec, String, Position), Error> { match next_token(&input, &pos) { (Token::Type(t), s1, p1) => match next_token::(&s1, &p1) { (Token::Ide(id), s2, p2) => { - acc.push(id.clone()); + acc.push(Node::new(p1, p2, Assignee::Identifier(id.clone()))); decl.push(Node::new(pos, p2, Variable::new(id, t))); match next_token::(&s2, &p2) { (Token::Comma, s3, p3) => { @@ -632,7 +698,7 @@ fn parse_comma_separated_identifier_list_rec( }), }, (Token::Ide(id), s1, p1) => { - acc.push(id); + acc.push(Node::new(pos, p1, Assignee::Identifier(id))); match next_token::(&s1, &p1) { (Token::Comma, s2, p2) => { parse_comma_separated_identifier_list_rec(s2, p2, &mut acc, &mut decl) @@ -660,9 +726,10 @@ mod tests { let pos = Position { line: 45, col: 121 }; let string = String::from("() == 1"); let cond = Statement::Condition( - Expression::FunctionCall(String::from("foo"), vec![]), - Expression::Number(FieldPrime::from(1)), - ); + Expression::FunctionCall(String::from("foo"), vec![]).into(), + Expression::Number(FieldPrime::from(1)).into(), + ) + .into(); assert_eq!( Ok((vec![cond], String::from(""), pos.col(string.len() as isize))), parse_statement1(String::from("foo"), string, pos) @@ -676,13 +743,16 @@ mod tests { let cond = Statement::Condition( Expression::Sub( box Expression::Sub( - box Expression::FunctionCall(String::from("foo"), vec![]), - box Expression::FunctionCall(String::from("g"), vec![]), - ), - box Expression::Number(FieldPrime::from(1)), - ), - Expression::Number(FieldPrime::from(1)), - ); + box Expression::FunctionCall(String::from("foo"), vec![]).into(), + box Expression::FunctionCall(String::from("g"), vec![]).into(), + ) + .into(), + box Expression::Number(FieldPrime::from(1)).into(), + ) + .into(), + Expression::Number(FieldPrime::from(1)).into(), + ) + .into(); assert_eq!( Ok((vec![cond], String::from(""), pos.col(string.len() as isize))), parse_statement1(String::from("foo"), string, pos) @@ -697,15 +767,19 @@ mod tests { Expression::Sub( box Expression::Sub( box Expression::Select( - box Expression::Identifier(String::from("foo")), - box Expression::Number(FieldPrime::from(3)), - ), - box Expression::FunctionCall(String::from("g"), vec![]), - ), - box Expression::Number(FieldPrime::from(1)), - ), - Expression::Number(FieldPrime::from(1)), - ); + box Expression::Identifier(String::from("foo")).into(), + box Expression::Number(FieldPrime::from(3)).into(), + ) + .into(), + box Expression::FunctionCall(String::from("g"), vec![]).into(), + ) + .into(), + box Expression::Number(FieldPrime::from(1)).into(), + ) + .into(), + Expression::Number(FieldPrime::from(1)).into(), + ) + .into(); assert_eq!( Ok((vec![cond], String::from(""), pos.col(string.len() as isize))), parse_statement1(String::from("foo"), string, pos) diff --git a/zokrates_core/src/semantics.rs b/zokrates_core/src/semantics.rs index 3ffe427c..7e1e486c 100644 --- a/zokrates_core/src/semantics.rs +++ b/zokrates_core/src/semantics.rs @@ -21,35 +21,18 @@ use types::Type; use std::hash::{Hash, Hasher}; #[derive(PartialEq, Debug)] -pub struct Error(Vec); - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!( - f, - "{}", - self.0 - .iter() - .map(|x| x.to_string()) - .collect::>() - .join("\n") - ) - } -} - -#[derive(PartialEq, Debug)] -struct SingleError { +pub struct Error { pos: Option<(Position, Position)>, message: String, } -impl fmt::Display for SingleError { +impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let location = self .pos - .map(|p| format!("At {}:{} | ", p.0, p.1)) - .unwrap_or("".to_string()); - write!(f, "{}{}", location, self.message) + .map(|p| format!("{}", p.0)) + .unwrap_or("?".to_string()); + write!(f, "{}\n\t{}", location, self.message) } } @@ -152,7 +135,7 @@ impl Checker { } } - pub fn check_program(&mut self, prog: Prog) -> Result, Error> { + pub fn check_program(&mut self, prog: Prog) -> Result, Vec> { for func in &prog.imported_functions { self.functions.insert(FunctionDeclaration { id: func.id.clone(), @@ -164,18 +147,23 @@ impl Checker { let mut checked_functions = vec![]; for func in prog.functions { - match self.check_function(&func) { + self.enter_scope(); + + let dec = FunctionDeclaration { + id: func.value.id.clone(), + signature: func.value.signature.clone(), + }; + + match self.check_function(func) { Ok(checked_function) => { checked_functions.push(checked_function); } Err(e) => { - errors.push(e); + errors.extend(e); } }; - self.functions.insert(FunctionDeclaration { - id: func.id, - signature: func.signature, - }); + self.functions.insert(dec); + self.exit_scope(); } match self.check_single_main() { @@ -184,34 +172,34 @@ impl Checker { }; if errors.len() > 0 { - return Err(Error(errors)); + return Err(errors); } Ok(TypedProg { functions: checked_functions, imported_functions: prog.imported_functions, - imports: prog.imports, + imports: prog.imports.into_iter().map(|i| i.value).collect(), }) } - fn check_single_main(&mut self) -> Result<(), SingleError> { + fn check_single_main(&mut self) -> Result<(), Error> { match self.functions.iter().filter(|fun| fun.id == "main").count() { 1 => Ok(()), - 0 => Err(SingleError { + 0 => Err(Error { pos: None, message: format!("No main function found"), }), - n => Err(SingleError { + n => Err(Error { pos: None, message: format!("Only one main function allowed, found {}", n), }), } } - fn check_for_var(&self, var: &VariableNode) -> Result<(), SingleError> { + fn check_for_var(&self, var: &VariableNode) -> Result<(), Error> { match var.value.get_type() { Type::FieldElement => Ok(()), - t => Err(SingleError { + t => Err(Error { pos: Some(var.pos()), message: format!("Variable in for loop cannot have type {}", t), }), @@ -220,8 +208,12 @@ impl Checker { fn check_function( &mut self, - funct: &Function, - ) -> Result, SingleError> { + funct_node: FunctionNode, + ) -> Result, Vec> { + let mut errors = vec![]; + let pos = funct_node.pos(); + let funct = funct_node.value; + assert_eq!(funct.arguments.len(), funct.signature.inputs.len()); let query = FunctionQuery::new( @@ -240,8 +232,8 @@ impl Checker { match candidates.len() { 1 => { - return Err(SingleError { - pos: None, + errors.push(Error { + pos: Some(pos), message: format!( "Duplicate definition for function {} with signature {}", funct.id, funct.signature @@ -252,24 +244,34 @@ impl Checker { _ => panic!("duplicate function declaration should have been caught"), } - self.enter_scope(); - for arg in funct.arguments.clone() { - self.insert_scope(arg.id); + self.insert_scope(arg.value.id.value); } let mut statements_checked = vec![]; for stat in funct.statements.iter() { - let checked_stat = self.check_statement(stat, &funct.signature.outputs)?; - statements_checked.push(checked_stat); + match self.check_statement(stat, &funct.signature.outputs) { + Ok(statement) => { + statements_checked.push(statement); + } + Err(e) => { + errors.push(e); + } + } } - self.exit_scope(); + if errors.len() > 0 { + return Err(errors); + } Ok(TypedFunction { id: funct.id.clone(), - arguments: funct.arguments.clone(), + arguments: funct + .arguments + .iter() + .map(|a| a.value.clone().into()) + .collect(), statements: statements_checked, signature: funct.signature.clone(), }) @@ -277,11 +279,10 @@ impl Checker { fn check_statement( &mut self, - stat: &Statement, + stat: &StatementNode, header_return_types: &Vec, - ) -> Result, SingleError> { - let pos = None; - match stat { + ) -> Result, Error> { + match stat.value { Statement::Return(ref list) => { let mut expression_list_checked = vec![]; for e in list.value.expressions.clone() { @@ -296,23 +297,32 @@ impl Checker { match return_statement_types == *header_return_types { true => Ok(TypedStatement::Return(expression_list_checked)), - false => Err(SingleError { - pos, + false => Err(Error { + pos: Some(stat.pos()), message: format!( - "Expected {:?} in return statement, found {:?}", - header_return_types, return_statement_types + "Expected ({}) in return statement, found ({})", + header_return_types + .iter() + .map(|t| t.to_string()) + .collect::>() + .join(", "), + return_statement_types + .iter() + .map(|t| t.to_string()) + .collect::>() + .join(", ") ), }), } } Statement::Declaration(ref var) => match self.insert_scope(var.clone().value) { - true => Ok(TypedStatement::Declaration(var.clone().value)), - false => Err(SingleError { - pos, + true => Ok(TypedStatement::Declaration(var.value.clone().into())), + false => Err(Error { + pos: Some(stat.pos()), message: format!("Duplicate declaration for variable named {}", var.value.id), }), }, - Statement::Definition(assignee, expr) => { + Statement::Definition(ref assignee, ref expr) => { // we create multidef when rhs is a function call to benefit from inference // check rhs is not a function call here match expr.value { @@ -332,8 +342,8 @@ impl Checker { // make sure the assignee has the same type as the rhs match var_type == expression_type { true => Ok(TypedStatement::Definition(var, checked_expr)), - false => Err(SingleError { - pos, + false => Err(Error { + pos: Some(stat.pos()), message: format!( "Expression {} of type {} cannot be assigned to {} of type {}", expr, expression_type, assignee, var_type @@ -341,7 +351,7 @@ impl Checker { }), } } - Statement::Condition(lhs, rhs) => { + Statement::Condition(ref lhs, ref rhs) => { let checked_lhs = self.check_expression(&lhs)?; let checked_rhs = self.check_expression(&rhs)?; @@ -349,14 +359,14 @@ impl Checker { (ref r, ref l) if r.get_type() == l.get_type() => { Ok(TypedStatement::Condition(checked_lhs, checked_rhs)) } - (e1, e2) => Err(SingleError { - pos, + (e1, e2) => Err(Error { + pos: Some(stat.pos()), message: format!( - "cannot compare {} of type {:?} to {} of type {:?}", + "Cannot compare {} of type {:?} to {} of type {:?}", lhs, - rhs, e1.get_type(), - e2.get_type() + rhs, + e2.get_type(), ), }), } @@ -377,13 +387,13 @@ impl Checker { self.exit_scope(); Ok(TypedStatement::For( - var.clone().value, + var.value.clone().into(), from.clone(), to.clone(), checked_statements, )) } - Statement::MultipleDefinition(assignees, rhs) => { + Statement::MultipleDefinition(ref assignees, ref rhs) => { match rhs.value { // Right side has to be a function call Expression::FunctionCall(ref fun_id, ref arguments) => { @@ -398,7 +408,9 @@ impl Checker { Some(sv) => Some(sv.id.get_type()) })) } - ref a => Err(SingleError { pos, message: format!("Left hand side of function return assignment must be a list of identifiers, found {}", a)}) + ref a => Err(Error { + pos: Some(stat.pos()), + message: format!("Left hand side of function return assignment must be a list of identifiers, found {}", a)}) }?; vars_types.push(t); var_names.push(name); @@ -431,14 +443,16 @@ impl Checker { self.insert_scope(var); } - Ok(TypedStatement::MultipleDefinition(lhs.collect(), TypedExpressionList::FunctionCall(f.id.clone(), arguments_checked, f.signature.outputs.clone()))) + Ok(TypedStatement::MultipleDefinition(lhs.map(|v| v.into()).collect(), TypedExpressionList::FunctionCall(f.id.clone(), arguments_checked, f.signature.outputs.clone()))) }, - 0 => Err(SingleError { pos, message: format!("Function definition for function {} with signature {} not found.", fun_id, query) }), - _ => Err(SingleError { pos, message: format!("Function call for function {} with arguments {:?} is ambiguous.", fun_id, arguments_types) }), + 0 => Err(Error { pos: Some(stat.pos()), + message: format!("Function definition for function {} with signature {} not found.", fun_id, query) }), + _ => Err(Error { pos: Some(stat.pos()), + message: format!("Function call for function {} with arguments {:?} is ambiguous.", fun_id, arguments_types) }), } } - _ => Err(SingleError { - pos: None, + _ => Err(Error { + pos: Some(stat.pos()), message: format!("{} should be a FunctionCall", rhs), }), } @@ -449,12 +463,12 @@ impl Checker { fn check_assignee( &mut self, assignee: &AssigneeNode, - ) -> Result, SingleError> { + ) -> Result, Error> { // check that the assignee is declared match assignee.value { Assignee::Identifier(ref variable_name) => match self.get_scope(&variable_name) { - Some(var) => Ok(TypedAssignee::Identifier(var.id.clone())), - None => Err(SingleError { + Some(var) => Ok(TypedAssignee::Identifier(var.id.clone().into())), + None => Err(Error { pos: Some(assignee.pos()), message: format!("Undeclared variable: {:?}", variable_name), }), @@ -465,7 +479,7 @@ impl Checker { let checked_typed_index = match checked_index { TypedExpression::FieldElement(e) => Ok(e), - e => Err(SingleError { + e => Err(Error { pos: Some(assignee.pos()), message: format!( @@ -487,7 +501,7 @@ impl Checker { fn check_expression( &mut self, expr: &ExpressionNode, - ) -> Result, SingleError> { + ) -> Result, Error> { match &expr.value { &Expression::Identifier(ref name) => { // check that `id` is defined in the scope @@ -501,7 +515,7 @@ impl Checker { Ok(FieldElementArrayExpression::Identifier(n, name.to_string()).into()) } }, - None => Err(SingleError { + None => Err(Error { pos: Some(expr.pos()), message: format!("Identifier is undefined"), @@ -516,7 +530,7 @@ impl Checker { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(FieldElementExpression::Add(box e1, box e2).into()) } - (t1, t2) => Err(SingleError { + (t1, t2) => Err(Error { pos: Some(expr.pos()), message: format!( @@ -535,7 +549,7 @@ impl Checker { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(FieldElementExpression::Sub(box e1, box e2).into()) } - (t1, t2) => Err(SingleError { + (t1, t2) => Err(Error { pos: Some(expr.pos()), message: format!( @@ -554,7 +568,7 @@ impl Checker { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(FieldElementExpression::Mult(box e1, box e2).into()) } - (t1, t2) => Err(SingleError { + (t1, t2) => Err(Error { pos: Some(expr.pos()), message: format!( @@ -573,7 +587,7 @@ impl Checker { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(FieldElementExpression::Div(box e1, box e2).into()) } - (t1, t2) => Err(SingleError { + (t1, t2) => Err(Error { pos: Some(expr.pos()), message: format!( @@ -592,7 +606,7 @@ impl Checker { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => Ok( TypedExpression::FieldElement(FieldElementExpression::Pow(box e1, box e2)), ), - (t1, t2) => Err(SingleError { + (t1, t2) => Err(Error { pos: Some(expr.pos()), message: format!( @@ -614,9 +628,8 @@ impl Checker { }, (condition, consequence, alternative) => Err( - SingleError { - pos: Some(expr.pos()), - + Error { + pos: Some(expr.pos()), message: format!("if {{condition}} then {{consequence}} else {{alternative}} should have types {}, {}, {}, found {}, {}, {}", Type::Boolean, @@ -672,7 +685,7 @@ impl Checker { } _ => unimplemented!(), }, - n => Err(SingleError { + n => Err(Error { pos: Some(expr.pos()), message: format!( @@ -682,7 +695,7 @@ impl Checker { }), } } - 0 => Err(SingleError { + 0 => Err(Error { pos: Some(expr.pos()), message: format!( @@ -700,10 +713,15 @@ impl Checker { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(BooleanExpression::Lt(box e1, box e2).into()) } - (e1, e2) => Err(SingleError { + (e1, e2) => Err(Error { pos: Some(expr.pos()), - - message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), }), } } @@ -714,10 +732,15 @@ impl Checker { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(BooleanExpression::Le(box e1, box e2).into()) } - (e1, e2) => Err(SingleError { + (e1, e2) => Err(Error { pos: Some(expr.pos()), - - message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), }), } } @@ -728,10 +751,15 @@ impl Checker { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(BooleanExpression::Eq(box e1, box e2).into()) } - (e1, e2) => Err(SingleError { + (e1, e2) => Err(Error { pos: Some(expr.pos()), - - message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), }), } } @@ -742,10 +770,15 @@ impl Checker { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(BooleanExpression::Ge(box e1, box e2).into()) } - (e1, e2) => Err(SingleError { + (e1, e2) => Err(Error { pos: Some(expr.pos()), - - message: format!("Cannot compare {} to {}", e1.get_type(), e2.get_type()), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), }), } } @@ -756,10 +789,15 @@ impl Checker { (TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => { Ok(BooleanExpression::Gt(box e1, box e2).into()) } - (e1, e2) => Err(SingleError { + (e1, e2) => Err(Error { pos: Some(expr.pos()), - - message: format!("Cannot compare {} to {}", e1.get_type(), e2.get_type()), + message: format!( + "Cannot compare {} of type {} to {} of type {}", + e1, + e1.get_type(), + e2, + e2.get_type() + ), }), } } @@ -771,11 +809,10 @@ impl Checker { TypedExpression::FieldElementArray(ref a), TypedExpression::FieldElement(ref i), ) => Ok(FieldElementExpression::Select(box a.clone(), box i.clone()).into()), - (a, e) => Err(SingleError { + (a, e) => Err(Error { pos: Some(expr.pos()), - message: format!( - "Cannot take element {} on expression of type {}", + "Cannot access element {} on expression of type {}", e, a.get_type() ), @@ -803,7 +840,7 @@ impl Checker { for e in expressions_checked { let unwrapped_e = match e { TypedExpression::FieldElement(e) => Ok(e), - e => Err(SingleError { + e => Err(Error { pos: Some(expr.pos()), message: format!( @@ -819,7 +856,7 @@ impl Checker { Ok(FieldElementArrayExpression::Value(size, unwrapped_expressions).into()) } - _ => Err(SingleError { + _ => Err(Error { pos: Some(expr.pos()), message: format!( @@ -837,7 +874,7 @@ impl Checker { (TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => { Ok(BooleanExpression::And(box e1, box e2).into()) } - (e1, e2) => Err(SingleError { + (e1, e2) => Err(Error { pos: Some(expr.pos()), message: format!( @@ -855,7 +892,7 @@ impl Checker { (TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => { Ok(BooleanExpression::Or(box e1, box e2).into()) } - (e1, e2) => Err(SingleError { + (e1, e2) => Err(Error { pos: Some(expr.pos()), message: format!("cannot compare {} to {}", e1.get_type(), e2.get_type()), @@ -866,7 +903,7 @@ impl Checker { let e_checked = self.check_expression(e)?; match e_checked { TypedExpression::Boolean(e) => Ok(BooleanExpression::Not(box e).into()), - e => Err(SingleError { + e => Err(Error { pos: Some(expr.pos()), message: format!("cannot negate {}", e.get_type()), @@ -908,845 +945,845 @@ impl Checker { #[cfg(test)] mod tests { - use super::*; - use absy::parameter::Parameter; - use zokrates_field::field::FieldPrime; - - pub fn new_with_args( - scope: HashSet, - level: usize, - functions: HashSet, - ) -> Checker { - Checker { - scope: scope, - functions: functions, - level: level, - } - } - - #[test] - fn undefined_variable_in_statement() { - // a = b - // b undefined - let statement: Statement = Statement::Definition( - Assignee::Identifier(String::from("a")), - Expression::Identifier(String::from("b")), - ); - let mut checker = Checker::new(); - assert_eq!( - checker.check_statement(&statement, &vec![]), - Err(SingleError { - message: "b is undefined".to_string() - }) - ); - } - - #[test] - fn defined_variable_in_statement() { - // a = b - // b defined - let statement: Statement = Statement::Definition( - Assignee::Identifier(String::from("a")), - Expression::Identifier(String::from("b")), - ); - - let mut scope = HashSet::new(); - scope.insert(ScopedVariable { - id: Variable::field_element("a"), - level: 0, - }); - scope.insert(ScopedVariable { - id: Variable::field_element("b"), - level: 0, - }); - let mut checker = new_with_args(scope, 1, HashSet::new()); - assert_eq!( - checker.check_statement(&statement, &vec![]), - Ok(TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Identifier(String::from("b")).into() - )) - ); - } - - #[test] - fn declared_in_other_function() { - // def foo(): - // field a = 1 - // def bar(): - // return a - // should fail - let foo_args = Vec::::new(); - let mut foo_statements = Vec::>::new(); - foo_statements.push(Statement::Declaration(Variable::field_element("a"))); - foo_statements.push(Statement::Definition( - Assignee::Identifier(String::from("a")), - Expression::Number(FieldPrime::from(1)), - )); - let foo = Function { - id: "foo".to_string(), - arguments: foo_args, - statements: foo_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let bar_args = Vec::::new(); - let mut bar_statements = Vec::>::new(); - bar_statements.push(Statement::Return(ExpressionList { - expressions: vec![Expression::Identifier(String::from("a"))], - })); - let bar = Function { - id: "bar".to_string(), - arguments: bar_args, - statements: bar_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let mut funcs = Vec::>::new(); - funcs.push(foo); - funcs.push(bar); - let prog = Prog { - functions: funcs, - imports: vec![], - imported_functions: vec![], - }; - - let mut checker = Checker::new(); - assert_eq!( - checker.check_program(prog), - Err(SingleError { - message: "a is undefined".to_string() - }) - ); - } - - #[test] - fn declared_in_two_scopes() { - // def foo(): - // a = 1 - // def bar(): - // a = 2 - // return a - // def main(): - // return 1 - // should pass - let foo_args = vec![]; - let foo_statements = vec![ - Statement::Declaration(Variable::field_element("a")), - Statement::Definition( - Assignee::Identifier(String::from("a")), - Expression::Number(FieldPrime::from(1)), - ), - ]; - - let foo = Function { - id: "foo".to_string(), - arguments: foo_args, - statements: foo_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let bar_args = Vec::::new(); - let bar_statements = vec![ - Statement::Declaration(Variable::field_element("a")), - Statement::Definition( - Assignee::Identifier(String::from("a")), - Expression::Number(FieldPrime::from(2)), - ), - Statement::Return(ExpressionList { - expressions: vec![Expression::Identifier(String::from("a"))], - }), - ]; - let bar = Function { - id: "bar".to_string(), - arguments: bar_args, - statements: bar_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let main_args = vec![]; - let main_statements = vec![Statement::Return(ExpressionList { - expressions: vec![Expression::Number(FieldPrime::from(1))], - })]; - - let main = Function { - id: "main".to_string(), - arguments: main_args, - statements: main_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let mut funcs = Vec::>::new(); - funcs.push(foo); - funcs.push(bar); - funcs.push(main); - let prog = Prog { - functions: funcs, - imports: vec![], - imported_functions: vec![], - }; - - let mut checker = Checker::new(); - assert!(checker.check_program(prog).is_ok()); - } - - #[test] - fn for_index_after_end() { - // def foo(): - // for field i in 0..10 do - // endfor - // return i - // should fail - let mut foo_statements = Vec::>::new(); - foo_statements.push(Statement::For( - Variable::field_element("i"), - FieldPrime::from(0), - FieldPrime::from(10), - Vec::>::new(), - )); - foo_statements.push(Statement::Return(ExpressionList { - expressions: vec![Expression::Identifier(String::from("i"))], - })); - let foo = Function { - id: "foo".to_string(), - arguments: Vec::::new(), - statements: foo_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let mut checker = Checker::new(); - assert_eq!( - checker.check_function(&foo), - Err(SingleError { - message: "i is undefined".to_string() - }) - ); - } - - #[test] - fn for_index_in_for() { - // def foo(): - // for i in 0..10 do - // a = i - // endfor - // should pass - let mut foo_statements = Vec::>::new(); - let mut for_statements = Vec::>::new(); - for_statements.push(Statement::Declaration(Variable::field_element("a"))); - for_statements.push(Statement::Definition( - Assignee::Identifier(String::from("a")), - Expression::Identifier(String::from("i")), - )); - foo_statements.push(Statement::For( - Variable::field_element("i"), - FieldPrime::from(0), - FieldPrime::from(10), - for_statements, - )); - - let mut foo_statements_checked = Vec::>::new(); - let mut for_statements_checked = Vec::>::new(); - - for_statements_checked.push(TypedStatement::Declaration(Variable::field_element("a"))); - - for_statements_checked.push(TypedStatement::Definition( - TypedAssignee::Identifier(Variable::field_element("a")), - FieldElementExpression::Identifier(String::from("i")).into(), - )); - - foo_statements_checked.push(TypedStatement::For( - Variable::field_element("i"), - FieldPrime::from(0), - FieldPrime::from(10), - for_statements_checked, - )); - - let foo = Function { - id: "foo".to_string(), - arguments: Vec::::new(), - statements: foo_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let foo_checked = TypedFunction { - id: "foo".to_string(), - arguments: Vec::::new(), - statements: foo_statements_checked, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let mut checker = Checker::new(); - assert_eq!(checker.check_function(&foo), Ok(foo_checked)); - } - - #[test] - fn arity_mismatch() { - // def foo(): - // return 1, 2 - // def bar(): - // field c = foo() - // should fail - let bar_statements: Vec> = vec![ - Statement::Declaration(Variable::field_element("a")), - Statement::MultipleDefinition( - vec![Assignee::Identifier(String::from("a"))], - Expression::FunctionCall("foo".to_string(), vec![]), - ), - ]; - - let foo = FunctionDeclaration { - id: "foo".to_string(), - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement, Type::FieldElement], - }, - }; - - let mut functions = HashSet::new(); - functions.insert(foo); - - let bar = Function { - id: "bar".to_string(), - arguments: vec![], - statements: bar_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let mut checker = new_with_args(HashSet::new(), 0, functions); - assert_eq!( - checker.check_function(&bar), - Err(SingleError { - message: - "Function definition for function foo with signature () -> (field) not found." - .to_string() - }) - ); - } - - #[test] - fn multi_return_outside_multidef() { - // def foo(): - // return 1, 2 - // def bar(): - // 4 == foo() - // should fail - let bar_statements: Vec> = vec![Statement::Condition( - Expression::Number(FieldPrime::from(2)), - Expression::FunctionCall("foo".to_string(), vec![]), - )]; - - let foo = FunctionDeclaration { - id: "foo".to_string(), - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement, Type::FieldElement], - }, - }; - - let mut functions = HashSet::new(); - functions.insert(foo); - - let bar = Function { - id: "bar".to_string(), - arguments: vec![], - statements: bar_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let mut checker = new_with_args(HashSet::new(), 0, functions); - assert_eq!( - checker.check_function(&bar), - Err(SingleError { - message: "Function definition for function foo with signature () -> (_) not found." - .to_string() - }) - ); - } - - #[test] - fn function_undefined_in_multidef() { - // def bar(): - // field a = foo() - // should fail - let bar_statements: Vec> = vec![ - Statement::Declaration(Variable::field_element("a")), - Statement::MultipleDefinition( - vec![Assignee::Identifier(String::from("a"))], - Expression::FunctionCall("foo".to_string(), vec![]), - ), - ]; - - let bar = Function { - id: "bar".to_string(), - arguments: vec![], - statements: bar_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); - assert_eq!( - checker.check_function(&bar), - Err(SingleError { - message: - "Function definition for function foo with signature () -> (field) not found." - .to_string() - }) - ); - } - - #[test] - fn undefined_variable_in_multireturn_call() { - // def foo(x): - // return 1, 2 - // def main(): - // a, b = foo(x) - // return 1 - // should fail - - let foo_statements: Vec> = vec![Statement::Return(ExpressionList { - expressions: vec![ - Expression::Number(FieldPrime::from(1)), - Expression::Number(FieldPrime::from(2)), - ], - })]; - - let foo = Function { - id: "foo".to_string(), - arguments: vec![Parameter { - id: Variable::field_element("x"), - private: false, - }], - statements: foo_statements, - signature: Signature { - inputs: vec![Type::FieldElement], - outputs: vec![Type::FieldElement, Type::FieldElement], - }, - }; - - let main_statements: Vec> = vec![ - Statement::Declaration(Variable::field_element("a")), - Statement::Declaration(Variable::field_element("b")), - Statement::MultipleDefinition( - vec![ - Assignee::Identifier(String::from("a")), - Assignee::Identifier(String::from("b")), - ], - Expression::FunctionCall( - "foo".to_string(), - vec![Expression::Identifier("x".to_string())], - ), - ), - Statement::Return(ExpressionList { - expressions: vec![Expression::Number(FieldPrime::from(1))], - }), - ]; - - let main = Function { - id: "main".to_string(), - arguments: vec![], - statements: main_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement, Type::FieldElement], - }, - }; - - let program = Prog { - functions: vec![foo, main], - imports: vec![], - imported_functions: vec![], - }; - - let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); - assert_eq!( - checker.check_program(program), - Err(SingleError { - message: "x is undefined".to_string() - }) - ); - } - - #[test] - fn function_undefined() { - // def bar(): - // 1 == foo() - // should fail - let bar_statements: Vec> = vec![Statement::Condition( - Expression::Number(FieldPrime::from(1)), - Expression::FunctionCall("foo".to_string(), vec![]), - )]; - - let bar = Function { - id: "bar".to_string(), - arguments: vec![], - statements: bar_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); - assert_eq!( - checker.check_function(&bar), - Err(SingleError { - message: "Function definition for function foo with signature () -> (_) not found." - .to_string() - }) - ); - } - - #[test] - fn return_undefined() { - // def bar(): - // return a, b - // should fail - let bar_statements: Vec> = vec![Statement::Return(ExpressionList { - expressions: vec![ - Expression::Identifier("a".to_string()), - Expression::Identifier("b".to_string()), - ], - })]; - - let bar = Function { - id: "bar".to_string(), - arguments: vec![], - statements: bar_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement, Type::FieldElement], - }, - }; - - let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); - assert_eq!( - checker.check_function(&bar), - Err(SingleError { - message: "a is undefined".to_string() - }) - ); - } - - #[test] - fn multi_def() { - // def foo(): - // return 1, 2 - // def bar(): - // field a, field b = foo() - // return a + b - // - // should pass - let bar_statements: Vec> = vec![ - Statement::Declaration(Variable::field_element("a")), - Statement::Declaration(Variable::field_element("b")), - Statement::MultipleDefinition( - vec![ - Assignee::Identifier(String::from("a")), - Assignee::Identifier(String::from("b")), - ], - Expression::FunctionCall("foo".to_string(), vec![]), - ), - Statement::Return(ExpressionList { - expressions: vec![Expression::Add( - box Expression::Identifier("a".to_string()), - box Expression::Identifier("b".to_string()), - )], - }), - ]; - - let bar_statements_checked: Vec> = vec![ - TypedStatement::Declaration(Variable::field_element("a")), - TypedStatement::Declaration(Variable::field_element("b")), - TypedStatement::MultipleDefinition( - vec![Variable::field_element("a"), Variable::field_element("b")], - TypedExpressionList::FunctionCall( - "foo".to_string(), - vec![], - vec![Type::FieldElement, Type::FieldElement], - ), - ), - TypedStatement::Return(vec![FieldElementExpression::Add( - box FieldElementExpression::Identifier("a".to_string()), - box FieldElementExpression::Identifier("b".to_string()), - ) - .into()]), - ]; - - let foo = FunctionDeclaration { - id: "foo".to_string(), - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement, Type::FieldElement], - }, - }; - - let mut functions = HashSet::new(); - functions.insert(foo); - - let bar = Function { - id: "bar".to_string(), - arguments: vec![], - statements: bar_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let bar_checked = TypedFunction { - id: "bar".to_string(), - arguments: vec![], - statements: bar_statements_checked, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let mut checker = new_with_args(HashSet::new(), 0, functions); - assert_eq!(checker.check_function(&bar), Ok(bar_checked)); - } - - #[test] - fn duplicate_function_declaration() { - // def foo(a, b): - // return 1 - // def foo(c, d): - // return 2 - // - // should fail - let foo2_statements: Vec> = vec![Statement::Return(ExpressionList { - expressions: vec![Expression::Number(FieldPrime::from(1))], - })]; - - let foo2_arguments = vec![ - Parameter { - id: Variable::field_element("a"), - private: true, - }, - Parameter { - id: Variable::field_element("b"), - private: true, - }, - ]; - - let foo1 = FunctionDeclaration { - id: "foo".to_string(), - signature: Signature { - inputs: vec![Type::FieldElement, Type::FieldElement], - outputs: vec![Type::FieldElement], - }, - }; - - let mut functions = HashSet::new(); - functions.insert(foo1); - - let foo2 = Function { - id: "foo".to_string(), - arguments: foo2_arguments, - statements: foo2_statements, - signature: Signature { - inputs: vec![Type::FieldElement, Type::FieldElement], - outputs: vec![Type::FieldElement], - }, - }; - - let mut checker = new_with_args(HashSet::new(), 0, functions); - assert_eq!( - checker.check_function(&foo2), - Err(SingleError { - message: - "Duplicate definition for function foo with signature (field, field) -> (field)" - .to_string() - }) - ); - } - - #[test] - fn duplicate_main_function() { - // def main(a): - // return 1 - // def main(): - // return 1 - // - // should fail - let main1_statements: Vec> = - vec![Statement::Return(ExpressionList { - expressions: vec![Expression::Number(FieldPrime::from(1))], - })]; - - let main1_arguments = vec![Parameter { - id: Variable::field_element("a"), - private: false, - }]; - - let main2_statements: Vec> = - vec![Statement::Return(ExpressionList { - expressions: vec![Expression::Number(FieldPrime::from(1))], - })]; - - let main2_arguments = vec![]; - - let main1 = Function { - id: "main".to_string(), - arguments: main1_arguments, - statements: main1_statements, - signature: Signature { - inputs: vec![Type::FieldElement], - outputs: vec![Type::FieldElement], - }, - }; - - let main2 = Function { - id: "main".to_string(), - arguments: main2_arguments, - statements: main2_statements, - signature: Signature { - inputs: vec![], - outputs: vec![Type::FieldElement], - }, - }; - - let prog = Prog { - functions: vec![main1, main2], - imports: vec![], - imported_functions: vec![], - }; - - let mut checker = Checker::new(); - assert_eq!( - checker.check_program(prog), - Err(SingleError { - message: "Only one main function allowed, found 2".to_string() - }) - ); - } - - #[test] - fn shadowing_with_same_type() { - // field a - // field a - // - // should fail - - let mut checker = Checker::new(); - let _: Result, SingleError> = checker.check_statement( - &Statement::Declaration(Variable::field_element("a")), - &vec![], - ); - let s2_checked: Result, SingleError> = checker.check_statement( - &Statement::Declaration(Variable::field_element("a")), - &vec![], - ); - assert_eq!( - s2_checked, - Err(SingleError { - message: "Duplicate declaration for variable named a".to_string() - }) - ); - } - - #[test] - fn shadowing_with_different_type() { - // field a - // bool a - // - // should fail - - let mut checker = Checker::new(); - let _: Result, SingleError> = checker.check_statement( - &Statement::Declaration(Variable::field_element("a")), - &vec![], - ); - let s2_checked: Result, SingleError> = - checker.check_statement(&Statement::Declaration(Variable::boolean("a")), &vec![]); - assert_eq!( - s2_checked, - Err(SingleError { - message: "Duplicate declaration for variable named a".to_string() - }) - ); - } - - mod assignee { - use super::*; - - #[test] - fn identifier() { - // a = 42 - let a = Assignee::Identifier::(String::from("a")); - - let mut checker: Checker = Checker::new(); - checker - .check_statement::( - &Statement::Declaration(Variable::field_element("a")), - &vec![], - ) - .unwrap(); - - assert_eq!( - checker.check_assignee(&a), - Ok(TypedAssignee::Identifier(Variable::field_element("a"))) - ); - } - - #[test] - fn array_element() { - // field[33] a - // a[2] = 42 - let a = Assignee::ArrayElement( - box Assignee::Identifier(String::from("a")), - box Expression::Number(FieldPrime::from(2)), - ); - - let mut checker: Checker = Checker::new(); - checker - .check_statement::( - &Statement::Declaration(Variable::field_array("a", 33)), - &vec![], - ) - .unwrap(); - - assert_eq!( - checker.check_assignee(&a), - Ok(TypedAssignee::ArrayElement( - box TypedAssignee::Identifier(Variable::field_array("a", 33)), - box FieldElementExpression::Number(FieldPrime::from(2)).into() - )) - ); - } - } + // use super::*; + // use absy::parameter::Parameter; + // use zokrates_field::field::FieldPrime; + + // pub fn new_with_args( + // scope: HashSet, + // level: usize, + // functions: HashSet, + // ) -> Checker { + // Checker { + // scope: scope, + // functions: functions, + // level: level, + // } + // } + + // #[test] + // fn undefined_variable_in_statement() { + // // a = b + // // b undefined + // let statement: Statement = Statement::Definition( + // Assignee::Identifier(String::from("a")), + // Expression::Identifier(String::from("b")), + // ); + // let mut checker = Checker::new(); + // assert_eq!( + // checker.check_statement(&statement, &vec![]), + // Err(Error { + // message: "b is undefined".to_string() + // }) + // ); + // } + + // #[test] + // fn defined_variable_in_statement() { + // // a = b + // // b defined + // let statement: Statement = Statement::Definition( + // Assignee::Identifier(String::from("a")), + // Expression::Identifier(String::from("b")), + // ); + + // let mut scope = HashSet::new(); + // scope.insert(ScopedVariable { + // id: Variable::field_element("a"), + // level: 0, + // }); + // scope.insert(ScopedVariable { + // id: Variable::field_element("b"), + // level: 0, + // }); + // let mut checker = new_with_args(scope, 1, HashSet::new()); + // assert_eq!( + // checker.check_statement(&statement, &vec![]), + // Ok(TypedStatement::Definition( + // TypedAssignee::Identifier(Variable::field_element("a")), + // FieldElementExpression::Identifier(String::from("b")).into() + // )) + // ); + // } + + // #[test] + // fn declared_in_other_function() { + // // def foo(): + // // field a = 1 + // // def bar(): + // // return a + // // should fail + // let foo_args = Vec::::new(); + // let mut foo_statements = Vec::>::new(); + // foo_statements.push(Statement::Declaration(Variable::field_element("a"))); + // foo_statements.push(Statement::Definition( + // Assignee::Identifier(String::from("a")), + // Expression::Number(FieldPrime::from(1)), + // )); + // let foo = Function { + // id: "foo".to_string(), + // arguments: foo_args, + // statements: foo_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let bar_args = Vec::::new(); + // let mut bar_statements = Vec::>::new(); + // bar_statements.push(Statement::Return(ExpressionList { + // expressions: vec![Expression::Identifier(String::from("a"))], + // })); + // let bar = Function { + // id: "bar".to_string(), + // arguments: bar_args, + // statements: bar_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut funcs = Vec::>::new(); + // funcs.push(foo); + // funcs.push(bar); + // let prog = Prog { + // functions: funcs, + // imports: vec![], + // imported_functions: vec![], + // }; + + // let mut checker = Checker::new(); + // assert_eq!( + // checker.check_program(prog), + // Err(Error { + // message: "a is undefined".to_string() + // }) + // ); + // } + + // #[test] + // fn declared_in_two_scopes() { + // // def foo(): + // // a = 1 + // // def bar(): + // // a = 2 + // // return a + // // def main(): + // // return 1 + // // should pass + // let foo_args = vec![]; + // let foo_statements = vec![ + // Statement::Declaration(Variable::field_element("a")), + // Statement::Definition( + // Assignee::Identifier(String::from("a")), + // Expression::Number(FieldPrime::from(1)), + // ), + // ]; + + // let foo = Function { + // id: "foo".to_string(), + // arguments: foo_args, + // statements: foo_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let bar_args = Vec::::new(); + // let bar_statements = vec![ + // Statement::Declaration(Variable::field_element("a")), + // Statement::Definition( + // Assignee::Identifier(String::from("a")), + // Expression::Number(FieldPrime::from(2)), + // ), + // Statement::Return(ExpressionList { + // expressions: vec![Expression::Identifier(String::from("a"))], + // }), + // ]; + // let bar = Function { + // id: "bar".to_string(), + // arguments: bar_args, + // statements: bar_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let main_args = vec![]; + // let main_statements = vec![Statement::Return(ExpressionList { + // expressions: vec![Expression::Number(FieldPrime::from(1))], + // })]; + + // let main = Function { + // id: "main".to_string(), + // arguments: main_args, + // statements: main_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut funcs = Vec::>::new(); + // funcs.push(foo); + // funcs.push(bar); + // funcs.push(main); + // let prog = Prog { + // functions: funcs, + // imports: vec![], + // imported_functions: vec![], + // }; + + // let mut checker = Checker::new(); + // assert!(checker.check_program(prog).is_ok()); + // } + + // #[test] + // fn for_index_after_end() { + // // def foo(): + // // for field i in 0..10 do + // // endfor + // // return i + // // should fail + // let mut foo_statements = Vec::>::new(); + // foo_statements.push(Statement::For( + // Variable::field_element("i"), + // FieldPrime::from(0), + // FieldPrime::from(10), + // Vec::>::new(), + // )); + // foo_statements.push(Statement::Return(ExpressionList { + // expressions: vec![Expression::Identifier(String::from("i"))], + // })); + // let foo = Function { + // id: "foo".to_string(), + // arguments: Vec::::new(), + // statements: foo_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut checker = Checker::new(); + // assert_eq!( + // checker.check_function(&foo), + // Err(Error { + // message: "i is undefined".to_string() + // }) + // ); + // } + + // #[test] + // fn for_index_in_for() { + // // def foo(): + // // for i in 0..10 do + // // a = i + // // endfor + // // should pass + // let mut foo_statements = Vec::>::new(); + // let mut for_statements = Vec::>::new(); + // for_statements.push(Statement::Declaration(Variable::field_element("a"))); + // for_statements.push(Statement::Definition( + // Assignee::Identifier(String::from("a")), + // Expression::Identifier(String::from("i")), + // )); + // foo_statements.push(Statement::For( + // Variable::field_element("i"), + // FieldPrime::from(0), + // FieldPrime::from(10), + // for_statements, + // )); + + // let mut foo_statements_checked = Vec::>::new(); + // let mut for_statements_checked = Vec::>::new(); + + // for_statements_checked.push(TypedStatement::Declaration(Variable::field_element("a"))); + + // for_statements_checked.push(TypedStatement::Definition( + // TypedAssignee::Identifier(Variable::field_element("a")), + // FieldElementExpression::Identifier(String::from("i")).into(), + // )); + + // foo_statements_checked.push(TypedStatement::For( + // Variable::field_element("i"), + // FieldPrime::from(0), + // FieldPrime::from(10), + // for_statements_checked, + // )); + + // let foo = Function { + // id: "foo".to_string(), + // arguments: Vec::::new(), + // statements: foo_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let foo_checked = TypedFunction { + // id: "foo".to_string(), + // arguments: Vec::::new(), + // statements: foo_statements_checked, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut checker = Checker::new(); + // assert_eq!(checker.check_function(&foo), Ok(foo_checked)); + // } + + // #[test] + // fn arity_mismatch() { + // // def foo(): + // // return 1, 2 + // // def bar(): + // // field c = foo() + // // should fail + // let bar_statements: Vec> = vec![ + // Statement::Declaration(Variable::field_element("a")), + // Statement::MultipleDefinition( + // vec![Assignee::Identifier(String::from("a"))], + // Expression::FunctionCall("foo".to_string(), vec![]), + // ), + // ]; + + // let foo = FunctionDeclaration { + // id: "foo".to_string(), + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement, Type::FieldElement], + // }, + // }; + + // let mut functions = HashSet::new(); + // functions.insert(foo); + + // let bar = Function { + // id: "bar".to_string(), + // arguments: vec![], + // statements: bar_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut checker = new_with_args(HashSet::new(), 0, functions); + // assert_eq!( + // checker.check_function(&bar), + // Err(Error { + // message: + // "Function definition for function foo with signature () -> (field) not found." + // .to_string() + // }) + // ); + // } + + // #[test] + // fn multi_return_outside_multidef() { + // // def foo(): + // // return 1, 2 + // // def bar(): + // // 4 == foo() + // // should fail + // let bar_statements: Vec> = vec![Statement::Condition( + // Expression::Number(FieldPrime::from(2)), + // Expression::FunctionCall("foo".to_string(), vec![]), + // )]; + + // let foo = FunctionDeclaration { + // id: "foo".to_string(), + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement, Type::FieldElement], + // }, + // }; + + // let mut functions = HashSet::new(); + // functions.insert(foo); + + // let bar = Function { + // id: "bar".to_string(), + // arguments: vec![], + // statements: bar_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut checker = new_with_args(HashSet::new(), 0, functions); + // assert_eq!( + // checker.check_function(&bar), + // Err(Error { + // message: "Function definition for function foo with signature () -> (_) not found." + // .to_string() + // }) + // ); + // } + + // #[test] + // fn function_undefined_in_multidef() { + // // def bar(): + // // field a = foo() + // // should fail + // let bar_statements: Vec> = vec![ + // Statement::Declaration(Variable::field_element("a")), + // Statement::MultipleDefinition( + // vec![Assignee::Identifier(String::from("a"))], + // Expression::FunctionCall("foo".to_string(), vec![]), + // ), + // ]; + + // let bar = Function { + // id: "bar".to_string(), + // arguments: vec![], + // statements: bar_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); + // assert_eq!( + // checker.check_function(&bar), + // Err(Error { + // message: + // "Function definition for function foo with signature () -> (field) not found." + // .to_string() + // }) + // ); + // } + + // #[test] + // fn undefined_variable_in_multireturn_call() { + // // def foo(x): + // // return 1, 2 + // // def main(): + // // a, b = foo(x) + // // return 1 + // // should fail + + // let foo_statements: Vec> = vec![Statement::Return(ExpressionList { + // expressions: vec![ + // Expression::Number(FieldPrime::from(1)), + // Expression::Number(FieldPrime::from(2)), + // ], + // })]; + + // let foo = Function { + // id: "foo".to_string(), + // arguments: vec![Parameter { + // id: Variable::field_element("x"), + // private: false, + // }], + // statements: foo_statements, + // signature: Signature { + // inputs: vec![Type::FieldElement], + // outputs: vec![Type::FieldElement, Type::FieldElement], + // }, + // }; + + // let main_statements: Vec> = vec![ + // Statement::Declaration(Variable::field_element("a")), + // Statement::Declaration(Variable::field_element("b")), + // Statement::MultipleDefinition( + // vec![ + // Assignee::Identifier(String::from("a")), + // Assignee::Identifier(String::from("b")), + // ], + // Expression::FunctionCall( + // "foo".to_string(), + // vec![Expression::Identifier("x".to_string())], + // ), + // ), + // Statement::Return(ExpressionList { + // expressions: vec![Expression::Number(FieldPrime::from(1))], + // }), + // ]; + + // let main = Function { + // id: "main".to_string(), + // arguments: vec![], + // statements: main_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement, Type::FieldElement], + // }, + // }; + + // let program = Prog { + // functions: vec![foo, main], + // imports: vec![], + // imported_functions: vec![], + // }; + + // let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); + // assert_eq!( + // checker.check_program(program), + // Err(Error { + // message: "x is undefined".to_string() + // }) + // ); + // } + + // #[test] + // fn function_undefined() { + // // def bar(): + // // 1 == foo() + // // should fail + // let bar_statements: Vec> = vec![Statement::Condition( + // Expression::Number(FieldPrime::from(1)), + // Expression::FunctionCall("foo".to_string(), vec![]), + // )]; + + // let bar = Function { + // id: "bar".to_string(), + // arguments: vec![], + // statements: bar_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); + // assert_eq!( + // checker.check_function(&bar), + // Err(Error { + // message: "Function definition for function foo with signature () -> (_) not found." + // .to_string() + // }) + // ); + // } + + // #[test] + // fn return_undefined() { + // // def bar(): + // // return a, b + // // should fail + // let bar_statements: Vec> = vec![Statement::Return(ExpressionList { + // expressions: vec![ + // Expression::Identifier("a".to_string()), + // Expression::Identifier("b".to_string()), + // ], + // })]; + + // let bar = Function { + // id: "bar".to_string(), + // arguments: vec![], + // statements: bar_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement, Type::FieldElement], + // }, + // }; + + // let mut checker = new_with_args(HashSet::new(), 0, HashSet::new()); + // assert_eq!( + // checker.check_function(&bar), + // Err(Error { + // message: "a is undefined".to_string() + // }) + // ); + // } + + // #[test] + // fn multi_def() { + // // def foo(): + // // return 1, 2 + // // def bar(): + // // field a, field b = foo() + // // return a + b + // // + // // should pass + // let bar_statements: Vec> = vec![ + // Statement::Declaration(Variable::field_element("a")), + // Statement::Declaration(Variable::field_element("b")), + // Statement::MultipleDefinition( + // vec![ + // Assignee::Identifier(String::from("a")), + // Assignee::Identifier(String::from("b")), + // ], + // Expression::FunctionCall("foo".to_string(), vec![]), + // ), + // Statement::Return(ExpressionList { + // expressions: vec![Expression::Add( + // box Expression::Identifier("a".to_string()), + // box Expression::Identifier("b".to_string()), + // )], + // }), + // ]; + + // let bar_statements_checked: Vec> = vec![ + // TypedStatement::Declaration(Variable::field_element("a")), + // TypedStatement::Declaration(Variable::field_element("b")), + // TypedStatement::MultipleDefinition( + // vec![Variable::field_element("a"), Variable::field_element("b")], + // TypedExpressionList::FunctionCall( + // "foo".to_string(), + // vec![], + // vec![Type::FieldElement, Type::FieldElement], + // ), + // ), + // TypedStatement::Return(vec![FieldElementExpression::Add( + // box FieldElementExpression::Identifier("a".to_string()), + // box FieldElementExpression::Identifier("b".to_string()), + // ) + // .into()]), + // ]; + + // let foo = FunctionDeclaration { + // id: "foo".to_string(), + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement, Type::FieldElement], + // }, + // }; + + // let mut functions = HashSet::new(); + // functions.insert(foo); + + // let bar = Function { + // id: "bar".to_string(), + // arguments: vec![], + // statements: bar_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let bar_checked = TypedFunction { + // id: "bar".to_string(), + // arguments: vec![], + // statements: bar_statements_checked, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut checker = new_with_args(HashSet::new(), 0, functions); + // assert_eq!(checker.check_function(&bar), Ok(bar_checked)); + // } + + // #[test] + // fn duplicate_function_declaration() { + // // def foo(a, b): + // // return 1 + // // def foo(c, d): + // // return 2 + // // + // // should fail + // let foo2_statements: Vec> = vec![Statement::Return(ExpressionList { + // expressions: vec![Expression::Number(FieldPrime::from(1))], + // })]; + + // let foo2_arguments = vec![ + // Parameter { + // id: Variable::field_element("a"), + // private: true, + // }, + // Parameter { + // id: Variable::field_element("b"), + // private: true, + // }, + // ]; + + // let foo1 = FunctionDeclaration { + // id: "foo".to_string(), + // signature: Signature { + // inputs: vec![Type::FieldElement, Type::FieldElement], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut functions = HashSet::new(); + // functions.insert(foo1); + + // let foo2 = Function { + // id: "foo".to_string(), + // arguments: foo2_arguments, + // statements: foo2_statements, + // signature: Signature { + // inputs: vec![Type::FieldElement, Type::FieldElement], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let mut checker = new_with_args(HashSet::new(), 0, functions); + // assert_eq!( + // checker.check_function(&foo2), + // Err(Error { + // message: + // "Duplicate definition for function foo with signature (field, field) -> (field)" + // .to_string() + // }) + // ); + // } + + // #[test] + // fn duplicate_main_function() { + // // def main(a): + // // return 1 + // // def main(): + // // return 1 + // // + // // should fail + // let main1_statements: Vec> = + // vec![Statement::Return(ExpressionList { + // expressions: vec![Expression::Number(FieldPrime::from(1))], + // })]; + + // let main1_arguments = vec![Parameter { + // id: Variable::field_element("a"), + // private: false, + // }]; + + // let main2_statements: Vec> = + // vec![Statement::Return(ExpressionList { + // expressions: vec![Expression::Number(FieldPrime::from(1))], + // })]; + + // let main2_arguments = vec![]; + + // let main1 = Function { + // id: "main".to_string(), + // arguments: main1_arguments, + // statements: main1_statements, + // signature: Signature { + // inputs: vec![Type::FieldElement], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let main2 = Function { + // id: "main".to_string(), + // arguments: main2_arguments, + // statements: main2_statements, + // signature: Signature { + // inputs: vec![], + // outputs: vec![Type::FieldElement], + // }, + // }; + + // let prog = Prog { + // functions: vec![main1, main2], + // imports: vec![], + // imported_functions: vec![], + // }; + + // let mut checker = Checker::new(); + // assert_eq!( + // checker.check_program(prog), + // Err(Error { + // message: "Only one main function allowed, found 2".to_string() + // }) + // ); + // } + + // #[test] + // fn shadowing_with_same_type() { + // // field a + // // field a + // // + // // should fail + + // let mut checker = Checker::new(); + // let _: Result, Error> = checker.check_statement( + // &Statement::Declaration(Variable::field_element("a")), + // &vec![], + // ); + // let s2_checked: Result, Error> = checker.check_statement( + // &Statement::Declaration(Variable::field_element("a")), + // &vec![], + // ); + // assert_eq!( + // s2_checked, + // Err(Error { + // message: "Duplicate declaration for variable named a".to_string() + // }) + // ); + // } + + // #[test] + // fn shadowing_with_different_type() { + // // field a + // // bool a + // // + // // should fail + + // let mut checker = Checker::new(); + // let _: Result, Error> = checker.check_statement( + // &Statement::Declaration(Variable::field_element("a")), + // &vec![], + // ); + // let s2_checked: Result, Error> = + // checker.check_statement(&Statement::Declaration(Variable::boolean("a")), &vec![]); + // assert_eq!( + // s2_checked, + // Err(Error { + // message: "Duplicate declaration for variable named a".to_string() + // }) + // ); + // } + + // mod assignee { + // use super::*; + + // #[test] + // fn identifier() { + // // a = 42 + // let a = Assignee::Identifier::(String::from("a")); + + // let mut checker: Checker = Checker::new(); + // checker + // .check_statement::( + // &Statement::Declaration(Variable::field_element("a")), + // &vec![], + // ) + // .unwrap(); + + // assert_eq!( + // checker.check_assignee(&a), + // Ok(TypedAssignee::Identifier(Variable::field_element("a"))) + // ); + // } + + // #[test] + // fn array_element() { + // // field[33] a + // // a[2] = 42 + // let a = Assignee::ArrayElement( + // box Assignee::Identifier(String::from("a")), + // box Expression::Number(FieldPrime::from(2)), + // ); + + // let mut checker: Checker = Checker::new(); + // checker + // .check_statement::( + // &Statement::Declaration(Variable::field_array("a", 33)), + // &vec![], + // ) + // .unwrap(); + + // assert_eq!( + // checker.check_assignee(&a), + // Ok(TypedAssignee::ArrayElement( + // box TypedAssignee::Identifier(Variable::field_array("a", 33)), + // box FieldElementExpression::Number(FieldPrime::from(2)).into() + // )) + // ); + // } + // } } diff --git a/zokrates_core/src/static_analysis/inline.rs b/zokrates_core/src/static_analysis/inline.rs index f6a762c8..dbf4af45 100644 --- a/zokrates_core/src/static_analysis/inline.rs +++ b/zokrates_core/src/static_analysis/inline.rs @@ -262,7 +262,6 @@ mod tests { #[cfg(test)] mod heuristics { use super::*; - use absy::{Parameter, Variable}; #[test] fn inline_constant_field() { diff --git a/zokrates_core/src/static_analysis/propagation.rs b/zokrates_core/src/static_analysis/propagation.rs index b4296768..eabc0a59 100644 --- a/zokrates_core/src/static_analysis/propagation.rs +++ b/zokrates_core/src/static_analysis/propagation.rs @@ -4,7 +4,6 @@ //! @author Thibaut Schaeffer //! @date 2018 -use absy::variable::Variable; use std::collections::HashMap; use typed_absy::folder::*; use typed_absy::*; diff --git a/zokrates_core/src/static_analysis/unroll.rs b/zokrates_core/src/static_analysis/unroll.rs index df594539..1d5e8f8e 100644 --- a/zokrates_core/src/static_analysis/unroll.rs +++ b/zokrates_core/src/static_analysis/unroll.rs @@ -4,7 +4,6 @@ //! @author Thibaut Schaeffer //! @date 2018 -use absy::variable::Variable; use std::collections::HashMap; use typed_absy::folder::*; use typed_absy::*; diff --git a/zokrates_core/src/typed_absy/folder.rs b/zokrates_core/src/typed_absy/folder.rs index 074502b7..6117fbcb 100644 --- a/zokrates_core/src/typed_absy/folder.rs +++ b/zokrates_core/src/typed_absy/folder.rs @@ -1,6 +1,5 @@ // Generic walk through a typed AST. Not mutating in place -use absy::variable::Variable; use typed_absy::*; use zokrates_field::field::Field; diff --git a/zokrates_core/src/typed_absy/mod.rs b/zokrates_core/src/typed_absy/mod.rs index dc8d4c80..2193b2dc 100644 --- a/zokrates_core/src/typed_absy/mod.rs +++ b/zokrates_core/src/typed_absy/mod.rs @@ -6,9 +6,11 @@ //! @date 2017 pub mod folder; +mod parameter; +mod variable; -use absy::parameter::Parameter; -use absy::variable::Variable; +pub use typed_absy::parameter::Parameter; +pub use typed_absy::variable::Variable; use types::Signature; use flat_absy::*; diff --git a/zokrates_core/src/typed_absy/parameter.rs b/zokrates_core/src/typed_absy/parameter.rs new file mode 100644 index 00000000..735b2514 --- /dev/null +++ b/zokrates_core/src/typed_absy/parameter.rs @@ -0,0 +1,41 @@ +use absy; +use std::fmt; +use typed_absy::Variable; + +#[derive(Clone, PartialEq, Serialize, Deserialize)] +pub struct Parameter { + pub id: Variable, + pub private: bool, +} + +impl Parameter { + #[cfg(test)] + pub fn private(v: Variable) -> Self { + Parameter { + id: v, + private: true, + } + } +} + +impl fmt::Display for Parameter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let visibility = if self.private { "private " } else { "" }; + write!(f, "{}{} {}", visibility, self.id.get_type(), self.id.id) + } +} + +impl fmt::Debug for Parameter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Parameter(variable: {:?})", self.id) + } +} + +impl From for Parameter { + fn from(p: absy::Parameter) -> Parameter { + Parameter { + private: p.private, + id: p.id.value.into(), + } + } +} diff --git a/zokrates_core/src/typed_absy/variable.rs b/zokrates_core/src/typed_absy/variable.rs new file mode 100644 index 00000000..1e3b2520 --- /dev/null +++ b/zokrates_core/src/typed_absy/variable.rs @@ -0,0 +1,57 @@ +use absy; +use std::fmt; +use types::Type; + +#[derive(Serialize, Deserialize, Clone, PartialEq, Hash, Eq)] +pub struct Variable { + pub id: String, + pub _type: Type, +} + +impl Variable { + pub fn field_element>(id: S) -> Variable { + Variable { + id: id.into(), + _type: Type::FieldElement, + } + } + + pub fn boolean>(id: S) -> Variable { + Variable { + id: id.into(), + _type: Type::Boolean, + } + } + + pub fn field_array>(id: S, size: usize) -> Variable { + Variable { + id: id.into(), + _type: Type::FieldElementArray(size), + } + } + + pub fn get_type(&self) -> Type { + self._type.clone() + } +} + +impl fmt::Display for Variable { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} {}", self._type, self.id,) + } +} + +impl fmt::Debug for Variable { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Variable(type: {:?}, id: {:?})", self._type, self.id,) + } +} + +impl From for Variable { + fn from(v: absy::Variable) -> Variable { + Variable { + id: v.id, + _type: v._type, + } + } +} diff --git a/zokrates_core/tests/utils/mod.rs b/zokrates_core/tests/utils/mod.rs index 840bc675..ab9529b0 100644 --- a/zokrates_core/tests/utils/mod.rs +++ b/zokrates_core/tests/utils/mod.rs @@ -1,7 +1,7 @@ extern crate serde_json; use std::io; -use zokrates_core::compile::{compile as generic_compile, CompileError}; +use zokrates_core::compile::{compile as generic_compile, CompileErrors}; use zokrates_core::ir; use zokrates_field::field::{Field, FieldPrime}; @@ -80,7 +80,7 @@ pub fn read_file(path: &str) -> String { contents } -pub fn compile(code: &str) -> Result, CompileError> { +pub fn compile(code: &str) -> Result, CompileErrors> { generic_compile::(&mut code.as_bytes(), None, None) }