impl syntax error handling

This commit is contained in:
collin 2020-06-04 15:44:38 -07:00
parent 0e8ee81108
commit bd54f367cf
20 changed files with 192 additions and 331 deletions

View File

@ -85,7 +85,8 @@ pub struct Not<'ast> {
// Binary Operations
#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::operation_binary))]
pub enum BinaryOperator {
Or,
And,
@ -1003,6 +1004,7 @@ pub struct MultipleAssignmentStatement<'ast> {
pub variables: Vec<Variable<'ast>>,
pub function_name: Identifier<'ast>,
pub arguments: Vec<Expression<'ast>>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
@ -1012,6 +1014,7 @@ pub struct MultipleAssignmentStatement<'ast> {
pub struct DefinitionStatement<'ast> {
pub variable: Variable<'ast>,
pub expression: Expression<'ast>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
@ -1022,6 +1025,7 @@ pub struct AssignStatement<'ast> {
pub assignee: Assignee<'ast>,
pub assign: OperationAssign,
pub expression: Expression<'ast>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
@ -1031,6 +1035,7 @@ pub struct AssignStatement<'ast> {
pub struct AssertEq<'ast> {
pub left: Expression<'ast>,
pub right: Expression<'ast>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
@ -1045,6 +1050,7 @@ pub enum AssertStatement<'ast> {
#[pest_ast(rule(Rule::statement_expression))]
pub struct ExpressionStatement<'ast> {
pub expression: Expression<'ast>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}
@ -1185,6 +1191,10 @@ pub struct Function<'ast> {
#[pest_ast(rule(Rule::EOI))]
pub struct EOI;
#[derive(Clone, Debug, FromPest, PartialEq)]
#[pest_ast(rule(Rule::LINE_END))]
pub struct LineEnd;
// Imports
#[derive(Clone, Debug, FromPest, PartialEq)]
@ -1210,6 +1220,7 @@ pub struct ImportSymbol<'ast> {
pub struct Import<'ast> {
pub source: ImportSource<'ast>,
pub symbols: Vec<ImportSymbol<'ast>>,
pub line_end: LineEnd,
#[pest_ast(outer())]
pub span: Span<'ast>,
}

View File

@ -88,7 +88,9 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
.map_err(|_| CompilerError::FileReadError(self.main_file_path.clone()))?;
// Parse the file using leo.pest
let mut file = ast::parse(&unparsed_file).map_err(|_| CompilerError::FileParsingError)?;
let mut file = ast::parse(&unparsed_file).map_err(|error| {
CompilerError::from(error.with_path(&self.main_file_path.to_str().unwrap()))
})?;
// Build the abstract syntax tree
let syntax_tree =

View File

@ -427,11 +427,12 @@ impl<F: Field + PrimeField, G: GroupType<F>, CS: ConstraintSystem<F>> Constraine
self.enforce_assert_eq_statement(cs, left, right)?;
}
}
(val_1, val_2) => unimplemented!(
"assert eq not supported for given types {} == {}",
val_1,
val_2
),
(val_1, val_2) => {
return Err(StatementError::AssertEq(
val_1.to_string(),
val_2.to_string(),
))
}
})
}

View File

@ -0,0 +1,44 @@
use crate::ast::Rule;
use pest::error::Error;
#[derive(Debug, Error)]
pub enum SyntaxError {
#[error("aborting due to syntax error")]
Error,
}
impl From<Error<Rule>> for SyntaxError {
fn from(mut error: Error<Rule>) -> Self {
error = error.renamed_rules(|rule| match *rule {
Rule::LINE_END => "`;`".to_owned(),
Rule::type_integer => "`u32`".to_owned(),
Rule::type_field => "`field`".to_owned(),
Rule::type_group => "`group`".to_owned(),
Rule::file => "an import, circuit, or function".to_owned(),
Rule::identifier => "a variable name".to_owned(),
Rule::_type => "a type".to_owned(),
Rule::access => "`.`, `::`, `()`".to_owned(),
Rule::operation_and => "`&&`".to_owned(),
Rule::operation_or => "`||`".to_owned(),
Rule::operation_eq => "`==`".to_owned(),
Rule::operation_ne => "`!=`".to_owned(),
Rule::operation_ge => "`>=`".to_owned(),
Rule::operation_gt => "`>`".to_owned(),
Rule::operation_le => "`<=`".to_owned(),
Rule::operation_lt => "`<`".to_owned(),
Rule::operation_add => "`+`".to_owned(),
Rule::operation_sub => "`-`".to_owned(),
Rule::operation_mul => "`*`".to_owned(),
Rule::operation_div => "`/`".to_owned(),
Rule::operation_pow => "`**`".to_owned(),
rule => format!("{:?}", rule),
});
log::error!("{}\n", error);
SyntaxError::Error
}
}

View File

@ -1,5 +1,7 @@
use crate::errors::{FunctionError, ImportError, IntegerError};
use crate::ast::Rule;
use crate::errors::{FunctionError, ImportError, IntegerError, SyntaxError};
use pest::error::Error;
use std::{io, path::PathBuf};
#[derive(Debug, Error)]
@ -11,13 +13,13 @@ pub enum CompilerError {
DirectoryError(io::Error),
#[error("{}", _0)]
ImportError(ImportError),
ImportError(#[from] ImportError),
#[error("{}", _0)]
IntegerError(IntegerError),
IntegerError(#[from] IntegerError),
#[error("{}", _0)]
FunctionError(FunctionError),
FunctionError(#[from] FunctionError),
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
@ -31,6 +33,9 @@ pub enum CompilerError {
#[error("Main must be a function")]
NoMainFunction,
#[error("{}", _0)]
SyntaxError(#[from] SyntaxError),
#[error("Unable to construct abstract syntax tree")]
SyntaxTreeError,
@ -38,20 +43,8 @@ pub enum CompilerError {
Writing(io::Error),
}
impl From<ImportError> for CompilerError {
fn from(error: ImportError) -> Self {
CompilerError::ImportError(error)
}
}
impl From<IntegerError> for CompilerError {
fn from(error: IntegerError) -> Self {
CompilerError::IntegerError(error)
}
}
impl From<FunctionError> for CompilerError {
fn from(error: FunctionError) -> Self {
CompilerError::FunctionError(error)
impl From<Error<Rule>> for CompilerError {
fn from(error: Error<Rule>) -> Self {
CompilerError::SyntaxError(SyntaxError::from(error))
}
}

View File

@ -1,33 +1,16 @@
use crate::errors::ValueError;
use snarkos_errors::gadgets::SynthesisError;
#[derive(Debug, Error)]
pub enum BooleanError {
#[error("{}", _0)]
ValueError(ValueError),
#[error("Expected boolean parameter, got {}", _0)]
InvalidBoolean(String),
#[error("Cannot evaluate {}", _0)]
CannotEvaluate(String),
#[error("Cannot enforce {}", _0)]
CannotEnforce(String),
#[error("Expected boolean parameter, got {}", _0)]
InvalidBoolean(String),
#[error("{}", _0)]
SynthesisError(SynthesisError),
}
impl From<SynthesisError> for BooleanError {
fn from(error: SynthesisError) -> Self {
BooleanError::SynthesisError(error)
}
}
impl From<ValueError> for BooleanError {
fn from(error: ValueError) -> Self {
BooleanError::ValueError(error)
}
SynthesisError(#[from] SynthesisError),
}

View File

@ -12,136 +12,88 @@ pub enum ExpressionError {
UndefinedIdentifier(String),
// Types
#[error("Expected single type for implicit number {}", _0)]
SingleType(String),
#[error("{}", _0)]
BooleanError(#[from] BooleanError),
#[error("{}", _0)]
IncompatibleTypes(String),
#[error("{}", _0)]
ValueError(ValueError),
IntegerError(#[from] IntegerError),
#[error("{}", _0)]
IntegerError(IntegerError),
#[error("{}", _0)]
ParseIntError(ParseIntError),
#[error("{}", _0)]
FieldError(FieldError),
FieldError(#[from] FieldError),
#[error("{}", _0)]
GroupError(#[from] GroupError),
#[error("{}", _0)]
BooleanError(BooleanError),
ParseIntError(#[from] ParseIntError),
#[error("Exponent must be an integer, got field {}", _0)]
InvalidExponent(String),
#[error("{}", _0)]
ValueError(#[from] ValueError),
// Arrays
#[error(
"Array {} must be declared before it is used in an inline expression",
_0
)]
UndefinedArray(String),
#[error("Cannot access array {}", _0)]
InvalidArrayAccess(String),
#[error("Spread should contain an array, got {}", _0)]
InvalidSpread(String),
#[error("Index must resolve to an integer, got {}", _0)]
InvalidIndex(String),
#[error("Expected array length {}, got {}", _0, _1)]
InvalidLength(usize, usize),
#[error("Spread should contain an array, got {}", _0)]
InvalidSpread(String),
#[error(
"Array {} must be declared before it is used in an inline expression",
_0
)]
UndefinedArray(String),
// Circuits
#[error("Expected circuit member {}", _0)]
ExpectedCircuitMember(String),
#[error("Cannot access circuit {}", _0)]
InvalidCircuitAccess(String),
#[error("Non-static member {} must be accessed using `.` syntax", _0)]
InvalidMemberAccess(String),
#[error("Static member {} must be accessed using `::` syntax", _0)]
InvalidStaticAccess(String),
#[error(
"Circuit {} must be declared before it is used in an inline expression",
_0
)]
UndefinedCircuit(String),
#[error("Cannot access circuit {}", _0)]
InvalidCircuitAccess(String),
#[error("Expected circuit member {}", _0)]
ExpectedCircuitMember(String),
#[error("Circuit {} has no member {}", _0, _1)]
UndefinedMemberAccess(String, String),
#[error("Non-static member {} must be accessed using `.` syntax", _0)]
InvalidMemberAccess(String),
#[error("Circuit {} has no static member {}", _0, _1)]
UndefinedStaticAccess(String, String),
#[error("Static member {} must be accessed using `::` syntax", _0)]
InvalidStaticAccess(String),
// Functions
#[error("Inline function call to {} did not return", _0)]
FunctionDidNotReturn(String),
#[error("{}", _0)]
FunctionError(#[from] Box<FunctionError>),
#[error(
"Function {} must be declared before it is used in an inline expression",
_0
)]
UndefinedFunction(String),
#[error("{}", _0)]
FunctionError(Box<FunctionError>),
#[error("Inline function call to {} did not return", _0)]
FunctionDidNotReturn(String),
// Conditionals
#[error("If, else conditional must resolve to a boolean, got {}", _0)]
IfElseConditional(String),
#[error("{}", _0)]
SynthesisError(SynthesisError),
}
impl From<SynthesisError> for ExpressionError {
fn from(error: SynthesisError) -> Self {
ExpressionError::SynthesisError(error)
}
}
impl From<ValueError> for ExpressionError {
fn from(error: ValueError) -> Self {
ExpressionError::ValueError(error)
}
}
impl From<IntegerError> for ExpressionError {
fn from(error: IntegerError) -> Self {
ExpressionError::IntegerError(error)
}
}
impl From<ParseIntError> for ExpressionError {
fn from(error: ParseIntError) -> Self {
ExpressionError::ParseIntError(error)
}
}
impl From<FieldError> for ExpressionError {
fn from(error: FieldError) -> Self {
ExpressionError::FieldError(error)
}
}
impl From<BooleanError> for ExpressionError {
fn from(error: BooleanError) -> Self {
ExpressionError::BooleanError(error)
}
}
impl From<Box<FunctionError>> for ExpressionError {
fn from(error: Box<FunctionError>) -> Self {
ExpressionError::FunctionError(error)
}
SynthesisError(#[from] SynthesisError),
}

View File

@ -9,11 +9,5 @@ pub enum FieldError {
NoInverse(String),
#[error("{}", _0)]
SynthesisError(SynthesisError),
}
impl From<SynthesisError> for FieldError {
fn from(error: SynthesisError) -> Self {
FieldError::SynthesisError(error)
}
SynthesisError(#[from] SynthesisError),
}

View File

@ -7,78 +7,27 @@ pub enum FunctionError {
#[error("Function expected {} inputs, got {}", _0, _1)]
ArgumentsLength(usize, usize),
#[error("Function input type not defined {}", _0)]
UndefinedInput(String),
#[error("{}", _0)]
BooleanError(#[from] BooleanError),
#[error("Function expected input type {}, got {}", _0, _1)]
InvalidInput(String, String),
#[error("{}", _0)]
ExpressionError(#[from] ExpressionError),
#[error("{}", _0)]
FieldError(#[from] FieldError),
#[error("{}", _0)]
GroupError(#[from] GroupError),
#[error("{}", _0)]
IntegerError(#[from] IntegerError),
#[error("Expected function input array, got {}", _0)]
InvalidArray(String),
#[error("Expected function input array length {}, got length {}", _0, _1)]
InvalidArrayLength(usize, usize),
#[error("{}", _0)]
StatementError(#[from] StatementError),
#[error("{}", _0)]
ValueError(ValueError),
#[error("{}", _0)]
IntegerError(IntegerError),
#[error("{}", _0)]
FieldError(FieldError),
#[error("{}", _0)]
GroupError(GroupError),
#[error("{}", _0)]
BooleanError(BooleanError),
#[error("{}", _0)]
ExpressionError(ExpressionError),
#[error("{}", _0)]
StatementError(StatementError),
}
impl From<ValueError> for FunctionError {
fn from(error: ValueError) -> Self {
FunctionError::ValueError(error)
}
}
impl From<IntegerError> for FunctionError {
fn from(error: IntegerError) -> Self {
FunctionError::IntegerError(error)
}
}
impl From<FieldError> for FunctionError {
fn from(error: FieldError) -> Self {
FunctionError::FieldError(error)
}
}
impl From<GroupError> for FunctionError {
fn from(error: GroupError) -> Self {
FunctionError::GroupError(error)
}
}
impl From<BooleanError> for FunctionError {
fn from(error: BooleanError) -> Self {
FunctionError::BooleanError(error)
}
}
impl From<ExpressionError> for FunctionError {
fn from(error: ExpressionError) -> Self {
FunctionError::ExpressionError(error)
}
}
impl From<StatementError> for FunctionError {
fn from(error: StatementError) -> Self {
FunctionError::StatementError(error)
}
ValueError(#[from] ValueError),
}

View File

@ -6,11 +6,5 @@ pub enum GroupError {
Invalid(String),
#[error("{}", _0)]
SynthesisError(SynthesisError),
}
impl From<SynthesisError> for GroupError {
fn from(error: SynthesisError) -> Self {
GroupError::SynthesisError(error)
}
SynthesisError(#[from] SynthesisError),
}

View File

@ -5,12 +5,12 @@ pub enum ImportError {
#[error("Attempt to access current directory failed - {:?}", _0)]
DirectoryError(io::Error),
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
#[error("Syntax error. Cannot parse the file")]
FileParsingError,
#[error("Cannot read from the provided file path - {:?}", _0)]
FileReadError(PathBuf),
#[error("Unable to construct abstract syntax tree")]
SyntaxTreeError,
}

View File

@ -2,24 +2,12 @@ use snarkos_errors::gadgets::SynthesisError;
#[derive(Debug, Error)]
pub enum IntegerError {
#[error("expected integer parameter type, got {}", _0)]
InvalidType(String),
#[error("Cannot enforce {}", _0)]
CannotEnforce(String),
#[error("Expected integer parameter, got {}", _0)]
InvalidInteger(String),
#[error("Cannot evaluate {}", _0)]
CannotEvaluate(String),
#[error("Cannot enforce {}", _0)]
CannotEnforce(String),
#[error("{}", _0)]
SynthesisError(SynthesisError),
}
impl From<SynthesisError> for IntegerError {
fn from(error: SynthesisError) -> Self {
IntegerError::SynthesisError(error)
}
SynthesisError(#[from] SynthesisError),
}

View File

@ -1,27 +1,18 @@
use crate::errors::{BooleanError, ExpressionError, FieldError, IntegerError, ValueError};
use crate::errors::{BooleanError, ExpressionError};
use snarkos_errors::gadgets::SynthesisError;
#[derive(Debug, Error)]
pub enum StatementError {
#[error("{}", _0)]
BooleanError(#[from] BooleanError),
#[error("{}", _0)]
ExpressionError(#[from] ExpressionError),
#[error("Attempted to assign to unknown variable {}", _0)]
UndefinedVariable(String),
#[error("{}", _0)]
ExpressionError(ExpressionError),
#[error("{}", _0)]
IntegerError(IntegerError),
#[error("{}", _0)]
FieldError(FieldError),
#[error("{}", _0)]
BooleanError(BooleanError),
#[error("{}", _0)]
ValueError(ValueError),
// Arrays
#[error("Cannot assign single index to array of values")]
ArrayAssignIndex,
@ -29,9 +20,6 @@ pub enum StatementError {
#[error("Cannot assign range of array values to single value")]
ArrayAssignRange,
#[error("Cannot assign to unknown array {}", _0)]
UndefinedArray(String),
// Circuits
#[error("Cannot mutate circuit function, {}", _0)]
ImmutableCircuitFunction(String),
@ -43,6 +31,12 @@ pub enum StatementError {
UndefinedCircuitObject(String),
// Statements
#[error("Cannot assert equality between {} == {}", _0, _1)]
AssertEq(String, String),
#[error("If, else conditional must resolve to a boolean, got {}", _0)]
IfElseConditional(String),
#[error("Cannot assign to immutable variable {}", _0)]
ImmutableAssign(String),
@ -56,45 +50,9 @@ pub enum StatementError {
#[error("Function return statement expected {} return values, got {}", _0, _1)]
InvalidNumberOfReturns(usize, usize),
#[error("If, else conditional must resolve to a boolean, got {}", _0)]
IfElseConditional(String),
#[error("Cannot assert equality between {} == {}", _0, _1)]
AssertEq(String, String),
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
#[error("Expected assignment of return values for expression {}", _0)]
Unassigned(String),
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
}
impl From<ExpressionError> for StatementError {
fn from(error: ExpressionError) -> Self {
StatementError::ExpressionError(error)
}
}
impl From<IntegerError> for StatementError {
fn from(error: IntegerError) -> Self {
StatementError::IntegerError(error)
}
}
impl From<FieldError> for StatementError {
fn from(error: FieldError) -> Self {
StatementError::FieldError(error)
}
}
impl From<BooleanError> for StatementError {
fn from(error: BooleanError) -> Self {
StatementError::BooleanError(error)
}
}
impl From<ValueError> for StatementError {
fn from(error: ValueError) -> Self {
StatementError::ValueError(error)
}
}

View File

@ -5,49 +5,17 @@ use std::{num::ParseIntError, str::ParseBoolError};
#[derive(Debug, Error)]
pub enum ValueError {
#[error("{}", _0)]
ParseIntError(ParseIntError),
#[error("{}", _0)]
ParseBoolError(ParseBoolError),
#[error("{}", _0)]
IntegerError(IntegerError),
/// Unexpected array length
#[error("{}", _0)]
ArrayLength(String),
#[error("Expected type array, got {}", _0)]
ArrayModel(String),
/// Unexpected circuit name
#[error("Expected circuit name {} got {}", _0, _1)]
CircuitName(String, String),
/// Unexpected type
#[error("{}", _0)]
TypeError(String),
FieldError(#[from] FieldError),
#[error("{}", _0)]
GroupError(#[from] GroupError),
#[error("{}", _0)]
FieldError(#[from] FieldError),
}
IntegerError(#[from] IntegerError),
impl From<ParseIntError> for ValueError {
fn from(error: ParseIntError) -> Self {
ValueError::ParseIntError(error)
}
}
#[error("{}", _0)]
ParseBoolError(#[from] ParseBoolError),
impl From<ParseBoolError> for ValueError {
fn from(error: ParseBoolError) -> Self {
ValueError::ParseBoolError(error)
}
}
impl From<IntegerError> for ValueError {
fn from(error: IntegerError) -> Self {
ValueError::IntegerError(error)
}
#[error("{}", _0)]
ParseIntError(#[from] ParseIntError),
}

View File

@ -1,3 +1,6 @@
pub mod ast;
pub use self::ast::*;
pub mod compiler;
pub use self::compiler::*;

View File

@ -173,7 +173,7 @@ expression_tuple = _{ (expression ~ ("," ~ expression)*)? }
/// Asserts
assert_eq = {"assert_eq!" ~ "(" ~ NEWLINE* ~ expression ~ "," ~ NEWLINE* ~ expression ~ NEWLINE* ~ ")"}
assert_eq = {"assert_eq!" ~ "(" ~ NEWLINE* ~ expression ~ "," ~ NEWLINE* ~ expression ~ NEWLINE* ~ ")" ~ LINE_END}
// assert_true = {"assert"}
/// Conditionals
@ -181,16 +181,16 @@ conditional_nested_or_end = { statement_conditional | "{" ~ NEWLINE* ~ statement
/// Statements
statement_return = { "return" ~ expression_tuple }
statement_definition = { "let" ~ variable ~ "=" ~ expression }
statement_assign = { assignee ~ operation_assign ~ expression }
statement_multiple_assignment = { "let" ~ "(" ~ variable_tuple ~ ")" ~ "=" ~ identifier ~ "(" ~ expression_tuple ~ ")" }
statement_definition = { "let" ~ variable ~ "=" ~ expression ~ LINE_END}
statement_assign = { assignee ~ operation_assign ~ expression ~ LINE_END}
statement_multiple_assignment = { "let" ~ "(" ~ variable_tuple ~ ")" ~ "=" ~ identifier ~ "(" ~ expression_tuple ~ ")" ~ LINE_END}
statement_conditional = {"if" ~ (expression | "(" ~ expression ~ ")") ~ "{" ~ NEWLINE* ~ statement+ ~ "}" ~ ("else" ~ conditional_nested_or_end)?}
statement_for = { "for" ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "{" ~ NEWLINE* ~ statement+ ~ "}"}
statement_assert = {
assert_eq
// | assert_true |
}
statement_expression = { expression }
statement_expression = { expression ~ LINE_END }
statement = {
(statement_return
@ -201,7 +201,7 @@ statement = {
| statement_definition
| statement_assign
| statement_expression
) ~ LINE_END
)
) ~ NEWLINE*
}
@ -216,7 +216,7 @@ function_definition = {"function" ~ identifier ~ "(" ~ input_model_list ~ ")" ~
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
WHITESPACE = _{ " " | "\t" ~ (NEWLINE)* }
LINE_END = _{";" ~ NEWLINE*}
LINE_END = {";" ~ NEWLINE*}
/// Imports

View File

@ -2,6 +2,7 @@
#[macro_use]
extern crate thiserror;
extern crate log;
#[macro_use]
extern crate lazy_static;

View File

@ -8,6 +8,7 @@ pub mod import;
pub mod integer;
pub mod mutability;
pub mod statement;
pub mod syntax;
use leo_compiler::{
compiler::Compiler,

View File

@ -0,0 +1,16 @@
use crate::compile_program;
use leo_compiler::errors::CompilerError;
const DIRECTORY_NAME: &str = "tests/syntax/";
#[test]
fn test_semicolon() {
let error = compile_program(DIRECTORY_NAME, "semicolon.leo")
.err()
.unwrap();
match error {
CompilerError::SyntaxError(_) => {}
_ => panic!("wrong error"),
}
}

View File

@ -0,0 +1,3 @@
function main() {
let a = 0
}