Merge pull request #224 from Zokrates/useful-semantic-errors
Output more, better errors in the CLI
This commit is contained in:
commit
033217b520
26 changed files with 2081 additions and 1336 deletions
|
@ -41,4 +41,4 @@ WORKDIR /home/zokrates
|
|||
COPY --chown=zokrates:zokrates . ZoKrates
|
||||
|
||||
RUN cd ZoKrates \
|
||||
&& ./build.sh
|
||||
# && ./build.sh
|
||||
|
|
|
@ -224,7 +224,7 @@ fn cli() -> Result<(), String> {
|
|||
|
||||
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());
|
||||
|
||||
|
@ -248,7 +248,7 @@ fn cli() -> Result<(), String> {
|
|||
|
||||
let program_flattened: ir::Prog<FieldPrime> =
|
||||
compile(&mut reader, Some(location), Some(fs_resolve))
|
||||
.map_err(|e| format!("Compilation failed: {}", e))?;
|
||||
.map_err(|e| format!("Compilation failed:\n\n {}", e))?;
|
||||
|
||||
// number of constraints the flattened program will translate to.
|
||||
let num_constraints = program_flattened.constraint_count();
|
||||
|
|
|
@ -5,23 +5,25 @@
|
|||
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
|
||||
//! @date 2017
|
||||
|
||||
mod node;
|
||||
pub mod parameter;
|
||||
pub mod variable;
|
||||
|
||||
pub use absy::parameter::Parameter;
|
||||
pub use absy::variable::Variable;
|
||||
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<T: Field> {
|
||||
/// Functions of the program
|
||||
pub functions: Vec<Function<T>>,
|
||||
pub imports: Vec<Import>,
|
||||
pub functions: Vec<FunctionNode<T>>,
|
||||
pub imports: Vec<ImportNode>,
|
||||
pub imported_functions: Vec<FlatFunction<T>>,
|
||||
}
|
||||
|
||||
|
@ -79,13 +81,15 @@ pub struct Function<T: Field> {
|
|||
/// Name of the program
|
||||
pub id: String,
|
||||
/// Arguments of the function
|
||||
pub arguments: Vec<Parameter>,
|
||||
pub arguments: Vec<ParameterNode>,
|
||||
/// Vector of statements that are executed when running the function
|
||||
pub statements: Vec<Statement<T>>,
|
||||
pub statements: Vec<StatementNode<T>>,
|
||||
/// function signature
|
||||
pub signature: Signature,
|
||||
}
|
||||
|
||||
pub type FunctionNode<T> = Node<Function<T>>;
|
||||
|
||||
impl<T: Field> fmt::Display for Function<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
|
@ -125,9 +129,11 @@ impl<T: Field> fmt::Debug for Function<T> {
|
|||
#[derive(Clone, PartialEq)]
|
||||
pub enum Assignee<T: Field> {
|
||||
Identifier(String),
|
||||
ArrayElement(Box<Assignee<T>>, Box<Expression<T>>),
|
||||
ArrayElement(Box<AssigneeNode<T>>, Box<ExpressionNode<T>>),
|
||||
}
|
||||
|
||||
pub type AssigneeNode<T> = Node<Assignee<T>>;
|
||||
|
||||
impl<T: Field> fmt::Debug for Assignee<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
@ -143,12 +149,24 @@ impl<T: Field> fmt::Display for Assignee<T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<Expression<T>> for Assignee<T> {
|
||||
fn from(e: Expression<T>) -> Self {
|
||||
match e {
|
||||
Expression::Select(box Expression::Identifier(id), box e2) => {
|
||||
Assignee::ArrayElement(box Assignee::Identifier(id), box e2)
|
||||
}
|
||||
impl<T: Field> From<ExpressionNode<T>> for AssigneeNode<T> {
|
||||
fn from(e: ExpressionNode<T>) -> Self {
|
||||
match e.value {
|
||||
Expression::Select(box e1, box e2) => match e1 {
|
||||
ExpressionNode {
|
||||
value: Expression::Identifier(id),
|
||||
start,
|
||||
end,
|
||||
} => Node::new(
|
||||
e.start,
|
||||
e.end,
|
||||
Assignee::ArrayElement(
|
||||
box Node::new(start, end, Assignee::Identifier(id)),
|
||||
box e2,
|
||||
),
|
||||
),
|
||||
_ => panic!("only use expression to assignee for elements like foo[bar]"),
|
||||
},
|
||||
_ => panic!("only use expression to assignee for elements like foo[bar]"),
|
||||
}
|
||||
}
|
||||
|
@ -156,14 +174,16 @@ impl<T: Field> From<Expression<T>> for Assignee<T> {
|
|||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Statement<T: Field> {
|
||||
Return(ExpressionList<T>),
|
||||
Declaration(Variable),
|
||||
Definition(Assignee<T>, Expression<T>),
|
||||
Condition(Expression<T>, Expression<T>),
|
||||
For(Variable, T, T, Vec<Statement<T>>),
|
||||
MultipleDefinition(Vec<Assignee<T>>, Expression<T>),
|
||||
Return(ExpressionListNode<T>),
|
||||
Declaration(VariableNode),
|
||||
Definition(AssigneeNode<T>, ExpressionNode<T>),
|
||||
Condition(ExpressionNode<T>, ExpressionNode<T>),
|
||||
For(VariableNode, T, T, Vec<StatementNode<T>>),
|
||||
MultipleDefinition(Vec<AssigneeNode<T>>, ExpressionNode<T>),
|
||||
}
|
||||
|
||||
pub type StatementNode<T> = Node<Statement<T>>;
|
||||
|
||||
impl<T: Field> fmt::Display for Statement<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
@ -218,25 +238,31 @@ impl<T: Field> fmt::Debug for Statement<T> {
|
|||
pub enum Expression<T: Field> {
|
||||
Number(T),
|
||||
Identifier(String),
|
||||
Add(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Sub(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Mult(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Div(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Pow(Box<Expression<T>>, Box<Expression<T>>),
|
||||
IfElse(Box<Expression<T>>, Box<Expression<T>>, Box<Expression<T>>),
|
||||
FunctionCall(String, Vec<Expression<T>>),
|
||||
Lt(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Le(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Eq(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Ge(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Gt(Box<Expression<T>>, Box<Expression<T>>),
|
||||
And(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Not(Box<Expression<T>>),
|
||||
InlineArray(Vec<Expression<T>>),
|
||||
Select(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Or(Box<Expression<T>>, Box<Expression<T>>),
|
||||
Add(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
Sub(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
Mult(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
Div(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
Pow(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
IfElse(
|
||||
Box<ExpressionNode<T>>,
|
||||
Box<ExpressionNode<T>>,
|
||||
Box<ExpressionNode<T>>,
|
||||
),
|
||||
FunctionCall(String, Vec<ExpressionNode<T>>),
|
||||
Lt(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
Le(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
Eq(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
Ge(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
Gt(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
And(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
Not(Box<ExpressionNode<T>>),
|
||||
InlineArray(Vec<ExpressionNode<T>>),
|
||||
Select(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
Or(Box<ExpressionNode<T>>, Box<ExpressionNode<T>>),
|
||||
}
|
||||
|
||||
pub type ExpressionNode<T> = Node<Expression<T>>;
|
||||
|
||||
impl<T: Field> fmt::Display for Expression<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
|
@ -325,9 +351,11 @@ impl<T: Field> fmt::Debug for Expression<T> {
|
|||
|
||||
#[derive(Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct ExpressionList<T: Field> {
|
||||
pub expressions: Vec<Expression<T>>,
|
||||
pub expressions: Vec<ExpressionNode<T>>,
|
||||
}
|
||||
|
||||
pub type ExpressionListNode<T> = Node<ExpressionList<T>>;
|
||||
|
||||
impl<T: Field> ExpressionList<T> {
|
||||
pub fn new() -> ExpressionList<T> {
|
||||
ExpressionList {
|
||||
|
|
62
zokrates_core/src/absy/node.rs
Normal file
62
zokrates_core/src/absy/node.rs
Normal file
|
@ -0,0 +1,62 @@
|
|||
use parser::Position;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Node<T: fmt::Display> {
|
||||
pub start: Position,
|
||||
pub end: Position,
|
||||
pub value: T,
|
||||
}
|
||||
|
||||
impl<T: fmt::Display> Node<T> {
|
||||
pub fn pos(&self) -> (Position, Position) {
|
||||
(self.start, self.end)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display> fmt::Display for Node<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.value)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: fmt::Display> Node<T> {
|
||||
pub fn new(start: Position, end: Position, value: T) -> Node<T> {
|
||||
Node { start, end, value }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NodeValue: fmt::Display + Sized + PartialEq {
|
||||
fn at(self, line: usize, col: usize, delta: isize) -> Node<Self> {
|
||||
let start = Position { col, line };
|
||||
Node::new(start, start.col(delta), self)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl<V: NodeValue> From<V> for Node<V> {
|
||||
fn from(v: V) -> Node<V> {
|
||||
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<T: Field> NodeValue for Expression<T> {}
|
||||
impl<T: Field> NodeValue for ExpressionList<T> {}
|
||||
impl<T: Field> NodeValue for Assignee<T> {}
|
||||
impl<T: Field> NodeValue for Statement<T> {}
|
||||
impl<T: Field> NodeValue for Function<T> {}
|
||||
impl<T: Field> NodeValue for Prog<T> {}
|
||||
impl NodeValue for Variable {}
|
||||
impl NodeValue for Parameter {}
|
||||
impl NodeValue for Import {}
|
||||
|
||||
impl<T: NodeValue> std::cmp::PartialEq for Node<T> {
|
||||
fn eq(&self, other: &Node<T>) -> bool {
|
||||
self.value.eq(&other.value)
|
||||
}
|
||||
}
|
|
@ -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<Parameter>;
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
use absy::Node;
|
||||
use std::fmt;
|
||||
use types::Type;
|
||||
|
||||
|
@ -7,6 +8,8 @@ pub struct Variable {
|
|||
pub _type: Type,
|
||||
}
|
||||
|
||||
pub type VariableNode = Node<Variable>;
|
||||
|
||||
impl Variable {
|
||||
pub fn new<S: Into<String>>(id: S, t: Type) -> Variable {
|
||||
Variable {
|
||||
|
|
|
@ -18,44 +18,106 @@ use std::io::BufRead;
|
|||
use zokrates_field::field::Field;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CompileError<T: Field> {
|
||||
pub struct CompileErrors<T: Field>(Vec<CompileError<T>>);
|
||||
|
||||
impl<T: Field> From<CompileError<T>> for CompileErrors<T> {
|
||||
fn from(e: CompileError<T>) -> CompileErrors<T> {
|
||||
CompileErrors(vec![e])
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for CompileErrors<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
self.0
|
||||
.iter()
|
||||
.map(|e| format!("{}", e))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\n")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum CompileErrorInner<T: Field> {
|
||||
ParserError(parser::Error<T>),
|
||||
ImportError(imports::Error),
|
||||
SemanticError(semantics::Error),
|
||||
ReadError(io::Error),
|
||||
}
|
||||
|
||||
impl<T: Field> From<parser::Error<T>> for CompileError<T> {
|
||||
fn from(error: parser::Error<T>) -> Self {
|
||||
CompileError::ParserError(error)
|
||||
impl<T: Field> CompileErrorInner<T> {
|
||||
pub fn with_context(self, context: &Option<String>) -> CompileError<T> {
|
||||
CompileError {
|
||||
value: self,
|
||||
context: context.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<imports::Error> for CompileError<T> {
|
||||
fn from(error: imports::Error) -> Self {
|
||||
CompileError::ImportError(error)
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub struct CompileError<T: Field> {
|
||||
context: Option<String>,
|
||||
value: CompileErrorInner<T>,
|
||||
}
|
||||
|
||||
impl<T: Field> From<io::Error> for CompileError<T> {
|
||||
fn from(error: io::Error) -> Self {
|
||||
CompileError::ReadError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<semantics::Error> for CompileError<T> {
|
||||
fn from(error: semantics::Error) -> Self {
|
||||
CompileError::SemanticError(error)
|
||||
impl<T: Field> CompileErrors<T> {
|
||||
pub fn with_context(self, context: Option<String>) -> Self {
|
||||
CompileErrors(
|
||||
self.0
|
||||
.into_iter()
|
||||
.map(|e| CompileError {
|
||||
context: context.clone(),
|
||||
..e
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for CompileError<T> {
|
||||
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<T: Field> From<parser::Error<T>> for CompileErrorInner<T> {
|
||||
fn from(error: parser::Error<T>) -> Self {
|
||||
CompileErrorInner::ParserError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<imports::Error> for CompileErrorInner<T> {
|
||||
fn from(error: imports::Error) -> Self {
|
||||
CompileErrorInner::ImportError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<io::Error> for CompileErrorInner<T> {
|
||||
fn from(error: io::Error) -> Self {
|
||||
CompileErrorInner::ReadError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> From<semantics::Error> for CompileErrorInner<T> {
|
||||
fn from(error: semantics::Error) -> Self {
|
||||
CompileErrorInner::SemanticError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Field> fmt::Display for CompileErrorInner<T> {
|
||||
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: {}", 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<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
|
|||
reader: &mut R,
|
||||
location: Option<String>,
|
||||
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
|
||||
) -> Result<ir::Prog<T>, CompileError<T>> {
|
||||
) -> Result<ir::Prog<T>, CompileErrors<T>> {
|
||||
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<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
|
|||
reader: &mut R,
|
||||
location: Option<String>,
|
||||
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
|
||||
) -> Result<FlatProg<T>, CompileError<T>> {
|
||||
let program_ast_without_imports: Prog<T> = parse_program(reader)?;
|
||||
) -> Result<FlatProg<T>, CompileErrors<T>> {
|
||||
let program_ast_without_imports: Prog<T> = 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<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
|
|||
)?;
|
||||
|
||||
// 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<ir::Prog<FieldPrime>, CompileError<FieldPrime>> = compile(
|
||||
let res: Result<ir::Prog<FieldPrime>, CompileErrors<FieldPrime>> = compile(
|
||||
&mut r,
|
||||
Some(String::from("./path/to/file")),
|
||||
None::<
|
||||
|
@ -124,10 +196,11 @@ mod test {
|
|||
) -> Result<(BufReader<Empty>, 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<ir::Prog<FieldPrime>, CompileError<FieldPrime>> = compile(
|
||||
let res: Result<ir::Prog<FieldPrime>, CompileErrors<FieldPrime>> = compile(
|
||||
&mut r,
|
||||
Some(String::from("./path/to/file")),
|
||||
None::<
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
|
||||
//! @date 2017
|
||||
|
||||
use absy::parameter::Parameter;
|
||||
use absy::variable::Variable;
|
||||
use bimap::BiMap;
|
||||
use flat_absy::*;
|
||||
use helpers::{DirectiveStatement, Helper, RustHelper};
|
||||
|
@ -1437,6 +1435,7 @@ impl Flattener {
|
|||
|
||||
let mut arguments_flattened: Vec<FlatParameter> = Vec::new();
|
||||
let mut statements_flattened: Vec<FlatStatement<T>> = Vec::new();
|
||||
|
||||
// push parameters
|
||||
for arg in &funct.arguments {
|
||||
let arg_type = arg.id.get_type();
|
||||
|
@ -1549,7 +1548,6 @@ impl Flattener {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use absy::variable::Variable;
|
||||
use types::Signature;
|
||||
use types::Type;
|
||||
use zokrates_field::field::FieldPrime;
|
||||
|
|
|
@ -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<T: Field> CompiledImport<T> {
|
|||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Error {
|
||||
pos: Option<(Position, Position)>,
|
||||
message: String,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
pub fn new<T: Into<String>>(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<io::Error> 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<String>,
|
||||
}
|
||||
|
||||
pub type ImportNode = Node<Import>;
|
||||
|
||||
impl Import {
|
||||
pub fn new(source: String) -> Import {
|
||||
Import {
|
||||
|
@ -118,10 +132,12 @@ impl Importer {
|
|||
destination: Prog<T>,
|
||||
location: Option<String>,
|
||||
resolve_option: Option<fn(&Option<String>, &String) -> Result<(S, String, String), E>>,
|
||||
) -> Result<Prog<T>, CompileError<T>> {
|
||||
) -> Result<Prog<T>, CompileErrors<T>> {
|
||||
let mut origins: Vec<CompiledImport<T>> = 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")]
|
||||
|
@ -176,13 +192,18 @@ impl Importer {
|
|||
origins.push(CompiledImport::new(compiled, alias));
|
||||
}
|
||||
s => {
|
||||
return Err(CompileError::ImportError(Error::new(format!(
|
||||
"Gadget {} not found",
|
||||
s
|
||||
))));
|
||||
return Err(CompileErrorInner::ImportError(
|
||||
Error::new(format!("Gadget {} not found", s)).with_pos(Some(pos)),
|
||||
)
|
||||
.with_context(&location)
|
||||
.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "libsnark"))]
|
||||
{
|
||||
panic!("libsnark is not enabled, cannot access {}", import.source)
|
||||
}
|
||||
} else if import.source.starts_with("PACKING") {
|
||||
use types::conversions::{pack, unpack};
|
||||
|
||||
|
@ -204,10 +225,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 +238,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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ impl<T: Field> fmt::Display for Error<T> {
|
|||
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
|
||||
|
|
|
@ -4,3 +4,4 @@ mod tokenize;
|
|||
|
||||
pub use parser::error::Error;
|
||||
pub use parser::parse::parse_program;
|
||||
pub use parser::tokenize::Position;
|
||||
|
|
|
@ -3,21 +3,23 @@ use zokrates_field::field::Field;
|
|||
use parser::tokenize::{next_token, Position, Token};
|
||||
use parser::Error;
|
||||
|
||||
use absy::Expression;
|
||||
use absy::{Expression, ExpressionNode, Node};
|
||||
|
||||
fn parse_then_else<T: Field>(
|
||||
cond: Expression<T>,
|
||||
cond: ExpressionNode<T>,
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match next_token(input, pos) {
|
||||
(Token::Then, s5, p5) => match parse_expr(&s5, &p5) {
|
||||
Ok((e6, s6, p6)) => match next_token(&s6, &p6) {
|
||||
(Token::Else, s7, p7) => match parse_expr(&s7, &p7) {
|
||||
Ok((e8, s8, p8)) => match next_token(&s8, &p8) {
|
||||
(Token::Fi, s9, p9) => {
|
||||
parse_expr1(Expression::IfElse(box cond, box e6, box e8), s9, p9)
|
||||
}
|
||||
(Token::Fi, s9, p9) => parse_expr1(
|
||||
Node::new(cond.start, p9, Expression::IfElse(box cond, box e6, box e8)),
|
||||
s9,
|
||||
p9,
|
||||
),
|
||||
(t10, _, p10) => Err(Error {
|
||||
expected: vec![Token::Fi],
|
||||
got: t10,
|
||||
|
@ -45,27 +47,37 @@ fn parse_then_else<T: Field>(
|
|||
fn parse_prim_cond<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match parse_expr(input, pos) {
|
||||
Ok((e2, s2, p2)) => match next_token(&s2, &p2) {
|
||||
(Token::Lt, s3, p3) => match parse_expr(&s3, &p3) {
|
||||
Ok((e4, s4, p4)) => Ok((Expression::Lt(box e2, box e4), s4, p4)),
|
||||
Ok((e4, s4, p4)) => {
|
||||
Ok((Node::new(*pos, p4, Expression::Lt(box e2, box e4)), s4, p4))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Le, s3, p3) => match parse_expr(&s3, &p3) {
|
||||
Ok((e4, s4, p4)) => Ok((Expression::Le(box e2, box e4), s4, p4)),
|
||||
Ok((e4, s4, p4)) => {
|
||||
Ok((Node::new(*pos, p4, Expression::Le(box e2, box e4)), s4, p4))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Eqeq, s3, p3) => match parse_expr(&s3, &p3) {
|
||||
Ok((e4, s4, p4)) => Ok((Expression::Eq(box e2, box e4), s4, p4)),
|
||||
Ok((e4, s4, p4)) => {
|
||||
Ok((Node::new(*pos, p4, Expression::Eq(box e2, box e4)), s4, p4))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Ge, s3, p3) => match parse_expr(&s3, &p3) {
|
||||
Ok((e4, s4, p4)) => Ok((Expression::Ge(box e2, box e4), s4, p4)),
|
||||
Ok((e4, s4, p4)) => {
|
||||
Ok((Node::new(*pos, p4, Expression::Ge(box e2, box e4)), s4, p4))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Gt, s3, p3) => match parse_expr(&s3, &p3) {
|
||||
Ok((e4, s4, p4)) => Ok((Expression::Gt(box e2, box e4), s4, p4)),
|
||||
Ok((e4, s4, p4)) => {
|
||||
Ok((Node::new(*pos, p4, Expression::Gt(box e2, box e4)), s4, p4))
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(t3, _, p3) => Err(Error {
|
||||
|
@ -81,11 +93,11 @@ fn parse_prim_cond<T: Field>(
|
|||
fn parse_bfactor<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match next_token::<T>(input, pos) {
|
||||
(Token::Not, s1, p1) => match next_token(&s1, &p1) {
|
||||
(Token::Open, _, _) => match parse_bfactor(&s1, &p1) {
|
||||
Ok((e3, s3, p3)) => Ok((Expression::Not(box e3), s3, p3)),
|
||||
Ok((e3, s3, p3)) => Ok((Node::new(*pos, p3, Expression::Not(box e3)), s3, p3)),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(t2, _, p2) => Err(Error {
|
||||
|
@ -110,13 +122,13 @@ fn parse_bfactor<T: Field>(
|
|||
}
|
||||
|
||||
pub fn parse_bterm1<T: Field>(
|
||||
expr: Expression<T>,
|
||||
expr: ExpressionNode<T>,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match next_token::<T>(&input, &pos) {
|
||||
(Token::And, s1, p1) => match parse_bterm(&s1, &p1) {
|
||||
Ok((e, s2, p2)) => Ok((Expression::And(box expr, box e), s2, p2)),
|
||||
Ok((e, s2, p2)) => Ok((Node::new(pos, p2, Expression::And(box expr, box e)), s2, p2)),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
_ => Ok((expr, input, pos)),
|
||||
|
@ -126,7 +138,7 @@ pub fn parse_bterm1<T: Field>(
|
|||
fn parse_bterm<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match parse_bfactor(input, pos) {
|
||||
Ok((e, s1, p1)) => parse_bterm1(e, s1, p1),
|
||||
Err(err) => Err(err),
|
||||
|
@ -134,13 +146,15 @@ fn parse_bterm<T: Field>(
|
|||
}
|
||||
|
||||
fn parse_bexpr1<T: Field>(
|
||||
expr: Expression<T>,
|
||||
expr: ExpressionNode<T>,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match next_token::<T>(&input, &pos) {
|
||||
(Token::Or, s1, p1) => match parse_bterm(&s1, &p1) {
|
||||
Ok((e2, s2, p2)) => parse_bexpr1(Expression::Or(box expr, box e2), s2, p2),
|
||||
Ok((e2, s2, p2)) => {
|
||||
parse_bexpr1(Node::new(pos, p2, Expression::Or(box expr, box e2)), s2, p2)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
_ => Ok((expr, input, pos)),
|
||||
|
@ -150,15 +164,17 @@ fn parse_bexpr1<T: Field>(
|
|||
fn parse_bexpr<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match next_token::<T>(input, pos) {
|
||||
(Token::Not, s1, p1) => match next_token(&s1, &p1) {
|
||||
(Token::Open, s2, p2) => match parse_bexpr(&s2, &p2) {
|
||||
Ok((e3, s3, p3)) => match next_token(&s3, &p3) {
|
||||
(Token::Close, s4, p4) => match parse_bterm1(Expression::Not(box e3), s4, p4) {
|
||||
Ok((e5, s5, p5)) => parse_bexpr1(e5, s5, p5),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Close, s4, p4) => {
|
||||
match parse_bterm1(Node::new(*pos, p4, Expression::Not(box e3)), s4, p4) {
|
||||
Ok((e5, s5, p5)) => parse_bexpr1(e5, s5, p5),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
(t4, _, p4) => Err(Error {
|
||||
expected: vec![Token::Close],
|
||||
got: t4,
|
||||
|
@ -211,7 +227,7 @@ fn parse_bexpr<T: Field>(
|
|||
fn parse_if_then_else<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match next_token(input, pos) {
|
||||
(Token::If, s1, p1) => match parse_bexpr(&s1, &p1) {
|
||||
Ok((e2, s2, p2)) => parse_then_else(e2, &s2, &p2),
|
||||
|
@ -226,17 +242,23 @@ fn parse_if_then_else<T: Field>(
|
|||
}
|
||||
|
||||
fn parse_factor1<T: Field>(
|
||||
expr: Expression<T>,
|
||||
expr: ExpressionNode<T>,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match parse_term1(expr.clone(), input.clone(), pos.clone()) {
|
||||
Ok((e1, s1, p1)) => match parse_expr1(e1, s1, p1) {
|
||||
Ok((e2, s2, p2)) => match next_token::<T>(&s2, &p2) {
|
||||
(Token::Pow, s3, p3) => match next_token(&s3, &p3) {
|
||||
(Token::Num(x), s4, p4) => {
|
||||
Ok((Expression::Pow(box e2, box Expression::Number(x)), s4, p4))
|
||||
}
|
||||
(Token::Num(x), s4, p4) => Ok((
|
||||
Node::new(
|
||||
pos,
|
||||
p4,
|
||||
Expression::Pow(box e2, box Node::new(p3, p4, Expression::Number(x))),
|
||||
),
|
||||
s4,
|
||||
p4,
|
||||
)),
|
||||
(t4, _, p4) => Err(Error {
|
||||
expected: vec![Token::ErrNum],
|
||||
got: t4,
|
||||
|
@ -256,18 +278,26 @@ fn parse_identified1<T: Field>(
|
|||
x: String,
|
||||
input: String,
|
||||
position: Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
let ide_initial_pos = Position {
|
||||
col: position.col - x.len(),
|
||||
..position
|
||||
};
|
||||
match next_token::<T>(&input, &position) {
|
||||
(Token::Open, s1, p1) => parse_function_call(x, s1, p1),
|
||||
(Token::LeftBracket, s1, p1) => parse_array_select(x, s1, p1),
|
||||
_ => Ok((Expression::Identifier(x), input, position)),
|
||||
_ => Ok((
|
||||
Node::new(ide_initial_pos, position, Expression::Identifier(x)),
|
||||
input,
|
||||
position,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_factor<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match next_token(input, pos) {
|
||||
(Token::If, ..) => parse_if_then_else(input, pos),
|
||||
(Token::Open, s1, p1) => match parse_expr(&s1, &p1) {
|
||||
|
@ -285,7 +315,9 @@ fn parse_factor<T: Field>(
|
|||
Ok((e2, s2, p2)) => parse_factor1(e2, s2, p2),
|
||||
e => e,
|
||||
},
|
||||
(Token::Num(x), s1, p1) => parse_factor1(Expression::Number(x), s1, p1),
|
||||
(Token::Num(x), s1, p1) => {
|
||||
parse_factor1(Node::new(*pos, p1, Expression::Number(x)), s1, p1)
|
||||
}
|
||||
(t1, _, p1) => Err(Error {
|
||||
expected: vec![Token::If, Token::Open, Token::ErrIde, Token::ErrNum],
|
||||
got: t1,
|
||||
|
@ -295,17 +327,25 @@ fn parse_factor<T: Field>(
|
|||
}
|
||||
|
||||
pub fn parse_term1<T: Field>(
|
||||
expr: Expression<T>,
|
||||
expr: ExpressionNode<T>,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match next_token::<T>(&input, &pos) {
|
||||
(Token::Mult, s1, p1) => match parse_term(&s1, &p1) {
|
||||
Ok((e, s2, p2)) => Ok((Expression::Mult(box expr, box e), s2, p2)),
|
||||
Ok((e, s2, p2)) => Ok((
|
||||
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((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)),
|
||||
|
@ -315,7 +355,7 @@ pub fn parse_term1<T: Field>(
|
|||
fn parse_term<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match parse_factor(input, pos) {
|
||||
Ok((e, s1, p1)) => parse_term1(e, s1, p1),
|
||||
Err(err) => Err(err),
|
||||
|
@ -323,21 +363,33 @@ fn parse_term<T: Field>(
|
|||
}
|
||||
|
||||
pub fn parse_expr1<T: Field>(
|
||||
expr: Expression<T>,
|
||||
expr: ExpressionNode<T>,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match next_token::<T>(&input, &pos) {
|
||||
(Token::Add, s1, p1) => match parse_term(&s1, &p1) {
|
||||
Ok((e2, s2, p2)) => parse_expr1(Expression::Add(box expr, box e2), s2, p2),
|
||||
Ok((e2, s2, p2)) => parse_expr1(
|
||||
Node::new(expr.start, p2, Expression::Add(box expr, box e2)),
|
||||
s2,
|
||||
p2,
|
||||
),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Sub, s1, p1) => match parse_term(&s1, &p1) {
|
||||
Ok((e2, s2, p2)) => parse_expr1(Expression::Sub(box expr, box e2), s2, p2),
|
||||
Ok((e2, s2, p2)) => parse_expr1(
|
||||
Node::new(expr.start, p2, Expression::Sub(box expr, box e2)),
|
||||
s2,
|
||||
p2,
|
||||
),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Pow, s1, p1) => match parse_term(&s1, &p1) {
|
||||
Ok((e, s2, p2)) => match parse_term1(Expression::Pow(box expr, box e), s2, p2) {
|
||||
Ok((e, s2, p2)) => match parse_term1(
|
||||
Node::new(expr.start, p2, Expression::Pow(box expr, box e)),
|
||||
s2,
|
||||
p2,
|
||||
) {
|
||||
Ok((e3, s3, p3)) => parse_expr1(e3, s3, p3),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
|
@ -351,7 +403,13 @@ pub fn parse_function_call<T: Field>(
|
|||
ide: String,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
// 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;
|
||||
|
@ -361,7 +419,11 @@ pub fn parse_function_call<T: Field>(
|
|||
match next_token::<T>(&s, &p) {
|
||||
// no arguments
|
||||
(Token::Close, s1, p1) => {
|
||||
return parse_term1(Expression::FunctionCall(ide, args), s1, p1);
|
||||
return parse_term1(
|
||||
Node::new(start_pos, p1, Expression::FunctionCall(ide, args)),
|
||||
s1,
|
||||
p1,
|
||||
);
|
||||
}
|
||||
// at least one argument
|
||||
(_, _, _) => match parse_expr(&s, &p) {
|
||||
|
@ -373,7 +435,11 @@ pub fn parse_function_call<T: Field>(
|
|||
p = p2;
|
||||
}
|
||||
(Token::Close, s2, p2) => {
|
||||
return parse_term1(Expression::FunctionCall(ide, args), s2, p2);
|
||||
return parse_term1(
|
||||
Node::new(start_pos, p2, Expression::FunctionCall(ide, args)),
|
||||
s2,
|
||||
p2,
|
||||
);
|
||||
}
|
||||
(t2, _, p2) => {
|
||||
return Err(Error {
|
||||
|
@ -393,7 +459,7 @@ pub fn parse_function_call<T: Field>(
|
|||
pub fn parse_inline_array<T: Field>(
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
// function call can have 0 .. n args
|
||||
let mut expressions = Vec::new();
|
||||
let mut s: String = input;
|
||||
|
@ -403,7 +469,11 @@ pub fn parse_inline_array<T: Field>(
|
|||
match next_token::<T>(&s, &p) {
|
||||
// no arguments
|
||||
(Token::RightBracket, s1, p1) => {
|
||||
match parse_term1(Expression::InlineArray(expressions), s1, p1) {
|
||||
match parse_term1(
|
||||
Node::new(pos, p1, Expression::InlineArray(expressions)),
|
||||
s1,
|
||||
p1,
|
||||
) {
|
||||
Ok((e2, s2, p2)) => return parse_expr1(e2, s2, p2),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
@ -418,7 +488,11 @@ pub fn parse_inline_array<T: Field>(
|
|||
p = p2;
|
||||
}
|
||||
(Token::RightBracket, s2, p2) => {
|
||||
match parse_term1(Expression::InlineArray(expressions), s2, p2) {
|
||||
match parse_term1(
|
||||
Node::new(pos, p2, Expression::InlineArray(expressions)),
|
||||
s2,
|
||||
p2,
|
||||
) {
|
||||
Ok((e3, s3, p3)) => return parse_expr1(e3, s3, p3),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
@ -442,13 +516,25 @@ pub fn parse_array_select<T: Field>(
|
|||
ide: String,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
let start_pos = Position {
|
||||
col: pos.col - ide.len() - 1,
|
||||
..pos
|
||||
};
|
||||
|
||||
// array select can have exactly one arg
|
||||
match next_token::<T>(&input, &pos) {
|
||||
(_, _, _) => match parse_expr(&input, &pos) {
|
||||
Ok((e1, s1, p1)) => match next_token::<T>(&s1, &p1) {
|
||||
(Token::RightBracket, s2, p2) => parse_term1(
|
||||
Expression::Select(box Expression::Identifier(ide), box e1),
|
||||
Node::new(
|
||||
pos,
|
||||
p2,
|
||||
Expression::Select(
|
||||
box Node::new(start_pos, p1, Expression::Identifier(ide)),
|
||||
box e1,
|
||||
),
|
||||
),
|
||||
s2,
|
||||
p2,
|
||||
),
|
||||
|
@ -466,7 +552,7 @@ pub fn parse_array_select<T: Field>(
|
|||
pub fn parse_expr<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Expression<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionNode<T>, String, Position), Error<T>> {
|
||||
match next_token::<T>(input, pos) {
|
||||
(Token::If, ..) => parse_if_then_else(input, pos),
|
||||
(Token::Open, s1, p1) => match parse_expr(&s1, &p1) {
|
||||
|
@ -490,10 +576,12 @@ pub fn parse_expr<T: Field>(
|
|||
},
|
||||
e => e,
|
||||
},
|
||||
(Token::Num(x), s1, p1) => match parse_term1(Expression::Number(x), s1, p1) {
|
||||
Ok((e2, s2, p2)) => parse_expr1(e2, s2, p2),
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Num(x), s1, p1) => {
|
||||
match parse_term1(Node::new(*pos, p1, Expression::Number(x)), s1, p1) {
|
||||
Ok((e2, s2, p2)) => parse_expr1(e2, s2, p2),
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
(Token::LeftBracket, s1, p1) => parse_inline_array(s1, p1),
|
||||
(t1, _, p1) => Err(Error {
|
||||
expected: vec![Token::If, Token::Open, Token::ErrIde, Token::ErrNum],
|
||||
|
@ -517,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)
|
||||
|
@ -534,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)
|
||||
|
@ -550,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)
|
||||
|
@ -568,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)
|
||||
|
@ -585,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)
|
||||
|
@ -602,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)
|
||||
|
@ -622,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)
|
||||
|
@ -642,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)
|
||||
|
@ -659,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)
|
||||
|
@ -677,12 +785,14 @@ mod tests {
|
|||
let string = String::from("if a < b then c else d fi");
|
||||
let expr = Expression::IfElse::<FieldPrime>(
|
||||
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)
|
||||
|
@ -697,26 +807,33 @@ mod tests {
|
|||
let expr = Expression::IfElse::<FieldPrime>(
|
||||
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))),
|
||||
|
@ -732,12 +849,14 @@ mod tests {
|
|||
let pos = Position { line: 45, col: 121 };
|
||||
let string = String::from("foo[42 + 33]");
|
||||
let expr = Expression::Select::<FieldPrime>(
|
||||
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)
|
||||
|
@ -766,20 +885,25 @@ mod tests {
|
|||
let expr = Expression::IfElse::<FieldPrime>(
|
||||
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)
|
||||
|
@ -793,20 +917,25 @@ mod tests {
|
|||
let string = String::from("2 == 3 || 4 == 5 && 6 == 7");
|
||||
let expr = Or::<FieldPrime>(
|
||||
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)
|
||||
|
@ -822,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)
|
||||
|
@ -863,12 +1002,14 @@ mod tests {
|
|||
let string = String::from("if a < b then c else d fi");
|
||||
let expr = Expression::IfElse::<FieldPrime>(
|
||||
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)
|
||||
|
@ -879,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)
|
||||
|
@ -894,7 +1037,7 @@ mod tests {
|
|||
fn ide() {
|
||||
let pos = Position { line: 45, col: 121 };
|
||||
let string = String::from("a");
|
||||
let expr = Expression::Identifier::<FieldPrime>(String::from("a"));
|
||||
let expr = Expression::Identifier::<FieldPrime>(String::from("a")).into();
|
||||
assert_eq!(
|
||||
Ok((expr, String::from(""), pos.col(string.len() as isize))),
|
||||
parse_factor(&string, &pos)
|
||||
|
@ -904,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)
|
||||
|
|
|
@ -5,13 +5,13 @@ use parser::Error;
|
|||
|
||||
use super::expression::parse_expr;
|
||||
|
||||
use absy::ExpressionList;
|
||||
use absy::{ExpressionList, ExpressionListNode, Node};
|
||||
|
||||
// parse an expression list
|
||||
pub fn parse_expression_list<T: Field>(
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(ExpressionList<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionListNode<T>, String, Position), Error<T>> {
|
||||
let mut res = ExpressionList::new();
|
||||
parse_comma_separated_expression_list_rec(input, pos, &mut res)
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ fn parse_comma_separated_expression_list_rec<T: Field>(
|
|||
input: String,
|
||||
pos: Position,
|
||||
mut acc: &mut ExpressionList<T>,
|
||||
) -> Result<(ExpressionList<T>, String, Position), Error<T>> {
|
||||
) -> Result<(ExpressionListNode<T>, String, Position), Error<T>> {
|
||||
match parse_expr(&input, &pos) {
|
||||
Ok((e1, s1, p1)) => {
|
||||
acc.expressions.push(e1);
|
||||
|
@ -28,7 +28,7 @@ fn parse_comma_separated_expression_list_rec<T: Field>(
|
|||
(Token::Comma, s2, p2) => {
|
||||
parse_comma_separated_expression_list_rec(s2, p2, &mut acc)
|
||||
}
|
||||
(..) => Ok((acc.clone(), s1, p1)),
|
||||
(..) => Ok((Node::new(pos, p1, acc.clone()), s1, p1)),
|
||||
}
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
|
@ -44,8 +44,8 @@ mod tests {
|
|||
fn parse_comma_separated_list<T: Field>(
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(ExpressionList<T>, String, Position), Error<T>> {
|
||||
let mut res = ExpressionList::new();
|
||||
) -> Result<(ExpressionListNode<T>, String, Position), Error<T>> {
|
||||
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::<FieldPrime> {
|
||||
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::<FieldPrime>(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::<FieldPrime>(string, pos)
|
||||
|
|
|
@ -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<T: Field>(
|
||||
|
@ -28,7 +30,7 @@ fn parse_function_identifier<T: Field>(
|
|||
fn parse_function_header<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(String, Vec<Parameter>, Signature), Error<T>> {
|
||||
) -> Result<(String, Vec<ParameterNode>, Signature), Error<T>> {
|
||||
// parse function identifier
|
||||
let (id, s, p) = parse_function_identifier(input, pos)?;
|
||||
|
||||
|
@ -90,7 +92,7 @@ fn parse_function_header<T: Field>(
|
|||
}?;
|
||||
|
||||
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<T: Field>(
|
|||
fn parse_function_argument_variable<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Variable, String, Position), Error<T>> {
|
||||
) -> Result<(VariableNode, String, Position), Error<T>> {
|
||||
let s4 = input;
|
||||
let p4 = pos;
|
||||
|
||||
match next_token::<T>(&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<T: Field>(
|
|||
fn parse_function_arguments<T: Field>(
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Vec<Parameter>, String, Position), Error<T>> {
|
||||
) -> Result<(Vec<ParameterNode>, String, Position), Error<T>> {
|
||||
let mut args = Vec::new();
|
||||
let mut s = input;
|
||||
let mut p = pos;
|
||||
|
@ -152,10 +154,7 @@ fn parse_function_arguments<T: Field>(
|
|||
match next_token(&s, &p) {
|
||||
(Token::Private, s1, p1) => {
|
||||
let (var, s2, p2) = parse_function_argument_variable::<T>(&s1, &p1)?;
|
||||
args.push(Parameter {
|
||||
id: var,
|
||||
private: true,
|
||||
});
|
||||
args.push(Node::new(p, p1, Parameter::private(var)));
|
||||
match next_token::<T>(&s2, &p2) {
|
||||
(Token::Comma, s3, p3) => {
|
||||
s = s3;
|
||||
|
@ -173,10 +172,7 @@ fn parse_function_arguments<T: Field>(
|
|||
}
|
||||
(Token::Type(_), _, _) => {
|
||||
let (var, s2, p2) = parse_function_argument_variable::<T>(&s, &p)?;
|
||||
args.push(Parameter {
|
||||
id: var,
|
||||
private: false,
|
||||
});
|
||||
args.push(Node::new(p, p2, Parameter::public(var)));
|
||||
match next_token::<T>(&s2, &p2) {
|
||||
(Token::Comma, s3, p3) => {
|
||||
s = s3;
|
||||
|
@ -255,7 +251,7 @@ pub fn parse_function<T: Field, R: BufRead>(
|
|||
mut lines: &mut Lines<R>,
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Function<T>, Position), Error<T>> {
|
||||
) -> Result<(FunctionNode<T>, Position), Error<T>> {
|
||||
let mut current_line = pos.line;
|
||||
|
||||
let (id, args, sig) = parse_function_header(input, pos)?;
|
||||
|
@ -279,7 +275,7 @@ pub fn parse_function<T: Field, R: BufRead>(
|
|||
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<T: Field, R: BufRead>(
|
|||
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,
|
||||
))
|
||||
}
|
||||
|
|
|
@ -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<T: Field>(
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Import, Position), Error<T>> {
|
||||
) -> Result<(ImportNode, Position), Error<T>> {
|
||||
match next_token(input, pos) {
|
||||
(Token::DoubleQuote, s1, p1) => match parse_quoted_path(&s1, &p1) {
|
||||
(Token::Path(code_path), s2, p2) => match next_token::<T>(&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<T: Field>(
|
|||
});
|
||||
}
|
||||
},
|
||||
(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(),
|
||||
|
|
|
@ -13,14 +13,16 @@ use super::expression::{
|
|||
};
|
||||
use super::expression_list::parse_expression_list;
|
||||
|
||||
use absy::{Assignee, Expression, Statement, Variable};
|
||||
use absy::{
|
||||
Assignee, AssigneeNode, Expression, Node, Statement, StatementNode, Variable, VariableNode,
|
||||
};
|
||||
use types::Type;
|
||||
|
||||
pub fn parse_statement<T: Field, R: BufRead>(
|
||||
lines: &mut Lines<R>,
|
||||
input: &String,
|
||||
pos: &Position,
|
||||
) -> Result<(Vec<Statement<T>>, String, Position), Error<T>> {
|
||||
) -> Result<(Vec<StatementNode<T>>, String, Position), Error<T>> {
|
||||
match next_token::<T>(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<T: Field, R: BufRead>(
|
|||
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<T: Field, R: BufRead>(
|
|||
match next_token(&s8, &p8) {
|
||||
(Token::InlineComment(_), ref s9, _) => {
|
||||
assert_eq!(s9, "");
|
||||
return Ok((vec![Statement::For(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(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<T: Field, R: BufRead>(
|
|||
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())],
|
||||
|
@ -218,28 +228,56 @@ pub fn parse_statement<T: Field, R: BufRead>(
|
|||
}
|
||||
|
||||
fn parse_definition1<T: Field>(
|
||||
x: Assignee<T>,
|
||||
x: AssigneeNode<T>,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Vec<Statement<T>>, String, Position), Error<T>> {
|
||||
) -> Result<(Vec<StatementNode<T>>, String, Position), Error<T>> {
|
||||
match parse_expr(&input, &pos) {
|
||||
Ok((e1, s1, p1)) => match next_token(&s1, &p1) {
|
||||
(Token::InlineComment(_), ref s2, _) => {
|
||||
assert_eq!(s2, "");
|
||||
match e1 {
|
||||
e @ Expression::FunctionCall(..) => {
|
||||
Ok((vec![Statement::MultipleDefinition(vec![x], e)], s1, p1))
|
||||
}
|
||||
e => Ok((vec![Statement::Definition(x, e)], s1, p1)),
|
||||
match e1.value {
|
||||
e @ Expression::FunctionCall(..) => Ok((
|
||||
vec![Node::new(
|
||||
x.start,
|
||||
p1,
|
||||
Statement::MultipleDefinition(vec![x], Node::new(pos, p1, e)),
|
||||
)],
|
||||
s1,
|
||||
p1,
|
||||
)),
|
||||
e => Ok((
|
||||
vec![Node::new(
|
||||
x.start,
|
||||
p1,
|
||||
Statement::Definition(x, Node::new(pos, p1, e)),
|
||||
)],
|
||||
s1,
|
||||
p1,
|
||||
)),
|
||||
}
|
||||
}
|
||||
(Token::Unknown(ref t2), ref s2, _) if t2 == "" => {
|
||||
assert_eq!(s2, "");
|
||||
match e1 {
|
||||
e @ Expression::FunctionCall(..) => {
|
||||
Ok((vec![Statement::MultipleDefinition(vec![x], e)], s1, p1))
|
||||
}
|
||||
e => Ok((vec![Statement::Definition(x, e)], s1, p1)),
|
||||
match e1.value {
|
||||
e @ Expression::FunctionCall(..) => Ok((
|
||||
vec![Node::new(
|
||||
x.start,
|
||||
p1,
|
||||
Statement::MultipleDefinition(vec![x], Node::new(pos, p1, e)),
|
||||
)],
|
||||
s1,
|
||||
p1,
|
||||
)),
|
||||
e => Ok((
|
||||
vec![Node::new(
|
||||
x.start,
|
||||
p1,
|
||||
Statement::Definition(x, Node::new(pos, p1, e)),
|
||||
)],
|
||||
s1,
|
||||
p1,
|
||||
)),
|
||||
}
|
||||
}
|
||||
(t2, _, p2) => Err(Error {
|
||||
|
@ -256,26 +294,56 @@ fn parse_declaration_definition<T: Field>(
|
|||
t: Type,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Vec<Statement<T>>, String, Position), Error<T>> {
|
||||
) -> Result<(Vec<StatementNode<T>>, String, Position), Error<T>> {
|
||||
match next_token::<T>(&input, &pos) {
|
||||
(Token::Ide(x), s0, p0) => match next_token(&s0, &p0) {
|
||||
(Token::Eq, s1, p1) => match parse_expr(&s1, &p1) {
|
||||
Ok((e2, s2, p2)) => match next_token(&s2, &p2) {
|
||||
(Token::InlineComment(_), ref s3, _) => {
|
||||
assert_eq!(s3, "");
|
||||
match e2 {
|
||||
match e2.value {
|
||||
e @ Expression::FunctionCall(..) => Ok((
|
||||
vec![
|
||||
Statement::Declaration(Variable::new(x.clone(), t)),
|
||||
Statement::MultipleDefinition(vec![Assignee::Identifier(x)], e),
|
||||
Node::new(
|
||||
pos,
|
||||
p0,
|
||||
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,
|
||||
p2,
|
||||
)),
|
||||
e => Ok((
|
||||
vec![
|
||||
Statement::Declaration(Variable::new(x.clone(), t)),
|
||||
Statement::Definition(Assignee::Identifier(x), e),
|
||||
Node::new(
|
||||
pos,
|
||||
p0,
|
||||
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,
|
||||
p2,
|
||||
|
@ -284,19 +352,49 @@ fn parse_declaration_definition<T: Field>(
|
|||
}
|
||||
(Token::Unknown(ref t3), ref s3, _) if t3 == "" => {
|
||||
assert_eq!(s3, "");
|
||||
match e2 {
|
||||
match e2.value {
|
||||
e @ Expression::FunctionCall(..) => Ok((
|
||||
vec![
|
||||
Statement::Declaration(Variable::new(x.clone(), t)),
|
||||
Statement::MultipleDefinition(vec![Assignee::Identifier(x)], e),
|
||||
Node::new(
|
||||
pos,
|
||||
p0,
|
||||
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,
|
||||
p2,
|
||||
)),
|
||||
e => Ok((
|
||||
vec![
|
||||
Statement::Declaration(Variable::new(x.clone(), t)),
|
||||
Statement::Definition(Assignee::Identifier(x), e),
|
||||
Node::new(
|
||||
pos,
|
||||
p0,
|
||||
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,
|
||||
p2,
|
||||
|
@ -324,11 +422,16 @@ fn parse_declaration_definition<T: Field>(
|
|||
// then we should have an equal sign
|
||||
(Token::Eq, s3, p3) => match parse_expr(&s3, &p3) {
|
||||
Ok((e4, s4, p4)) => {
|
||||
let mut statements: Vec<Statement<T>> =
|
||||
d2.into_iter().map(|v| Statement::Declaration(v)).collect();
|
||||
statements.push(Statement::MultipleDefinition(
|
||||
e2.into_iter().map(|e| Assignee::Identifier(e)).collect(),
|
||||
e4,
|
||||
let mut statements: Vec<_> = d2
|
||||
.iter()
|
||||
.map(|v| {
|
||||
Node::new(v.start, v.end, Statement::Declaration(v.clone()))
|
||||
})
|
||||
.collect();
|
||||
statements.push(Node::new(
|
||||
pos,
|
||||
p4,
|
||||
Statement::MultipleDefinition(e2, e4),
|
||||
));
|
||||
Ok((statements, s4, p4)) // output a multipledefinition with the destructure and the expression
|
||||
}
|
||||
|
@ -361,21 +464,28 @@ fn parse_statement1<T: Field>(
|
|||
ide: String,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Vec<Statement<T>>, String, Position), Error<T>> {
|
||||
) -> Result<(Vec<StatementNode<T>>, String, Position), Error<T>> {
|
||||
let ide_start_position = Position {
|
||||
col: pos.col - ide.len(),
|
||||
..pos
|
||||
};
|
||||
match next_token::<T>(&input, &pos) {
|
||||
(Token::Eq, s1, p1) => parse_definition1(Assignee::Identifier(ide), s1, p1),
|
||||
(Token::Eq, s1, p1) => parse_definition1(
|
||||
Node::new(ide_start_position, pos, Assignee::Identifier(ide)),
|
||||
s1,
|
||||
p1,
|
||||
),
|
||||
(Token::Comma, s1, p1) => match parse_identifier_list1(ide, None, s1, p1) {
|
||||
// if we find a comma, parse the rest of the destructure
|
||||
Ok((e2, d2, s2, p2)) => match next_token(&s2, &p2) {
|
||||
// then we should have an equal sign
|
||||
(Token::Eq, s3, p3) => match parse_expr(&s3, &p3) {
|
||||
Ok((e4, s4, p4)) => {
|
||||
let mut statements: Vec<Statement<T>> =
|
||||
d2.into_iter().map(|v| Statement::Declaration(v)).collect();
|
||||
statements.push(Statement::MultipleDefinition(
|
||||
e2.into_iter().map(|e| Assignee::Identifier(e)).collect(),
|
||||
e4,
|
||||
));
|
||||
let mut statements: Vec<_> = d2
|
||||
.iter()
|
||||
.map(|v| Node::new(v.start, v.end, Statement::Declaration(v.clone())))
|
||||
.collect();
|
||||
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),
|
||||
|
@ -395,11 +505,19 @@ fn parse_statement1<T: Field>(
|
|||
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![
|
||||
|
@ -433,11 +551,19 @@ fn parse_statement1<T: Field>(
|
|||
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![
|
||||
|
@ -454,7 +580,7 @@ fn parse_statement1<T: Field>(
|
|||
},
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
(Token::Eq, s5, p5) => parse_definition1(Assignee::from(e4), s5, p5),
|
||||
(Token::Eq, s5, p5) => parse_definition1(AssigneeNode::from(e4), s5, p5),
|
||||
(t4, _, p4) => Err(Error {
|
||||
expected: vec![Token::Eqeq],
|
||||
got: t4,
|
||||
|
@ -465,18 +591,30 @@ fn parse_statement1<T: Field>(
|
|||
},
|
||||
Err(err) => Err(err),
|
||||
},
|
||||
_ => match parse_term1(Expression::Identifier(ide), input, pos) {
|
||||
_ => match parse_term1(
|
||||
Node::new(ide_start_position, pos, Expression::Identifier(ide)),
|
||||
input,
|
||||
pos,
|
||||
) {
|
||||
Ok((e2, s2, p2)) => match parse_expr1(e2, s2, p2) {
|
||||
Ok((e3, s3, p3)) => match next_token(&s3, &p3) {
|
||||
(Token::Eqeq, s4, p4) => match parse_expr(&s4, &p4) {
|
||||
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![
|
||||
|
@ -512,13 +650,23 @@ pub fn parse_identifier_list1<T: Field>(
|
|||
_type: Option<Type>,
|
||||
input: String,
|
||||
pos: Position,
|
||||
) -> Result<(Vec<String>, Vec<Variable>, String, Position), Error<T>> {
|
||||
) -> Result<(Vec<AssigneeNode<T>>, Vec<VariableNode>, String, Position), Error<T>> {
|
||||
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) => {
|
||||
decl.push(Variable::new(head, t));
|
||||
decl.push(Node::new(start_pos, pos, Variable::new(head, t)));
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
|
@ -528,14 +676,14 @@ pub fn parse_identifier_list1<T: Field>(
|
|||
fn parse_comma_separated_identifier_list_rec<T: Field>(
|
||||
input: String,
|
||||
pos: Position,
|
||||
mut acc: &mut Vec<String>,
|
||||
mut decl: &mut Vec<Variable>,
|
||||
) -> Result<(Vec<String>, Vec<Variable>, String, Position), Error<T>> {
|
||||
mut acc: &mut Vec<AssigneeNode<T>>,
|
||||
mut decl: &mut Vec<VariableNode>,
|
||||
) -> Result<(Vec<AssigneeNode<T>>, Vec<VariableNode>, String, Position), Error<T>> {
|
||||
match next_token(&input, &pos) {
|
||||
(Token::Type(t), s1, p1) => match next_token::<T>(&s1, &p1) {
|
||||
(Token::Ide(id), s2, p2) => {
|
||||
acc.push(id.clone());
|
||||
decl.push(Variable::new(id, t));
|
||||
acc.push(Node::new(p1, p2, Assignee::Identifier(id.clone())));
|
||||
decl.push(Node::new(pos, p2, Variable::new(id, t)));
|
||||
match next_token::<T>(&s2, &p2) {
|
||||
(Token::Comma, s3, p3) => {
|
||||
parse_comma_separated_identifier_list_rec(s3, p3, &mut acc, &mut decl)
|
||||
|
@ -550,7 +698,7 @@ fn parse_comma_separated_identifier_list_rec<T: Field>(
|
|||
}),
|
||||
},
|
||||
(Token::Ide(id), s1, p1) => {
|
||||
acc.push(id);
|
||||
acc.push(Node::new(pos, p1, Assignee::Identifier(id)));
|
||||
match next_token::<T>(&s1, &p1) {
|
||||
(Token::Comma, s2, p2) => {
|
||||
parse_comma_separated_identifier_list_rec(s2, p2, &mut acc, &mut decl)
|
||||
|
@ -578,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)
|
||||
|
@ -594,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)
|
||||
|
@ -615,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)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::fmt;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
#[derive(Clone, PartialEq, Copy, Serialize, Deserialize)]
|
||||
pub struct Position {
|
||||
pub line: usize,
|
||||
pub col: usize,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -262,7 +262,6 @@ mod tests {
|
|||
#[cfg(test)]
|
||||
mod heuristics {
|
||||
use super::*;
|
||||
use absy::{Parameter, Variable};
|
||||
|
||||
#[test]
|
||||
fn inline_constant_field() {
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
|
||||
//! @date 2018
|
||||
|
||||
use absy::variable::Variable;
|
||||
use std::collections::HashMap;
|
||||
use typed_absy::folder::*;
|
||||
use typed_absy::*;
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
|
||||
//! @date 2018
|
||||
|
||||
use absy::variable::Variable;
|
||||
use std::collections::HashMap;
|
||||
use typed_absy::folder::*;
|
||||
use typed_absy::*;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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::*;
|
||||
|
|
41
zokrates_core/src/typed_absy/parameter.rs
Normal file
41
zokrates_core/src/typed_absy/parameter.rs
Normal file
|
@ -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<absy::Parameter> for Parameter {
|
||||
fn from(p: absy::Parameter) -> Parameter {
|
||||
Parameter {
|
||||
private: p.private,
|
||||
id: p.id.value.into(),
|
||||
}
|
||||
}
|
||||
}
|
57
zokrates_core/src/typed_absy/variable.rs
Normal file
57
zokrates_core/src/typed_absy/variable.rs
Normal file
|
@ -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<S: Into<String>>(id: S) -> Variable {
|
||||
Variable {
|
||||
id: id.into(),
|
||||
_type: Type::FieldElement,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn boolean<S: Into<String>>(id: S) -> Variable {
|
||||
Variable {
|
||||
id: id.into(),
|
||||
_type: Type::Boolean,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn field_array<S: Into<String>>(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<absy::Variable> for Variable {
|
||||
fn from(v: absy::Variable) -> Variable {
|
||||
Variable {
|
||||
id: v.id,
|
||||
_type: v._type,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,7 @@ extern crate serde_json;
|
|||
extern crate zokrates_field;
|
||||
|
||||
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};
|
||||
|
||||
|
@ -81,7 +81,7 @@ pub fn read_file(path: &str) -> String {
|
|||
contents
|
||||
}
|
||||
|
||||
pub fn compile(code: &str) -> Result<ir::Prog<FieldPrime>, CompileError<FieldPrime>> {
|
||||
pub fn compile(code: &str) -> Result<ir::Prog<FieldPrime>, CompileErrors<FieldPrime>> {
|
||||
generic_compile::<FieldPrime, &[u8], &[u8], io::Error>(&mut code.as_bytes(), None, None)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue