From f7261d0e842b151d97a0915fb6f54e74d8a6cc19 Mon Sep 17 00:00:00 2001 From: Alex Hansen Date: Tue, 2 Mar 2021 14:18:55 -0800 Subject: [PATCH] Refactor error and warning handling (#12) * begin refactor of error/warnings * finish refactor --- hllc/example_programs/basic.rs | 22 +- hllc/src/main.rs | 8 +- parser/src/error.rs | 201 ++++++++-- parser/src/hll.pest | 4 +- parser/src/lib.rs | 127 +++++-- .../declaration/enum_declaration.rs | 52 ++- .../declaration/function_declaration.rs | 136 +++++-- parser/src/parse_tree/declaration/mod.rs | 62 ++- .../declaration/struct_declaration.rs | 53 ++- .../declaration/trait_declaration.rs | 115 +++--- .../parse_tree/declaration/type_parameter.rs | 39 +- parser/src/parse_tree/expression.rs | 358 +++++++++++++----- parser/src/parse_tree/literal.rs | 194 +++++----- parser/src/parse_tree/use_statement.rs | 7 +- parser/src/semantics/error.rs | 86 ----- parser/src/semantics/mod.rs | 280 ++++++-------- parser/src/types.rs | 40 +- 17 files changed, 1143 insertions(+), 641 deletions(-) delete mode 100644 parser/src/semantics/error.rs diff --git a/hllc/example_programs/basic.rs b/hllc/example_programs/basic.rs index e32d4d843de..384382c75bf 100644 --- a/hllc/example_programs/basic.rs +++ b/hllc/example_programs/basic.rs @@ -1,35 +1,35 @@ contract { - /* trait my_trait { - fn someFnThing(): u32 + fn someFnThing(): T } { fn some_other_trait_thing(): bool { - return true; + true } } -*/ - fn contract_func_1(a: T, y: u32): T { - println("Test function."); - let z = x.a.b.c; + + pub fn contract_func_1(a: T, y: u32): T { + println("Test function.", "other str", 3); + let mut z: u8 = y; let x: byte = { // a code block w/ implicit return let y = 0b11110000; y }; + + let example_variable_decl = 5; let y = if true { let x = 5; let z = 2; a - } else { 10 }; + } else { a }; - a + // should be an error since ther3's no return here } - /* struct my_struct { FieldName: u64 } - */ } + diff --git a/hllc/src/main.rs b/hllc/src/main.rs index 12491e80d2b..57df2b1e121 100644 --- a/hllc/src/main.rs +++ b/hllc/src/main.rs @@ -1,6 +1,6 @@ #![allow(warnings)] use line_col::LineColLookup; -use parser::compile; +use parser::{compile, CompileError, CompileResult, CompileWarning}; use source_span::{ fmt::{Color, Formatter, Style}, Position, SourceBuffer, Span, DEFAULT_METRICS, @@ -57,9 +57,9 @@ fn main() -> Result<(), Box> { )); } } - Err(e) => { - let e_len = e.len(); - e.into_iter().for_each(|e| format_err(&content, e)); + Err((errors, warnings)) => { + let e_len = errors.len(); + errors.into_iter().for_each(|e| format_err(&content, e)); write_red(format!( "Aborting due to {} {}.", diff --git a/parser/src/error.rs b/parser/src/error.rs index 04f53402af5..567d6c9e9e6 100644 --- a/parser/src/error.rs +++ b/parser/src/error.rs @@ -5,11 +5,55 @@ use inflector::cases::snakecase::to_snake_case; use pest::Span; use thiserror::Error; +macro_rules! type_check { + ($name: ident, $val: expr, $namespace: expr, $type_annotation: expr, $help_text: expr, $err_recov: expr, $warnings: ident, $errors: ident) => {{ + use crate::CompileResult; + let res = $name::type_check($val.clone(), $namespace, $type_annotation, $help_text); + match res { + CompileResult::Ok { + value, + warnings: mut l_w, + errors: mut l_e, + } => { + $warnings.append(&mut l_w); + $errors.append(&mut l_e); + value + } + CompileResult::Err { + warnings: mut l_w, + errors: mut l_e, + } => { + $warnings.append(&mut l_w); + $errors.append(&mut l_e); + $err_recov + } + } + }}; +} + /// evaluates `$fn` with argument `$arg`, and pushes any warnings to the `$warnings` buffer. macro_rules! eval { - ($fn: expr, $warnings: ident, $arg: expr) => {{ - let (res, mut warns) = $fn($arg)?; - $warnings.append(&mut warns); + ($fn: expr, $warnings: ident, $errors: ident, $arg: expr, $error_recovery: expr) => {{ + use crate::CompileResult; + let res = match $fn($arg.clone()) { + CompileResult::Ok { + value, + warnings: mut l_w, + errors: mut l_e, + } => { + $warnings.append(&mut l_w); + $errors.append(&mut l_e); + value + } + CompileResult::Err { + warnings: mut l_w, + errors: mut l_e, + } => { + $errors.append(&mut l_e); + $warnings.append(&mut l_w); + $error_recovery + } + }; res }}; } @@ -26,7 +70,50 @@ macro_rules! assert_or_warn { }; } -pub type ParseResult<'sc, T> = Result<(T, Vec>), ParseError<'sc>>; +/// Denotes a non-recoverable state +pub(crate) fn err<'sc, T>( + warnings: Vec>, + errors: Vec>, +) -> CompileResult<'sc, T> { + CompileResult::Err { warnings, errors } +} + +/// Denotes a recovered or non-error state +pub(crate) fn ok<'sc, T>( + value: T, + warnings: Vec>, + errors: Vec>, +) -> CompileResult<'sc, T> { + CompileResult::Ok { + warnings, + value, + errors, + } +} + +#[derive(Debug)] +pub enum CompileResult<'sc, T> { + Ok { + value: T, + warnings: Vec>, + errors: Vec>, + }, + Err { + warnings: Vec>, + errors: Vec>, + }, +} + +impl<'sc, T> CompileResult<'sc, T> { + pub fn unwrap(&self) -> &T { + match self { + CompileResult::Ok { value, .. } => value, + CompileResult::Err { errors, .. } => { + panic!("Unwrapped an err {:?}", errors); + } + } + } +} #[derive(Debug, Clone)] pub struct CompileWarning<'sc> { @@ -81,8 +168,28 @@ impl<'sc> Warning<'sc> { } } -#[derive(Debug, Error)] -pub enum ParseError<'sc> { +#[derive(Error, Debug)] +pub enum CompileError<'sc> { + #[error("Variable \"{var_name}\" does not exist in this scope.")] + UnknownVariable { var_name: &'sc str, span: Span<'sc> }, + #[error("Function \"{name}\" does not exist in this scope.")] + UnknownFunction { name: &'sc str, span: Span<'sc> }, + #[error("Identifier \"{name}\" was used as a variable, but it is actually a {what_it_is}.")] + NotAVariable { + name: &'sc str, + span: Span<'sc>, + what_it_is: &'static str, + }, + #[error("Identifier \"{name}\" was called as if it was a function, but it is actually a {what_it_is}.")] + NotAFunction { + name: &'sc str, + span: Span<'sc>, + what_it_is: &'static str, + }, + #[error("Unimplemented feature: {0}")] + Unimplemented(&'static str, Span<'sc>), + #[error("{0}")] + TypeError(TypeError<'sc>), #[error("Error parsing input: expected {0:?}")] ParseFailure(#[from] pest::error::Error), #[error("Invalid top-level item: {0:?}. A program should consist of a contract, script, or predicate at the top level.")] @@ -90,7 +197,7 @@ pub enum ParseError<'sc> { #[error("Internal compiler error: {0}\nPlease file an issue on the repository and include the code that triggered this error.")] Internal(&'static str, Span<'sc>), #[error("Unimplemented feature: {0:?}")] - Unimplemented(Rule, Span<'sc>), + UnimplementedRule(Rule, Span<'sc>), #[error("Byte literal had length of {byte_length}. Byte literals must be either one byte long (8 binary digits or 2 hex digits) or 32 bytes long (256 binary digits or 64 hex digits)")] InvalidByteLiteralLength { byte_length: usize, span: Span<'sc> }, #[error("Expected an expression to follow operator \"{op}\"")] @@ -110,33 +217,45 @@ pub enum ParseError<'sc> { MultipleScripts(Span<'sc>), #[error("Program contains multiple predicates. A valid program should only contain at most one predicate.")] MultiplePredicates(Span<'sc>), + #[error("Trait constraint was applied to generic type that is not in scope. Trait \"{trait_name}\" cannot constrain type \"{type_name}\" because that type does not exist in this scope.")] + ConstrainedNonExistentType { + trait_name: &'sc str, + type_name: &'sc str, + span: Span<'sc>, + }, } -impl<'sc> ParseError<'sc> { - pub fn span(&self) -> (usize, usize) { - use ParseError::*; +impl<'sc> std::convert::From> for CompileError<'sc> { + fn from(other: TypeError<'sc>) -> CompileError<'sc> { + CompileError::TypeError(other) + } +} + +#[derive(Error, Debug)] +pub enum TypeError<'sc> { + #[error("Mismatched types: Expected type {expected} but found type {received}. Type {received} is not castable to type {expected}.\n help: {help_text}")] + MismatchedType { + expected: String, + received: String, + help_text: String, + span: Span<'sc>, + }, +} + +impl<'sc> TypeError<'sc> { + pub(crate) fn span(&self) -> (usize, usize) { + use TypeError::*; match self { - ParseFailure(err) => match err.location { - pest::error::InputLocation::Pos(num) => (num, num + 1), - pest::error::InputLocation::Span((start, end)) => (start, end), - }, - InvalidTopLevelItem(_, sp) => (sp.start(), sp.end()), - Internal(_, sp) => (sp.start(), sp.end()), - Unimplemented(_, sp) => (sp.start(), sp.end()), - InvalidByteLiteralLength { span, .. } => (span.start(), span.end()), - ExpectedExprAfterOp { span, .. } => (span.start(), span.end()), - ExpectedOp { span, .. } => (span.start(), span.end()), - UnexpectedWhereClause(sp) => (sp.start(), sp.end()), - UndeclaredGenericTypeInWhereClause { span, .. } => (span.start(), span.end()), - MultiplePredicates(sp) => (sp.start(), sp.end()), - MultipleScripts(sp) => (sp.start(), sp.end()), - MultipleContracts(sp) => (sp.start(), sp.end()), + MismatchedType { span, .. } => (span.start(), span.end()), } } +} +impl<'sc> CompileError<'sc> { pub fn to_friendly_error_string(&self) -> String { + use CompileError::*; match self { - ParseError::ParseFailure(err) => format!( + CompileError::ParseFailure(err) => format!( "Error parsing input: {}", match &err.variant { pest::error::ErrorVariant::ParsingError { @@ -169,7 +288,35 @@ impl<'sc> ParseError<'sc> { pest::error::ErrorVariant::CustomError { message } => message.to_string(), } ), - o => format!("{}", o), + a => format!("{}", a), + } + } + + pub fn span(&self) -> (usize, usize) { + use CompileError::*; + match self { + UnknownVariable { span, .. } => (span.start(), span.end()), + UnknownFunction { span, .. } => (span.start(), span.end()), + NotAVariable { span, .. } => (span.start(), span.end()), + NotAFunction { span, .. } => (span.start(), span.end()), + Unimplemented(_, span) => (span.start(), span.end()), + TypeError(err) => err.span(), + ParseFailure(err) => match err.location { + pest::error::InputLocation::Pos(num) => (num, num + 1), + pest::error::InputLocation::Span((start, end)) => (start, end), + }, + InvalidTopLevelItem(_, sp) => (sp.start(), sp.end()), + Internal(_, sp) => (sp.start(), sp.end()), + UnimplementedRule(_, sp) => (sp.start(), sp.end()), + InvalidByteLiteralLength { span, .. } => (span.start(), span.end()), + ExpectedExprAfterOp { span, .. } => (span.start(), span.end()), + ExpectedOp { span, .. } => (span.start(), span.end()), + UnexpectedWhereClause(sp) => (sp.start(), sp.end()), + UndeclaredGenericTypeInWhereClause { span, .. } => (span.start(), span.end()), + MultiplePredicates(sp) => (sp.start(), sp.end()), + MultipleScripts(sp) => (sp.start(), sp.end()), + MultipleContracts(sp) => (sp.start(), sp.end()), + ConstrainedNonExistentType { span, .. } => (span.start(), span.end()), } } } diff --git a/parser/src/hll.pest b/parser/src/hll.pest index a132fad88ef..7a71f07487e 100644 --- a/parser/src/hll.pest +++ b/parser/src/hll.pest @@ -69,10 +69,12 @@ array_exp = { "[" ~ (expr ~ ("," ~ expr)*) ~ "]" } declaration = {(enum_decl|var_decl|fn_decl|trait_decl|struct_decl)} var_decl = {var_decl_keyword ~ mut_keyword? ~ var_name ~ type_ascription? ~ assign ~ expr ~ ";"} type_ascription = { ":" ~ type_name} -fn_decl = {fn_signature ~ code_block} +fn_decl = {visibility ~ fn_signature ~ code_block} fn_signature = { fn_decl_keyword ~ fn_decl_name ~ type_params? ~ fn_decl_params ~ (fn_returns ~ return_type)? ~ trait_bounds? } var_name = {ident} +visibility = { "pub"? } + struct_decl = { "struct" ~ struct_name ~ type_params? ~ trait_bounds? ~ "{" ~ struct_fields ~ "}" } struct_name = @{ident} struct_fields = { struct_field_name ~ ":" ~ type_name ~ ("," ~ struct_field_name ~ ":" ~ type_name)* ~ ","? } diff --git a/parser/src/lib.rs b/parser/src/lib.rs index e3f83087fea..4e477de729f 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -8,6 +8,7 @@ mod parse_tree; mod parser; mod semantics; pub(crate) mod types; +use crate::error::*; use crate::parse_tree::*; pub(crate) use crate::parse_tree::{ Expression, FunctionDeclaration, FunctionParameter, Literal, UseStatement, @@ -16,12 +17,11 @@ use crate::parser::{HllParser, Rule}; use either::{Either, Left, Right}; use pest::iterators::Pair; use pest::Parser; -pub use semantics::error::CompileError; use semantics::TypedParseTree; use std::collections::HashMap; use types::TypeInfo; -pub use error::{CompileWarning, ParseError, ParseResult}; +pub use error::{CompileError, CompileResult, CompileWarning}; pub use pest::Span; // todo rename to language name @@ -70,9 +70,10 @@ struct ReturnStatement<'sc> { } impl<'sc> ReturnStatement<'sc> { - fn parse_from_pair(pair: Pair<'sc, Rule>) -> ParseResult<'sc, Self> { + fn parse_from_pair(pair: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let span = pair.as_span(); let mut warnings = Vec::new(); + let mut errors = Vec::new(); let mut inner = pair.into_inner(); let _ret_keyword = inner.next(); let expr = inner.next(); @@ -81,11 +82,17 @@ impl<'sc> ReturnStatement<'sc> { expr: Expression::Unit { span }, }, Some(expr_pair) => { - let expr = eval!(Expression::parse_from_pair, warnings, expr_pair); + let expr = eval!( + Expression::parse_from_pair, + warnings, + errors, + expr_pair, + Expression::Unit { span } + ); ReturnStatement { expr } } }; - Ok((res, warnings)) + ok(res, warnings, errors) } } @@ -96,8 +103,9 @@ pub(crate) struct CodeBlock<'sc> { } impl<'sc> CodeBlock<'sc> { - fn parse_from_pair(block: Pair<'sc, Rule>) -> ParseResult<'sc, Self> { + fn parse_from_pair(block: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let mut warnings = Vec::new(); + let mut errors = Vec::new(); let block_inner = block.into_inner(); let mut contents = Vec::new(); for pair in block_inner { @@ -106,7 +114,9 @@ impl<'sc> CodeBlock<'sc> { content: AstNodeContent::Declaration(eval!( Declaration::parse_from_pair, warnings, - pair.clone() + errors, + pair.clone(), + continue )), span: pair.into_span(), }, @@ -114,7 +124,9 @@ impl<'sc> CodeBlock<'sc> { let evaluated_node = eval!( Expression::parse_from_pair, warnings, - pair.clone().into_inner().next().unwrap().clone() + errors, + pair.clone().into_inner().next().unwrap().clone(), + continue ); AstNode { content: AstNodeContent::Expression(evaluated_node), @@ -122,15 +134,26 @@ impl<'sc> CodeBlock<'sc> { } } Rule::return_statement => { - let evaluated_node = - eval!(ReturnStatement::parse_from_pair, warnings, pair.clone()); + let evaluated_node = eval!( + ReturnStatement::parse_from_pair, + warnings, + errors, + pair.clone(), + continue + ); AstNode { content: AstNodeContent::ReturnStatement(evaluated_node), span: pair.as_span(), } } Rule::expr => { - let res = eval!(Expression::parse_from_pair, warnings, pair.clone()); + let res = eval!( + Expression::parse_from_pair, + warnings, + errors, + pair.clone(), + continue + ); AstNode { content: AstNodeContent::ImplicitReturnExpression(res), span: pair.as_span(), @@ -138,15 +161,17 @@ impl<'sc> CodeBlock<'sc> { } a => { println!("In code block parsing: {:?} {:?}", a, pair.as_str()); - return Err(ParseError::Unimplemented(a, pair.as_span())); + errors.push(CompileError::UnimplementedRule(a, pair.as_span())); + continue; } }) } - Ok(( + ok( CodeBlock { contents, scope: /* TODO */ HashMap::default() }, warnings, - )) + errors, + ) } } @@ -164,26 +189,38 @@ impl<'sc> ParseTree<'sc> { } } -pub fn parse<'sc>(input: &'sc str) -> ParseResult<'sc, HllParseTree<'sc>> { - let mut parsed = HllParser::parse(Rule::program, input)?; +pub fn parse<'sc>(input: &'sc str) -> CompileResult<'sc, HllParseTree<'sc>> { let mut warnings: Vec = Vec::new(); + let mut errors: Vec = Vec::new(); + let mut parsed = match HllParser::parse(Rule::program, input) { + Ok(o) => o, + Err(e) => return err(Vec::new(), vec![e.into()]), + }; let res = eval!( parse_root_from_pairs, warnings, - (parsed.next().unwrap().into_inner()) + errors, + (parsed.next().unwrap().into_inner()), + return err(warnings, errors) ); - Ok((res, warnings)) + ok(res, warnings, errors) } -// TODO compile result and not parse result pub fn compile<'sc>( input: &'sc str, -) -> Result<(HllTypedParseTree<'sc>, Vec>), Vec>> { +) -> Result< + (HllTypedParseTree<'sc>, Vec>), + (Vec>, Vec>), +> { let mut warnings = Vec::new(); let mut errors = Vec::new(); - // TODO handle multiple errors from the parse stage - let (parse_tree, mut l_warnings) = parse(input).map_err(|e| vec![e.into()])?; - warnings.append(&mut l_warnings); + let parse_tree = eval!( + parse, + warnings, + errors, + input, + return Err((errors, warnings)) + ); let maybe_contract_tree: Option> = parse_tree .contract_ast @@ -238,7 +275,7 @@ pub fn compile<'sc>( warnings, )) } else { - Err(errors) + Err((errors, warnings)) } } @@ -247,8 +284,9 @@ pub fn compile<'sc>( // sub-nodes fn parse_root_from_pairs<'sc>( input: impl Iterator>, -) -> ParseResult<'sc, HllParseTree<'sc>> { +) -> CompileResult<'sc, HllParseTree<'sc>> { let mut warnings = Vec::new(); + let mut errors = Vec::new(); let mut fuel_ast = HllParseTree { contract_ast: None, script_ast: None, @@ -261,47 +299,62 @@ fn parse_root_from_pairs<'sc>( for pair in input { match pair.as_rule() { Rule::declaration => { - let decl = eval!(Declaration::parse_from_pair, warnings, pair.clone()); + let decl = eval!( + Declaration::parse_from_pair, + warnings, + errors, + pair.clone(), + continue + ); parse_tree.push(AstNode { content: AstNodeContent::Declaration(decl), span: pair.as_span(), }); } Rule::use_statement => { - let stmt = UseStatement::parse_from_pair(pair.clone())?; + let stmt = eval!( + UseStatement::parse_from_pair, + warnings, + errors, + pair.clone(), + continue + ); parse_tree.push(AstNode { content: AstNodeContent::UseStatement(stmt), span: pair.as_span(), }); } - _ => unreachable!(), + a => unreachable!("{:?}", pair.as_str()), } } match rule { Rule::contract => { if fuel_ast.contract_ast.is_some() { - return Err(ParseError::MultipleContracts(block.as_span())); + errors.push(CompileError::MultipleContracts(block.as_span())); + } else { + fuel_ast.contract_ast = Some(parse_tree); } - fuel_ast.contract_ast = Some(parse_tree); } Rule::script => { if fuel_ast.script_ast.is_some() { - return Err(ParseError::MultipleScripts(block.as_span())); + errors.push(CompileError::MultipleScripts(block.as_span())); + } else { + fuel_ast.script_ast = Some(parse_tree); } - fuel_ast.script_ast = Some(parse_tree); } Rule::predicate => { if fuel_ast.predicate_ast.is_some() { - return Err(ParseError::MultiplePredicates(block.as_span())); + errors.push(CompileError::MultiplePredicates(block.as_span())); + } else { + fuel_ast.predicate_ast = Some(parse_tree); } - fuel_ast.predicate_ast = Some(parse_tree); } Rule::EOI => (), - a => return Err(ParseError::InvalidTopLevelItem(a, block.into_span())), + a => errors.push(CompileError::InvalidTopLevelItem(a, block.into_span())), } } - Ok((fuel_ast, warnings)) + ok(fuel_ast, warnings, errors) } #[test] @@ -375,7 +428,7 @@ fn test_basic_prog() { } } - fn prints_number_five(): u8 { + pub fn prints_number_five(): u8 { let x: u8 = 5; let reference_to_x = ref x; let second_value_of_x = deref x; // u8 is `Copy` so this clones diff --git a/parser/src/parse_tree/declaration/enum_declaration.rs b/parser/src/parse_tree/declaration/enum_declaration.rs index 83a92bdb8e6..2ca01e340a6 100644 --- a/parser/src/parse_tree/declaration/enum_declaration.rs +++ b/parser/src/parse_tree/declaration/enum_declaration.rs @@ -1,4 +1,4 @@ -use crate::error::{CompileWarning, ParseResult, Warning}; +use crate::error::*; use crate::parse_tree::declaration::TypeParameter; use crate::parser::{HllParser, Rule}; use crate::types::TypeInfo; @@ -21,9 +21,10 @@ pub(crate) struct EnumVariant<'sc> { } impl<'sc> EnumDeclaration<'sc> { - pub(crate) fn parse_from_pair(decl_inner: Pair<'sc, Rule>) -> ParseResult<'sc, Self> { + pub(crate) fn parse_from_pair(decl_inner: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let whole_enum_span = decl_inner.as_span(); let mut warnings = Vec::new(); + let mut errors = Vec::new(); let mut inner = decl_inner.into_inner(); let _enum_keyword = inner.next().unwrap(); let mut enum_name = None; @@ -49,7 +50,26 @@ impl<'sc> EnumDeclaration<'sc> { } let type_parameters = - TypeParameter::parse_from_type_params_and_where_clause(type_params, where_clause)?; + match TypeParameter::parse_from_type_params_and_where_clause(type_params, where_clause) + { + CompileResult::Ok { + value, + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + value + } + CompileResult::Err { + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + Vec::new() + } + }; // unwrap non-optional fields let enum_name = enum_name.unwrap(); @@ -62,9 +82,15 @@ impl<'sc> EnumDeclaration<'sc> { Warning::NonClassCaseEnumName { enum_name: name } ); - let variants = eval!(EnumVariant::parse_from_pairs, warnings, variants); + let variants = eval!( + EnumVariant::parse_from_pairs, + warnings, + errors, + variants, + Vec::new() + ); - Ok(( + ok( EnumDeclaration { name, type_parameters, @@ -72,15 +98,17 @@ impl<'sc> EnumDeclaration<'sc> { span: whole_enum_span, }, warnings, - )) + errors, + ) } } impl<'sc> EnumVariant<'sc> { pub(crate) fn parse_from_pairs( decl_inner: Option>, - ) -> ParseResult<'sc, Vec> { + ) -> CompileResult<'sc, Vec> { let mut warnings = Vec::new(); + let mut errors = Vec::new(); let mut fields_buf = Vec::new(); if let Some(decl_inner) = decl_inner { let mut fields = decl_inner.into_inner().collect::>(); @@ -93,10 +121,16 @@ impl<'sc> EnumVariant<'sc> { span, Warning::NonClassCaseEnumVariantName { variant_name: name } ); - let r#type = TypeInfo::parse_from_pair_inner(fields[i + 1].clone())?; + let r#type = eval!( + TypeInfo::parse_from_pair_inner, + warnings, + errors, + fields[i + 1].clone(), + TypeInfo::Unit + ); fields_buf.push(EnumVariant { name, r#type }); } } - Ok((fields_buf, warnings)) + ok(fields_buf, warnings, errors) } } diff --git a/parser/src/parse_tree/declaration/function_declaration.rs b/parser/src/parse_tree/declaration/function_declaration.rs index 28f029466ad..d17b800d9d8 100644 --- a/parser/src/parse_tree/declaration/function_declaration.rs +++ b/parser/src/parse_tree/declaration/function_declaration.rs @@ -1,14 +1,30 @@ -use crate::error::{ParseResult, Warning}; +use crate::error::*; use crate::parse_tree::{declaration::TypeParameter, Expression, VarName}; use crate::types::TypeInfo; -use crate::{CodeBlock, ParseError, Rule}; +use crate::{CodeBlock, CompileError, Rule}; use either::Either; use inflector::cases::snakecase::is_snake_case; use pest::iterators::Pair; +#[derive(Debug, Clone)] +pub(crate) enum Visibility { + Public, + Private, +} + +impl Visibility { + pub(crate) fn parse_from_pair<'sc>(input: Pair<'sc, Rule>) -> Self { + match input.as_str().trim() { + "pub" => Visibility::Public, + _ => Visibility::Private, + } + } +} + #[derive(Debug, Clone)] pub(crate) struct FunctionDeclaration<'sc> { pub(crate) name: &'sc str, + pub(crate) visibility: Visibility, pub(crate) body: CodeBlock<'sc>, pub(crate) parameters: Vec>, pub(crate) span: pest::Span<'sc>, @@ -17,10 +33,19 @@ pub(crate) struct FunctionDeclaration<'sc> { } impl<'sc> FunctionDeclaration<'sc> { - pub(crate) fn parse_from_pair(pair: Pair<'sc, Rule>) -> ParseResult<'sc, Self> { + pub(crate) fn parse_from_pair(pair: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let mut parts = pair.clone().into_inner(); let mut warnings = Vec::new(); - let mut signature = parts.next().unwrap().into_inner(); + let mut errors = Vec::new(); + let mut signature_or_visibility = parts.next().unwrap(); + let (visibility, mut signature) = if signature_or_visibility.as_rule() == Rule::visibility { + ( + Visibility::parse_from_pair(signature_or_visibility), + parts.next().unwrap().into_inner(), + ) + } else { + (Visibility::Private, signature_or_visibility.into_inner()) + }; let _fn_keyword = signature.next().unwrap(); let name = signature.next().unwrap(); let name_span = name.as_span(); @@ -57,28 +82,69 @@ impl<'sc> FunctionDeclaration<'sc> { // these are non-optional in a func decl let parameters_pair = parameters_pair.unwrap(); - let parameters = FunctionParameter::list_from_pairs(parameters_pair.into_inner())?; + let parameters = eval!( + FunctionParameter::list_from_pairs, + warnings, + errors, + parameters_pair.into_inner(), + Vec::new() + ); let return_type = match return_type_pair { - Some(pair) => TypeInfo::parse_from_pair(pair)?, + Some(pair) => eval!( + TypeInfo::parse_from_pair, + warnings, + errors, + pair, + TypeInfo::Unit + ), None => TypeInfo::Unit, }; - let type_parameters = TypeParameter::parse_from_type_params_and_where_clause( + let type_parameters = match TypeParameter::parse_from_type_params_and_where_clause( type_params_pair, where_clause_pair, - )?; + ) { + CompileResult::Ok { + value, + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + value + } + CompileResult::Err { + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + Vec::new() + } + }; let body = parts.next().unwrap(); - let body = eval!(CodeBlock::parse_from_pair, warnings, body); - Ok(( + let body = eval!( + CodeBlock::parse_from_pair, + warnings, + errors, + body, + crate::CodeBlock { + contents: Vec::new(), + scope: Default::default() + } + ); + ok( FunctionDeclaration { name, parameters, + visibility, body, span: pair.as_span(), return_type, type_parameters, }, warnings, - )) + errors, + ) } } @@ -91,20 +157,38 @@ pub(crate) struct FunctionParameter<'sc> { impl<'sc> FunctionParameter<'sc> { pub(crate) fn list_from_pairs( pairs: impl Iterator>, - ) -> Result>, ParseError<'sc>> { - pairs - .map(|pair: Pair<'sc, Rule>| { - let mut parts = pair.clone().into_inner(); - let name_pair = parts.next().unwrap(); - let name_str = name_pair.as_str(); - let name = VarName::parse_from_pair(name_pair)?; - let r#type = if name_str == "self" { - TypeInfo::SelfType - } else { - TypeInfo::parse_from_pair_inner(parts.next().unwrap())? - }; - Ok(FunctionParameter { name, r#type }) - }) - .collect() + ) -> CompileResult<'sc, Vec>> { + let mut warnings = Vec::new(); + let mut errors = Vec::new(); + let mut pairs_buf = Vec::new(); + for pair in pairs { + let mut parts = pair.clone().into_inner(); + let name_pair = parts.next().unwrap(); + let name_str = name_pair.as_str(); + let name = eval!( + VarName::parse_from_pair, + warnings, + errors, + name_pair, + VarName { + primary_name: "error parsing var name", + sub_names: Vec::new(), + span: name_pair.as_span() + } + ); + let r#type = if name_str == "self" { + TypeInfo::SelfType + } else { + eval!( + TypeInfo::parse_from_pair_inner, + warnings, + errors, + parts.next().unwrap(), + TypeInfo::ErrorRecovery + ) + }; + pairs_buf.push(FunctionParameter { name, r#type }); + } + ok(pairs_buf, warnings, errors) } } diff --git a/parser/src/parse_tree/declaration/mod.rs b/parser/src/parse_tree/declaration/mod.rs index a610b47e578..1bdced39286 100644 --- a/parser/src/parse_tree/declaration/mod.rs +++ b/parser/src/parse_tree/declaration/mod.rs @@ -12,7 +12,7 @@ pub(crate) use trait_declaration::*; pub(crate) use type_parameter::*; pub(crate) use variable_declaration::*; -use crate::error::{ParseError, ParseResult}; +use crate::error::*; use crate::parse_tree::{Expression, VarName}; use crate::parser::{HllParser, Rule}; use crate::types::TypeInfo; @@ -25,17 +25,21 @@ pub(crate) enum Declaration<'sc> { TraitDeclaration(TraitDeclaration<'sc>), StructDeclaration(StructDeclaration<'sc>), EnumDeclaration(EnumDeclaration<'sc>), + ErrorRecovery, } impl<'sc> Declaration<'sc> { - pub(crate) fn parse_from_pair(decl: Pair<'sc, Rule>) -> ParseResult<'sc, Self> { + pub(crate) fn parse_from_pair(decl: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let mut warnings = Vec::new(); + let mut errors = Vec::new(); let mut pair = decl.clone().into_inner(); let decl_inner = pair.next().unwrap(); let parsed_declaration = match decl_inner.as_rule() { Rule::fn_decl => Declaration::FunctionDeclaration(eval!( FunctionDeclaration::parse_from_pair, warnings, - decl_inner + errors, + decl_inner, + return err(warnings, errors) )), Rule::var_decl => { let mut var_decl_parts = decl_inner.into_inner(); @@ -56,11 +60,36 @@ impl<'sc> Declaration<'sc> { } _ => None, }; - let type_ascription = - invert(type_ascription.map(|x| TypeInfo::parse_from_pair(x)))?; - let body = eval!(Expression::parse_from_pair, warnings, maybe_body); + let type_ascription = if let Some(ascription) = type_ascription { + Some(eval!( + TypeInfo::parse_from_pair, + warnings, + errors, + ascription, + TypeInfo::Unit + )) + } else { + None + }; + let body = eval!( + Expression::parse_from_pair, + warnings, + errors, + maybe_body, + return err(warnings, errors) + ); Declaration::VariableDeclaration(VariableDeclaration { - name: VarName::parse_from_pair(name_pair)?, + name: eval!( + VarName::parse_from_pair, + warnings, + errors, + name_pair, + VarName { + primary_name: "parse failure", + sub_names: Vec::new(), + span: name_pair.as_span() + } + ), body, is_mutable, type_ascription, @@ -69,25 +98,26 @@ impl<'sc> Declaration<'sc> { Rule::trait_decl => Declaration::TraitDeclaration(eval!( TraitDeclaration::parse_from_pair, warnings, - decl_inner + errors, + decl_inner, + return err(warnings, errors) )), Rule::struct_decl => Declaration::StructDeclaration(eval!( StructDeclaration::parse_from_pair, warnings, - decl_inner + errors, + decl_inner, + return err(warnings, errors) )), Rule::enum_decl => Declaration::EnumDeclaration(eval!( EnumDeclaration::parse_from_pair, warnings, - decl_inner + errors, + decl_inner, + return err(warnings, errors) )), a => unreachable!("declarations don't have any other sub-types: {:?}", a), }; - Ok((parsed_declaration, warnings)) + ok(parsed_declaration, warnings, errors) } } - -// option res to res option helper -fn invert(x: Option>) -> Result, E> { - x.map_or(Ok(None), |v| v.map(Some)) -} diff --git a/parser/src/parse_tree/declaration/struct_declaration.rs b/parser/src/parse_tree/declaration/struct_declaration.rs index 7f9277457b1..73d50bbb6be 100644 --- a/parser/src/parse_tree/declaration/struct_declaration.rs +++ b/parser/src/parse_tree/declaration/struct_declaration.rs @@ -1,4 +1,4 @@ -use crate::error::{CompileWarning, ParseError, ParseResult, Warning}; +use crate::error::*; use crate::parse_tree::declaration::TypeParameter; use crate::parser::{HllParser, Rule}; use crate::types::TypeInfo; @@ -20,8 +20,9 @@ pub(crate) struct StructField<'sc> { } impl<'sc> StructDeclaration<'sc> { - pub(crate) fn parse_from_pair(decl: Pair<'sc, Rule>) -> ParseResult<'sc, Self> { + pub(crate) fn parse_from_pair(decl: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let mut warnings = Vec::new(); + let mut errors = Vec::new(); let mut decl = decl.into_inner(); let name = decl.next().unwrap(); let mut type_params_pair = None; @@ -42,13 +43,37 @@ impl<'sc> StructDeclaration<'sc> { } } - let type_parameters = TypeParameter::parse_from_type_params_and_where_clause( + let type_parameters = match TypeParameter::parse_from_type_params_and_where_clause( type_params_pair, where_clause_pair, - )?; + ) { + CompileResult::Ok { + value, + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + value + } + CompileResult::Err { + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + Vec::new() + } + }; let fields = if let Some(fields) = fields_pair { - eval!(StructField::parse_from_pairs, warnings, fields) + eval!( + StructField::parse_from_pairs, + warnings, + errors, + fields, + Vec::new() + ) } else { Vec::new() }; @@ -61,20 +86,22 @@ impl<'sc> StructDeclaration<'sc> { span, Warning::NonClassCaseStructName { struct_name: name } ); - Ok(( + ok( StructDeclaration { name, fields, type_parameters, }, warnings, - )) + errors, + ) } } impl<'sc> StructField<'sc> { - pub(crate) fn parse_from_pairs(pair: Pair<'sc, Rule>) -> ParseResult<'sc, Vec> { + pub(crate) fn parse_from_pairs(pair: Pair<'sc, Rule>) -> CompileResult<'sc, Vec> { let mut warnings = Vec::new(); + let mut errors = Vec::new(); let mut fields = pair.into_inner().collect::>(); let mut fields_buf = Vec::new(); for i in (0..fields.len()).step_by(2) { @@ -86,9 +113,15 @@ impl<'sc> StructField<'sc> { span, Warning::NonSnakeCaseStructFieldName { field_name: name } ); - let r#type = TypeInfo::parse_from_pair_inner(fields[i + 1].clone())?; + let r#type = eval!( + TypeInfo::parse_from_pair_inner, + warnings, + errors, + fields[i + 1].clone(), + TypeInfo::Unit + ); fields_buf.push(StructField { name, r#type }); } - Ok((fields_buf, warnings)) + ok(fields_buf, warnings, errors) } } diff --git a/parser/src/parse_tree/declaration/trait_declaration.rs b/parser/src/parse_tree/declaration/trait_declaration.rs index 649a56c8fc7..e7bd0007dad 100644 --- a/parser/src/parse_tree/declaration/trait_declaration.rs +++ b/parser/src/parse_tree/declaration/trait_declaration.rs @@ -1,9 +1,10 @@ use super::{FunctionDeclaration, FunctionParameter}; -use crate::error::{ParseError, ParseResult}; +use crate::error::*; use crate::parse_tree::VarName; use crate::parser::{HllParser, Rule}; use crate::types::TypeInfo; use either::*; +use inflector::cases::snakecase::is_snake_case; use pest::iterators::Pair; #[derive(Debug, Clone)] @@ -14,8 +15,9 @@ pub(crate) struct TraitDeclaration<'sc> { } impl<'sc> TraitDeclaration<'sc> { - pub(crate) fn parse_from_pair(pair: Pair<'sc, Rule>) -> ParseResult<'sc, Self> { + pub(crate) fn parse_from_pair(pair: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let mut warnings = Vec::new(); + let mut errors = Vec::new(); let mut trait_parts = pair.into_inner(); let _trait_keyword = trait_parts.next(); let name_pair = trait_parts.next().unwrap(); @@ -24,48 +26,43 @@ impl<'sc> TraitDeclaration<'sc> { sub_names: vec![], span: name_pair.as_span(), }; - let methods_and_interface = trait_parts - .next() - .map(|if_some: Pair<'sc, Rule>| -> Result<_, ParseError> { - if_some - .into_inner() - .map( - |fn_sig_or_decl| -> Result< - Either, FunctionDeclaration<'sc>>, - ParseError, - > { - Ok(match fn_sig_or_decl.as_rule() { - Rule::fn_signature => { - Left(TraitFn::parse_from_pair(fn_sig_or_decl)?) - } - Rule::fn_decl => Right(eval!( - FunctionDeclaration::parse_from_pair, - warnings, - fn_sig_or_decl - )), - _ => unreachable!(), - }) - }, - ) - .collect::, ParseError>>() - }) - .unwrap_or_else(|| Ok(Vec::new()))?; - - let mut interface_surface = Vec::new(); let mut methods = Vec::new(); - methods_and_interface.into_iter().for_each(|x| match x { - Left(x) => interface_surface.push(x), - Right(x) => methods.push(x), - }); + let mut interface = Vec::new(); - Ok(( + if let Some(methods_and_interface) = trait_parts.next() { + for fn_sig_or_decl in methods_and_interface.into_inner() { + match fn_sig_or_decl.as_rule() { + Rule::fn_signature => { + interface.push(eval!( + TraitFn::parse_from_pair, + warnings, + errors, + fn_sig_or_decl, + continue + )); + } + Rule::fn_decl => { + methods.push(eval!( + FunctionDeclaration::parse_from_pair, + warnings, + errors, + fn_sig_or_decl, + continue + )); + } + _ => unreachable!(), + } + } + } + ok( TraitDeclaration { name, - interface_surface, + interface_surface: interface, methods, }, warnings, - )) + errors, + ) } } @@ -77,22 +74,48 @@ pub(crate) struct TraitFn<'sc> { } impl<'sc> TraitFn<'sc> { - fn parse_from_pair(pair: Pair<'sc, Rule>) -> Result> { + fn parse_from_pair(pair: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { + let mut warnings = Vec::new(); + let mut errors = Vec::new(); let mut signature = pair.clone().into_inner(); let _fn_keyword = signature.next().unwrap(); - let name = signature.next().unwrap().as_str(); + let name = signature.next().unwrap(); + let mut name_span = name.as_span(); + let name = name.as_str(); + assert_or_warn!( + is_snake_case(name), + warnings, + name_span, + Warning::NonSnakeCaseFunctionName { name } + ); let parameters = signature.next().unwrap(); - let parameters = FunctionParameter::list_from_pairs(parameters.into_inner())?; + let parameters = eval!( + FunctionParameter::list_from_pairs, + warnings, + errors, + parameters.into_inner(), + Vec::new() + ); let return_type_signal = signature.next(); let return_type = match return_type_signal { - Some(_) => TypeInfo::parse_from_pair(signature.next().unwrap())?, + Some(_) => eval!( + TypeInfo::parse_from_pair, + warnings, + errors, + signature.next().unwrap(), + TypeInfo::ErrorRecovery + ), None => TypeInfo::Unit, }; - Ok(TraitFn { - name, - parameters, - return_type, - }) + ok( + TraitFn { + name, + parameters, + return_type, + }, + warnings, + errors, + ) } } diff --git a/parser/src/parse_tree/declaration/type_parameter.rs b/parser/src/parse_tree/declaration/type_parameter.rs index d2e958d2cbc..f2d5697eccd 100644 --- a/parser/src/parse_tree/declaration/type_parameter.rs +++ b/parser/src/parse_tree/declaration/type_parameter.rs @@ -1,5 +1,6 @@ +use crate::error::*; use crate::parse_tree::Expression; -use crate::{CodeBlock, ParseError, Rule}; +use crate::{CodeBlock, CompileError, Rule}; use either::Either; use pest::iterators::Pair; #[derive(Debug, Clone)] @@ -12,7 +13,8 @@ impl<'sc> TypeParameter<'sc> { pub(crate) fn parse_from_type_params_and_where_clause( type_params_pair: Option>, where_clause_pair: Option>, - ) -> Result>, ParseError<'sc>> { + ) -> CompileResult<'sc, Vec>> { + let mut errors = Vec::new(); let mut params: Vec = match type_params_pair { Some(type_params_pair) => type_params_pair .into_inner() @@ -24,9 +26,12 @@ impl<'sc> TypeParameter<'sc> { None => { // no type params specified, ensure where clause is empty if let Some(where_clause_pair) = where_clause_pair { - return Err(ParseError::UnexpectedWhereClause( - where_clause_pair.as_span(), - )); + return err( + Vec::new(), + vec![CompileError::UnexpectedWhereClause( + where_clause_pair.as_span(), + )], + ); } Vec::new() } @@ -40,11 +45,29 @@ impl<'sc> TypeParameter<'sc> { let trait_constraint = pair.next().unwrap(); assert_eq!(trait_constraint.as_rule(), Rule::trait_name); // assign trait constraints to above parsed type params + // find associated type name + let mut param_to_edit = match params + .iter_mut() + .find(|TypeParameter { name, .. }| *name == type_param.as_str()) + { + Some(o) => o, + None => { + errors.push(CompileError::ConstrainedNonExistentType { + type_name: type_param.as_str(), + trait_name: trait_constraint.as_str(), + span: trait_constraint.as_span(), + }); + continue; + } + }; + param_to_edit.trait_constraint.push(TraitConstraint { + name: trait_constraint.as_str(), + }); } } None => (), } - Ok(params) + ok(params, Vec::new(), errors) } } @@ -52,7 +75,7 @@ fn find_and_update_param<'sc>( mut params: Vec>, param_to_update: Pair<'sc, Rule>, trait_name_to_add: &'sc str, -) -> Result<(), ParseError<'sc>> { +) -> Result<(), CompileError<'sc>> { let mut found = false; for mut param in params { if param.name == param_to_update.as_str() { @@ -63,7 +86,7 @@ fn find_and_update_param<'sc>( } } if !found { - return Err(ParseError::UndeclaredGenericTypeInWhereClause { + return Err(CompileError::UndeclaredGenericTypeInWhereClause { span: param_to_update.as_span(), type_name: param_to_update.as_str(), }); diff --git a/parser/src/parse_tree/expression.rs b/parser/src/parse_tree/expression.rs index 9da34962f8a..ea79af7bc4f 100644 --- a/parser/src/parse_tree/expression.rs +++ b/parser/src/parse_tree/expression.rs @@ -1,7 +1,10 @@ +use crate::error::*; use crate::parse_tree::Literal; -use std::hash::{Hash, Hasher}; +use std::{ + collections::HashMap, + hash::{Hash, Hasher}, +}; #[macro_use] -use crate::error::{ParseError, ParseResult}; use crate::parser::{HllParser, Rule}; use crate::CodeBlock; use either::Either; @@ -80,27 +83,62 @@ impl<'sc> Expression<'sc> { }) .clone() } - pub(crate) fn parse_from_pair(expr: Pair<'sc, Rule>) -> ParseResult<'sc, Self> { + pub(crate) fn parse_from_pair(expr: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let mut warnings = Vec::new(); + let mut errors = Vec::new(); let expr_for_debug = expr.clone(); let mut expr_iter = expr.into_inner(); // first expr is always here let first_expr = expr_iter.next().unwrap(); - let first_expr = eval!(Expression::parse_from_pair_inner, warnings, first_expr); + let first_expr = eval!( + Expression::parse_from_pair_inner, + warnings, + errors, + first_expr, + Expression::Unit { + span: first_expr.as_span() + } + ); let mut expr_or_op_buf: Vec> = vec![Either::Right(first_expr.clone())]; // sometimes exprs are followed by ops in the same expr while let Some(op) = expr_iter.next() { let op_str = op.as_str(); - let op = parse_op(op)?; + let op_span = op.as_span(); + let op = match parse_op(op) { + CompileResult::Ok { + warnings: mut l_w, + value, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + value + } + CompileResult::Err { + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + return err(warnings, errors); + } + }; // an op is necessarily followed by an expression let next_expr = match expr_iter.next() { - Some(o) => eval!(Expression::parse_from_pair_inner, warnings, o), + Some(o) => eval!( + Expression::parse_from_pair_inner, + warnings, + errors, + o, + Expression::Unit { span: o.as_span() } + ), None => { - return Err(ParseError::ExpectedExprAfterOp { + errors.push(CompileError::ExpectedExprAfterOp { op: op_str, span: expr_for_debug.as_span(), - }) + }); + Expression::Unit { span: op_span } } }; // pushing these into a vec in this manner so we can re-associate according to order of @@ -114,47 +152,90 @@ impl<'sc> Expression<'sc> { */ } if expr_or_op_buf.len() == 1 { - Ok((first_expr, warnings)) + ok(first_expr, warnings, errors) } else { - let (expr, mut l_warnings) = - arrange_by_order_of_operations(expr_or_op_buf, expr_for_debug.as_span())?; - warnings.append(&mut l_warnings); - Ok((expr, warnings)) + let expr = + match arrange_by_order_of_operations(expr_or_op_buf, expr_for_debug.as_span()) { + CompileResult::Ok { + value, + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + value + } + CompileResult::Err { + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + Expression::Unit { + span: expr_for_debug.as_span(), + } + } + }; + ok(expr, warnings, errors) } } - pub(crate) fn parse_from_pair_inner(expr: Pair<'sc, Rule>) -> ParseResult<'sc, Self> { + pub(crate) fn parse_from_pair_inner(expr: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { + let mut errors = Vec::new(); let mut warnings = Vec::new(); let span = expr.as_span(); let parsed = match expr.as_rule() { - Rule::literal_value => Expression::Literal { - value: Literal::parse_from_pair(expr.clone())?, - span: expr.as_span(), + Rule::literal_value => match Literal::parse_from_pair(expr.clone()) { + CompileResult::Ok { + value, + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + Expression::Literal { value, span } + } + CompileResult::Err { + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + Expression::Unit { span } + } }, Rule::func_app => { let span = expr.as_span(); let mut func_app_parts = expr.into_inner(); - let name = VarName::parse_from_pair(func_app_parts.next().unwrap())?; + let name = eval!( + VarName::parse_from_pair, + warnings, + errors, + func_app_parts.next().unwrap(), + VarName { + primary_name: "error parsing var name", + sub_names: Vec::new(), + span: span.clone() + } + ); let arguments = func_app_parts.next(); - let arguments = arguments.map(|x| { - x.into_inner() - .map(|x| Expression::parse_from_pair_inner(x)) - .collect::, _>>() - }); - - let mut arguments = arguments.unwrap_or_else(|| Ok(Vec::new()))?; - let mut local_warnings = arguments.iter_mut().map(|(_, x)| x.clone()); - let mut warn_buf = Vec::new(); - for mut warning in local_warnings { - warn_buf.append(&mut warning); + let mut arguments_buf = Vec::new(); + for argument in arguments { + let arg = eval!( + Expression::parse_from_pair, + warnings, + errors, + argument, + Expression::Unit { + span: argument.as_span() + } + ); + arguments_buf.push(arg); } - warnings.append(&mut warn_buf); - - let arguments = arguments.into_iter().map(|(x, _)| x).collect(); Expression::FunctionApplication { name, - arguments, + arguments: arguments_buf, span, } } @@ -167,10 +248,21 @@ impl<'sc> Expression<'sc> { while let Some(pair) = var_exp_parts.next() { match pair.as_rule() { Rule::unary_op => { - unary_op = Some(UnaryOp::parse_from_pair(pair)?); + unary_op = + eval!(UnaryOp::parse_from_pair, warnings, errors, pair, None); } Rule::var_name_ident => { - name = Some(VarName::parse_from_pair(pair)?); + name = Some(eval!( + VarName::parse_from_pair, + warnings, + errors, + pair, + VarName { + primary_name: "error parsing var name", + sub_names: Vec::new(), + span: span.clone() + } + )); } a => unreachable!("what is this? {:?} {}", a, pair.as_str()), } @@ -187,7 +279,13 @@ impl<'sc> Expression<'sc> { let mut array_exps = expr.into_inner(); let mut contents = Vec::new(); for expr in array_exps { - contents.push(eval!(Expression::parse_from_pair, warnings, expr)); + contents.push(eval!( + Expression::parse_from_pair, + warnings, + errors, + expr, + Expression::Unit { span: span.clone() } + )); } Expression::Array { contents, span } } @@ -196,12 +294,24 @@ impl<'sc> Expression<'sc> { let primary_expression = eval!( Expression::parse_from_pair, warnings, - expr_iter.next().unwrap() + errors, + expr_iter.next().unwrap(), + Expression::Unit { span: span.clone() } ); let primary_expression = Box::new(primary_expression); let mut branches = Vec::new(); for exp in expr_iter { - let res = eval!(MatchBranch::parse_from_pair, warnings, exp); + let res = eval!( + MatchBranch::parse_from_pair, + warnings, + errors, + exp, + MatchBranch { + condition: MatchCondition::CatchAll, + result: Expression::Unit { span: span.clone() }, + span: span.clone() + } + ); branches.push(res); } Expression::MatchExpression { @@ -217,7 +327,13 @@ impl<'sc> Expression<'sc> { let mut fields_buf = Vec::new(); for i in (0..fields.len()).step_by(2) { let name = fields[i].as_str(); - let value = eval!(Expression::parse_from_pair, warnings, fields[i + 1].clone()); + let value = eval!( + Expression::parse_from_pair, + warnings, + errors, + fields[i + 1].clone(), + Expression::Unit { span: span.clone() } + ); fields_buf.push(StructExpressionField { name, value }); } // TODO add warning for capitalization on struct name @@ -231,7 +347,11 @@ impl<'sc> Expression<'sc> { let expr = eval!( Expression::parse_from_pair, warnings, - expr.into_inner().next().unwrap() + errors, + expr.clone().into_inner().next().unwrap(), + Expression::Unit { + span: expr.as_span() + } ); Expression::ParenthesizedExpression { inner: Box::new(expr), @@ -239,7 +359,16 @@ impl<'sc> Expression<'sc> { } } Rule::code_block => { - let expr = eval!(crate::CodeBlock::parse_from_pair, warnings, expr); + let expr = eval!( + crate::CodeBlock::parse_from_pair, + warnings, + errors, + expr, + crate::CodeBlock { + contents: Vec::new(), + scope: Default::default() + } + ); Expression::CodeBlock { contents: expr, span, @@ -251,18 +380,27 @@ impl<'sc> Expression<'sc> { let condition_pair = if_exp_pairs.next().unwrap(); let then_pair = if_exp_pairs.next().unwrap(); let else_pair = if_exp_pairs.next(); - let condition = - Box::new(eval!(Expression::parse_from_pair, warnings, condition_pair)); + let condition = Box::new(eval!( + Expression::parse_from_pair, + warnings, + errors, + condition_pair, + Expression::Unit { span: span.clone() } + )); let then = Box::new(eval!( Expression::parse_from_pair_inner, warnings, - then_pair + errors, + then_pair, + Expression::Unit { span: span.clone() } )); let r#else = match else_pair { Some(else_pair) => Some(Box::new(eval!( Expression::parse_from_pair_inner, warnings, - else_pair + errors, + else_pair, + Expression::Unit { span: span.clone() } ))), None => None, }; @@ -280,10 +418,14 @@ impl<'sc> Expression<'sc> { expr.as_str(), expr.as_rule() ); - return Err(ParseError::Unimplemented(a, expr.as_span())); + errors.push(CompileError::UnimplementedRule(a, expr.as_span())); + // construct unit expression for error recovery + Expression::Unit { + span: expr.as_span(), + } } }; - Ok((parsed, warnings)) + ok(parsed, warnings, errors) } } @@ -301,22 +443,30 @@ pub(crate) enum MatchCondition<'sc> { } impl<'sc> MatchBranch<'sc> { - fn parse_from_pair(pair: Pair<'sc, Rule>) -> ParseResult<'sc, Self> { + fn parse_from_pair(pair: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let mut warnings = Vec::new(); + let mut errors = Vec::new(); let span = pair.as_span(); let mut branch = pair.clone().into_inner(); let condition = match branch.next() { Some(o) => o, None => { - return Err(ParseError::Internal( + errors.push(CompileError::Internal( "Unexpected empty iterator in match branch parsing.", pair.as_span(), - )) + )); + return err(warnings, errors); } }; let condition = match condition.into_inner().next() { Some(e) => { - let expr = eval!(Expression::parse_from_pair, warnings, e); + let expr = eval!( + Expression::parse_from_pair, + warnings, + errors, + e, + Expression::Unit { span: e.as_span() } + ); MatchCondition::Expression(expr) } // the "_" case @@ -325,31 +475,50 @@ impl<'sc> MatchBranch<'sc> { let result = match branch.next() { Some(o) => o, None => { - return Err(ParseError::Internal( + errors.push(CompileError::Internal( "Unexpected empty iterator in match branch parsing.", pair.as_span(), - )) + )); + return err(warnings, errors); } }; let result = match result.as_rule() { - Rule::expr => eval!(Expression::parse_from_pair, warnings, result), + Rule::expr => eval!( + Expression::parse_from_pair, + warnings, + errors, + result, + Expression::Unit { + span: result.as_span() + } + ), Rule::code_block => { let span = result.as_span(); Expression::CodeBlock { - contents: eval!(CodeBlock::parse_from_pair, warnings, result), + contents: eval!( + CodeBlock::parse_from_pair, + warnings, + errors, + result, + CodeBlock { + contents: Vec::new(), + scope: HashMap::default() + } + ), span, } } _ => unreachable!(), }; - Ok(( + ok( MatchBranch { condition, result, span, }, warnings, - )) + errors, + ) } } @@ -361,16 +530,19 @@ pub(crate) enum UnaryOp { } impl UnaryOp { - fn parse_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result> { + fn parse_from_pair<'sc>(pair: Pair<'sc, Rule>) -> CompileResult<'sc, Option> { use UnaryOp::*; match pair.as_str() { - "!" => Ok(Not), - "ref" => Ok(Ref), - "deref" => Ok(Deref), - _ => Err(ParseError::Internal( - "Attempted to parse unary op from invalid op string.", - pair.as_span(), - )), + "!" => ok(Some(Not), Vec::new(), Vec::new()), + "ref" => ok(Some(Ref), Vec::new(), Vec::new()), + "deref" => ok(Some(Deref), Vec::new(), Vec::new()), + _ => { + let errors = vec![CompileError::Internal( + "Attempted to parse unary op from invalid op string.", + pair.as_span(), + )]; + return err(Vec::new(), errors); + } } } } @@ -403,7 +575,7 @@ impl PartialEq for VarName<'_> { impl Eq for VarName<'_> {} impl<'sc> VarName<'sc> { - pub(crate) fn parse_from_pair(pair: Pair<'sc, Rule>) -> Result, ParseError<'sc>> { + pub(crate) fn parse_from_pair(pair: Pair<'sc, Rule>) -> CompileResult<'sc, VarName> { let span = { let pair = pair.clone(); if pair.as_rule() != Rule::ident { @@ -415,16 +587,21 @@ impl<'sc> VarName<'sc> { let mut names = pair.into_inner(); let primary_name = names.next().unwrap().as_str(); let sub_names = names.map(|x| x.as_str()).collect(); - Ok(VarName { - primary_name, - sub_names, - span, - }) + ok( + VarName { + primary_name, + sub_names, + span, + }, + Vec::new(), + Vec::new(), + ) } } -fn parse_op<'sc>(op: Pair<'sc, Rule>) -> Result> { +fn parse_op<'sc>(op: Pair<'sc, Rule>) -> CompileResult<'sc, Op> { use OpVariant::*; + let mut errors = Vec::new(); let op_variant = match op.as_str() { "+" => Add, "-" => Subtract, @@ -439,16 +616,21 @@ fn parse_op<'sc>(op: Pair<'sc, Rule>) -> Result> { "|" => BinaryOr, "&" => BinaryAnd, a => { - return Err(ParseError::ExpectedOp { + errors.push(CompileError::ExpectedOp { op: a, span: op.as_span(), - }) + }); + return err(Vec::new(), errors); } }; - Ok(Op { - span: op.as_span(), - op_variant, - }) + ok( + Op { + span: op.as_span(), + op_variant, + }, + Vec::new(), + errors, + ) } #[derive(Debug)] @@ -522,7 +704,8 @@ impl OpVariant { fn arrange_by_order_of_operations<'sc>( expressions: Vec, Expression<'sc>>>, debug_span: Span<'sc>, -) -> ParseResult<'sc, Expression<'sc>> { +) -> CompileResult<'sc, Expression<'sc>> { + let mut errors = Vec::new(); let warnings = Vec::new(); let mut expression_stack = Vec::new(); let mut op_stack = Vec::new(); @@ -540,16 +723,18 @@ fn arrange_by_order_of_operations<'sc>( let lhs = expression_stack.pop(); let new_op = op_stack.pop().unwrap(); if lhs.is_none() { - return Err(ParseError::Internal( + errors.push(CompileError::Internal( "Prematurely empty expression stack for left hand side.", debug_span, )); + return err(warnings, errors); } if rhs.is_none() { - return Err(ParseError::Internal( + errors.push(CompileError::Internal( "Prematurely empty expression stack for right hand side.", debug_span, )); + return err(warnings, errors); } let lhs = lhs.unwrap(); let rhs = rhs.unwrap(); @@ -571,16 +756,18 @@ fn arrange_by_order_of_operations<'sc>( let lhs = expression_stack.pop(); if lhs.is_none() { - return Err(ParseError::Internal( + errors.push(CompileError::Internal( "Prematurely empty expression stack for left hand side.", debug_span, )); + return err(warnings, errors); } if rhs.is_none() { - return Err(ParseError::Internal( + errors.push(CompileError::Internal( "Prematurely empty expression stack for right hand side.", debug_span, )); + return err(warnings, errors); } let lhs = lhs.unwrap(); @@ -594,11 +781,12 @@ fn arrange_by_order_of_operations<'sc>( } if expression_stack.len() != 1 { - return Err(ParseError::Internal( + errors.push(CompileError::Internal( "Invalid expression stack length", debug_span, )); + return err(warnings, errors); } - Ok((expression_stack[0].clone(), warnings)) + ok(expression_stack[0].clone(), warnings, errors) } diff --git a/parser/src/parse_tree/literal.rs b/parser/src/parse_tree/literal.rs index ece072192b8..cc983d76d03 100644 --- a/parser/src/parse_tree/literal.rs +++ b/parser/src/parse_tree/literal.rs @@ -1,5 +1,6 @@ +use crate::error::*; use crate::parser::Rule; -use crate::ParseError; +use crate::CompileError; use pest::iterators::Pair; use std::convert::TryInto; @@ -17,96 +18,115 @@ pub(crate) enum Literal<'sc> { } impl<'sc> Literal<'sc> { - pub(crate) fn parse_from_pair(lit: Pair<'sc, Rule>) -> Result> { + pub(crate) fn parse_from_pair(lit: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let lit_inner = lit.into_inner().next().unwrap(); - let parsed = match lit_inner.as_rule() { - Rule::integer => { - let mut int_inner = lit_inner.into_inner().next().unwrap(); - let rule = int_inner.as_rule(); - if int_inner.as_rule() != Rule::basic_integer { - int_inner = int_inner.into_inner().next().unwrap() - } - match rule { - Rule::u8_integer => { - Literal::U8(int_inner.as_str().trim().parse().map_err(|e| { - ParseError::Internal( - "Called incorrect internal parser on literal type.", - int_inner.into_span(), - ) - })?) - } - Rule::u16_integer => { - Literal::U16(int_inner.as_str().trim().parse().map_err(|e| { - ParseError::Internal( - "Called incorrect internal parser on literal type.", - int_inner.into_span(), - ) - })?) + let parsed: Result = + match lit_inner.as_rule() { + Rule::integer => { + let mut int_inner = lit_inner.into_inner().next().unwrap(); + let rule = int_inner.as_rule(); + if int_inner.as_rule() != Rule::basic_integer { + int_inner = int_inner.into_inner().next().unwrap() } - Rule::u32_integer => { - Literal::U32(int_inner.as_str().trim().parse().map_err(|e| { - ParseError::Internal( - "Called incorrect internal parser on literal type.", - int_inner.into_span(), - ) - })?) + match rule { + Rule::u8_integer => int_inner + .as_str() + .trim() + .parse() + .map(Literal::U8) + .map_err(|e| { + CompileError::Internal( + "Called incorrect internal parser on literal type.", + int_inner.into_span(), + ) + }), + Rule::u16_integer => int_inner + .as_str() + .trim() + .parse() + .map(Literal::U16) + .map_err(|e| { + CompileError::Internal( + "Called incorrect internal parser on literal type.", + int_inner.into_span(), + ) + }), + Rule::u32_integer => int_inner + .as_str() + .trim() + .parse() + .map(Literal::U32) + .map_err(|e| { + CompileError::Internal( + "Called incorrect internal parser on literal type.", + int_inner.into_span(), + ) + }), + Rule::u64_integer => int_inner + .as_str() + .trim() + .parse() + .map(Literal::U64) + .map_err(|e| { + CompileError::Internal( + "Called incorrect internal parser on literal type.", + int_inner.into_span(), + ) + }), + Rule::u128_integer => int_inner + .as_str() + .trim() + .parse() + .map(Literal::U128) + .map_err(|e| { + CompileError::Internal( + "Called incorrect internal parser on literal type.", + int_inner.into_span(), + ) + }), + _ => unreachable!(), } - Rule::u64_integer => { - Literal::U64(int_inner.as_str().trim().parse().map_err(|e| { - ParseError::Internal( - "Called incorrect internal parser on literal type.", - int_inner.into_span(), - ) - })?) - } - Rule::u128_integer => { - Literal::U128(int_inner.as_str().trim().parse().map_err(|e| { - ParseError::Internal( - "Called incorrect internal parser on literal type.", - int_inner.into_span(), - ) - })?) + } + Rule::string => { + // remove opening and closing quotes + let lit_str = lit_inner.as_str(); + Ok(Literal::String(&lit_str[1..lit_str.len() - 1])) + } + Rule::byte => { + let inner_byte = lit_inner.into_inner().next().unwrap(); + match inner_byte.as_rule() { + Rule::binary_byte => parse_binary_from_pair(inner_byte), + Rule::hex_byte => parse_hex_from_pair(inner_byte), + _ => unreachable!(), } - _ => unreachable!(), } - } - Rule::string => { - // remove opening and closing quotes - let lit_str = lit_inner.as_str(); - Literal::String(&lit_str[1..lit_str.len() - 1]) - } - Rule::byte => { - let inner_byte = lit_inner.into_inner().next().unwrap(); - match inner_byte.as_rule() { - Rule::binary_byte => parse_binary_from_pair(inner_byte)?, - Rule::hex_byte => parse_hex_from_pair(inner_byte)?, + Rule::boolean => Ok(match lit_inner.as_str() { + "true" => Literal::Boolean(true), + "false" => Literal::Boolean(false), _ => unreachable!(), + }), + a => { + eprintln!( + "not yet able to parse literal rule {:?} ({:?})", + a, + lit_inner.as_str() + ); + Err(CompileError::UnimplementedRule(a, lit_inner.as_span())) } - } - Rule::boolean => match lit_inner.as_str() { - "true" => Literal::Boolean(true), - "false" => Literal::Boolean(false), - _ => unreachable!(), - }, - a => { - eprintln!( - "not yet able to parse literal rule {:?} ({:?})", - a, - lit_inner.as_str() - ); - return Err(ParseError::Unimplemented(a, lit_inner.as_span())); - } - }; + }; - Ok(parsed) + match parsed { + Ok(lit) => ok(lit, Vec::new(), Vec::new()), + Err(compile_err) => err(Vec::new(), vec![compile_err]), + } } } -fn parse_hex_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, ParseError<'sc>> { +fn parse_hex_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, CompileError<'sc>> { let hex = &pair.as_str()[2..]; Ok(match hex.len() { 2 => Literal::Byte(u8::from_str_radix(hex, 16).map_err(|e| { - ParseError::Internal( + CompileError::Internal( "Attempted to parse hex string from invalid hex", pair.as_span(), ) @@ -116,11 +136,11 @@ fn parse_hex_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, Parse .chars() .collect::>() .chunks(2) - .map(|two_hex_digits| -> Result { + .map(|two_hex_digits| -> Result { let mut str_buf = String::new(); two_hex_digits.iter().for_each(|x| str_buf.push(*x)); Ok(u8::from_str_radix(&str_buf, 16).map_err(|_| { - ParseError::Internal( + CompileError::Internal( "Attempted to parse individual byte from invalid hex string.", pair.as_span(), ) @@ -128,7 +148,7 @@ fn parse_hex_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, Parse }) .collect::, _>>()?; let arr: [u8; 32] = vec_nums.as_slice().try_into().map_err(|e| { - ParseError::Internal( + CompileError::Internal( "Attempted to parse bytes32 from hex literal of incorrect length. ", pair.as_span(), ) @@ -136,7 +156,7 @@ fn parse_hex_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, Parse Literal::Byte32(arr) } a => { - return Err(ParseError::InvalidByteLiteralLength { + return Err(CompileError::InvalidByteLiteralLength { span: pair.as_span(), byte_length: a, }) @@ -144,12 +164,12 @@ fn parse_hex_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, Parse }) } -fn parse_binary_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, ParseError<'sc>> { +fn parse_binary_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, CompileError<'sc>> { let bin = &pair.as_str()[2..]; Ok(match bin.len() { 8 => Literal::Byte(u8::from_str_radix(bin, 2).map_err(|e| { - ParseError::Internal( + CompileError::Internal( "Attempted to parse bin string from invalid bin string.", pair.as_span(), ) @@ -159,11 +179,11 @@ fn parse_binary_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, Pa .chars() .collect::>() .chunks(8) - .map(|eight_bin_digits| -> Result { + .map(|eight_bin_digits| -> Result { let mut str_buf = String::new(); eight_bin_digits.iter().for_each(|x| str_buf.push(*x)); Ok(u8::from_str_radix(&str_buf, 2).map_err(|_| { - ParseError::Internal( + CompileError::Internal( "Attempted to parse individual byte from invalid bin.", pair.as_span(), ) @@ -171,7 +191,7 @@ fn parse_binary_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, Pa }) .collect::, _>>()?; let arr: [u8; 32] = vec_nums.as_slice().try_into().map_err(|e| { - ParseError::Internal( + CompileError::Internal( "Attempted to parse bytes32 from bin literal of incorrect length. ", pair.as_span(), ) @@ -179,7 +199,7 @@ fn parse_binary_from_pair<'sc>(pair: Pair<'sc, Rule>) -> Result, Pa Literal::Byte32(arr) } a => { - return Err(ParseError::InvalidByteLiteralLength { + return Err(CompileError::InvalidByteLiteralLength { span: pair.as_span(), byte_length: a, }) diff --git a/parser/src/parse_tree/use_statement.rs b/parser/src/parse_tree/use_statement.rs index b70ff9f139e..703e84659e2 100644 --- a/parser/src/parse_tree/use_statement.rs +++ b/parser/src/parse_tree/use_statement.rs @@ -1,4 +1,5 @@ -use crate::error::ParseError; +use crate::error::CompileError; +use crate::error::*; use crate::Rule; use pest::iterators::Pair; @@ -9,7 +10,7 @@ pub(crate) struct UseStatement<'sc> { } impl<'sc> UseStatement<'sc> { - pub(crate) fn parse_from_pair(pair: Pair<'sc, Rule>) -> Result> { + pub(crate) fn parse_from_pair(pair: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let mut stmt = pair.into_inner(); let _use_keyword = stmt.next(); let import_path = stmt.next().unwrap(); @@ -19,6 +20,6 @@ impl<'sc> UseStatement<'sc> { .map(|x| x.as_str()); let root = path_iter.next().unwrap(); let path = path_iter.collect(); - Ok(UseStatement { root, path }) + ok(UseStatement { root, path }, Vec::new(), Vec::new()) } } diff --git a/parser/src/semantics/error.rs b/parser/src/semantics/error.rs deleted file mode 100644 index ca69f7065c6..00000000000 --- a/parser/src/semantics/error.rs +++ /dev/null @@ -1,86 +0,0 @@ -use crate::error::ParseError; -use pest::Span; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum CompileError<'sc> { - #[error("Variable \"{var_name}\" does not exist in this scope.")] - UnknownVariable { var_name: &'sc str, span: Span<'sc> }, - #[error("Function \"{name}\" does not exist in this scope.")] - UnknownFunction { name: &'sc str, span: Span<'sc> }, - #[error("Identifier \"{name}\" was used as a variable, but it is actually a {what_it_is}.")] - NotAVariable { - name: &'sc str, - span: Span<'sc>, - what_it_is: &'static str, - }, - #[error("Identifier \"{name}\" was called as if it was a function, but it is actually a {what_it_is}.")] - NotAFunction { - name: &'sc str, - span: Span<'sc>, - what_it_is: &'static str, - }, - #[error("Unimplemented feature: {0}")] - Unimplemented(&'static str, Span<'sc>), - #[error("Internal compiler error: {0}\nPlease file an issue on the repository and include the code that triggered this error.")] - Internal(&'static str, Span<'sc>), - #[error("{0}")] - TypeError(TypeError<'sc>), - #[error("Parse error: {0}")] - ParseError(ParseError<'sc>), -} - -impl<'sc> std::convert::From> for CompileError<'sc> { - fn from(other: ParseError<'sc>) -> CompileError<'sc> { - CompileError::ParseError(other) - } -} -impl<'sc> std::convert::From> for CompileError<'sc> { - fn from(other: TypeError<'sc>) -> CompileError<'sc> { - CompileError::TypeError(other) - } -} - -#[derive(Error, Debug)] -pub enum TypeError<'sc> { - #[error("Mismatched types: Expected type {expected} but found type {received}. Type {received} is not castable to type {expected}.\n help: {help_text}")] - MismatchedType { - expected: String, - received: String, - help_text: String, - span: Span<'sc>, - }, -} - -impl<'sc> TypeError<'sc> { - pub(crate) fn span(&self) -> (usize, usize) { - use TypeError::*; - match self { - MismatchedType { span, .. } => (span.start(), span.end()), - } - } -} - -impl<'sc> CompileError<'sc> { - pub fn to_friendly_error_string(&self) -> String { - use CompileError::*; - match self { - ParseError(err) => err.to_friendly_error_string(), - a => format!("{}", a), - } - } - - pub fn span(&self) -> (usize, usize) { - use CompileError::*; - match self { - ParseError(err) => err.span(), - UnknownVariable { span, .. } => (span.start(), span.end()), - UnknownFunction { span, .. } => (span.start(), span.end()), - NotAVariable { span, .. } => (span.start(), span.end()), - NotAFunction { span, .. } => (span.start(), span.end()), - Internal(_, span) => (span.start(), span.end()), - Unimplemented(_, span) => (span.start(), span.end()), - TypeError(err) => err.span(), - } - } -} diff --git a/parser/src/semantics/mod.rs b/parser/src/semantics/mod.rs index ed20e590745..18955a29b67 100644 --- a/parser/src/semantics/mod.rs +++ b/parser/src/semantics/mod.rs @@ -1,12 +1,10 @@ -use crate::error::CompileWarning; +use crate::error::*; use crate::parse_tree::*; use crate::types::{IntegerBits, TypeInfo}; use crate::{AstNode, AstNodeContent, CodeBlock, ParseTree, ReturnStatement, TraitFn}; use either::Either; -use std::collections::HashMap; -pub(crate) mod error; -use error::CompileError; use pest::Span; +use std::collections::HashMap; const ERROR_RECOVERY_EXPR: TypedExpression = TypedExpression { expression: TypedExpressionVariant::Unit, @@ -184,7 +182,7 @@ impl<'sc> TypedExpression<'sc> { namespace: HashMap, TypedDeclaration<'sc>>, type_annotation: Option>, help_text: impl Into + Clone, - ) -> Result<(Self, Vec>), Vec>> { + ) -> CompileResult<'sc, Self> { let mut warnings = Vec::new(); let mut errors = Vec::new(); let expr_span = other.span(); @@ -249,30 +247,34 @@ impl<'sc> TypedExpression<'sc> { // declaration. Use parameter type annotations as annotations for the // arguments // - let typed_call_arguments_res = arguments - .into_iter() - .zip(parameters.iter()) - .map(|(arg, param)| { - TypedExpression::type_check( - arg, - namespace.clone(), - Some(param.r#type.clone()), - "The argument that has been provided to this function's type does not match the declared type of the parameter in the function declaration." - ) - }) - .collect::>>(); let mut typed_call_arguments = Vec::new(); - for arg in typed_call_arguments_res { - typed_call_arguments.push(match arg { - Ok((o, mut l_warn)) => { - warnings.append(&mut l_warn); - o + for (arg, param) in arguments.into_iter().zip(parameters.iter()) { + let res = TypedExpression::type_check( + arg, + namespace.clone(), + Some(param.r#type.clone()), + "The argument that has been provided to this function's type does not match the declared type of the parameter in the function declaration." + ); + let arg = match res { + CompileResult::Ok { + value, + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); + value } - Err(mut errs) => { - errors.append(&mut errs); + CompileResult::Err { + warnings: mut l_w, + errors: mut l_e, + } => { + warnings.append(&mut l_w); + errors.append(&mut l_e); ERROR_RECOVERY_EXPR.clone() } - }) + }; + typed_call_arguments.push(arg); } TypedExpression { @@ -311,69 +313,53 @@ impl<'sc> TypedExpression<'sc> { span, .. } => { - let (typed_primary_expression, mut l_warnings) = match TypedExpression::type_check( + let typed_primary_expression = type_check!( + TypedExpression, *primary_expression, namespace.clone(), None, "", - ) { - Ok(tup) => tup, - Err(mut errs) => { - errors.append(&mut errs); - (ERROR_RECOVERY_EXPR.clone(), Vec::new()) - } - }; - warnings.append(&mut l_warnings); - - // TODO handle pattern matching on LHS - let (first_branch_result, mut l_warnings) = match TypedExpression::type_check( + ERROR_RECOVERY_EXPR.clone(), + warnings, + errors + ); + let first_branch_result = type_check!( + TypedExpression, branches[0].result.clone(), namespace.clone(), type_annotation.clone(), help_text.clone(), - ) { - Ok(tup) => tup, - Err(mut errs) => { - errors.append(&mut errs); - (ERROR_RECOVERY_EXPR.clone(), Vec::new()) - } - }; - warnings.append(&mut l_warnings); + ERROR_RECOVERY_EXPR.clone(), + warnings, + errors + ); + let first_branch_result = vec![first_branch_result]; // use type of first branch for annotation on the rest of the branches - let rest_of_branches = branches + // we checked the first branch separately just to get its return type for inferencing the rest + let mut rest_of_branches = branches .into_iter() .skip(1) .map( |MatchBranch { condition, result, .. }| { - TypedExpression::type_check( + type_check!( + TypedExpression, result, namespace.clone(), Some(first_branch_result[0].return_type.clone()), "All branches of a match expression must be of the same type.", + ERROR_RECOVERY_EXPR.clone(), + warnings, + errors ) }, ) - .collect::>>(); - - let mut branches_buf = Vec::new(); - for branch in rest_of_branches { - match branch { - Ok((br, mut l_warnings)) => { - warnings.append(&mut l_warnings); - branches_buf.push(br); - } - Err(mut e) => { - errors.append(&mut e); - branches_buf.push(ERROR_RECOVERY_EXPR.clone()); - } - } - } + .collect::>(); let mut all_branches = first_branch_result; - all_branches.append(&mut branches_buf); + all_branches.append(&mut rest_of_branches); errors.push(CompileError::Unimplemented( "Match expressions and pattern matching", @@ -413,54 +399,39 @@ impl<'sc> TypedExpression<'sc> { r#else, span, } => { - let condition = Box::new( - match TypedExpression::type_check( - *condition, - namespace.clone(), - Some(TypeInfo::Boolean), - "The condition of an if expression must be a boolean expression.", - ) { - Ok((condition, mut l_warnings)) => { - warnings.append(&mut l_warnings); - condition - } - Err(mut errs) => { - errors.append(&mut errs); - ERROR_RECOVERY_EXPR.clone() - } - }, - ); - let then = Box::new( - match TypedExpression::type_check(*then, namespace.clone(), None, "") { - Ok((then, mut l_warnings)) => { - warnings.append(&mut l_warnings); - then - } - Err(mut errs) => { - errors.append(&mut errs); - ERROR_RECOVERY_EXPR.clone() - } - }, - ); - let r#else = match r#else { - Some(expr) => Some(Box::new( - match TypedExpression::type_check( - *expr, - namespace, - Some(then.return_type.clone()), - "If expression branches must return the same type.", - ) { - Ok((r#else, mut l_warnings)) => { - warnings.append(&mut l_warnings); - r#else - } - Err(mut errs) => { - errors.append(&mut errs); - ERROR_RECOVERY_EXPR.clone() - } - }, - )), - None => None, + let condition = Box::new(type_check!( + TypedExpression, + *condition, + namespace.clone(), + Some(TypeInfo::Boolean), + "The condition of an if expression must be a boolean expression.", + ERROR_RECOVERY_EXPR.clone(), + warnings, + errors + )); + let then = Box::new(type_check!( + TypedExpression, + *then, + namespace.clone(), + None, + "", + ERROR_RECOVERY_EXPR.clone(), + warnings, + errors + )); + let r#else = if let Some(expr) = r#else { + Some(Box::new(type_check!( + TypedExpression, + *expr, + namespace, + Some(then.return_type.clone()), + "", + ERROR_RECOVERY_EXPR.clone(), + warnings, + errors + ))) + } else { + None }; TypedExpression { @@ -504,11 +475,7 @@ impl<'sc> TypedExpression<'sc> { } } } - if errors.is_empty() { - Ok((typed_expression, warnings)) - } else { - Err(errors) - } + ok(typed_expression, warnings, errors) } } @@ -670,24 +637,15 @@ fn type_check_node<'sc>( body, is_mutable, }) => { - let res = TypedExpression::type_check(body, namespace.clone(), type_ascription.clone(), format!("Variable declaration's type annotation (type {}) does not match up with the assigned expression's type.", type_ascription.map(|x| x.friendly_type_str()).unwrap_or("none".into()))); - match res { - Ok((body, mut l_warnings)) => { - warnings.append(&mut l_warnings); - let body = - TypedDeclaration::VariableDeclaration(TypedVariableDeclaration { - name: name.clone(), - body, - is_mutable, - }); - namespace.insert(name, body.clone()); - body - } - Err(mut errs) => { - errors.append(&mut errs); - ERROR_RECOVERY_DECLARATION.clone() - } - } + let body = type_check!(TypedExpression, body, namespace.clone(), type_ascription.clone(), + format!("Variable declaration's type annotation (type {}) does not match up with the assigned expression's type.", type_ascription.map(|x| x.friendly_type_str()).unwrap_or("none".into())), ERROR_RECOVERY_EXPR.clone(), warnings, errors); + let body = TypedDeclaration::VariableDeclaration(TypedVariableDeclaration { + name: name.clone(), + body, + is_mutable, + }); + namespace.insert(name, body.clone()); + body } Declaration::EnumDeclaration(e) => { let span = e.span.clone(); @@ -710,6 +668,7 @@ fn type_check_node<'sc>( span, return_type, type_parameters, + .. }) => { // insert parameters into namespace let mut namespace = namespace.clone(); @@ -818,15 +777,16 @@ fn type_check_node<'sc>( }), AstNodeContent::TraitDeclaration(a) => TypedAstNodeContent::TraitDeclaration(a), AstNodeContent::Expression(a) => { - let (inner, mut l_warnings) = - match TypedExpression::type_check(a, namespace.clone(), None, "") { - Ok(tup) => tup, - Err(mut errs) => { - errors.append(&mut errs); - (ERROR_RECOVERY_EXPR.clone(), Vec::new()) - } - }; - warnings.append(&mut l_warnings); + let inner = type_check!( + TypedExpression, + a, + namespace.clone(), + None, + "", + ERROR_RECOVERY_EXPR.clone(), + warnings, + errors + ); TypedAstNodeContent::Expression(inner) } AstNodeContent::ReturnStatement(ReturnStatement { expr }) => { @@ -837,26 +797,16 @@ fn type_check_node<'sc>( )); ERROR_RECOVERY_NODE_CONTENT.clone() } else { - match TypedExpression::type_check( - expr, - namespace.clone(), - return_type_annotation, + TypedAstNodeContent::ReturnStatement (TypedReturnStatement { + expr: type_check!(TypedExpression, expr, namespace.clone(), return_type_annotation, "Returned value must match up with the function return type annotation.", - ) { - Ok((res, mut l_warnings)) => { - warnings.append(&mut l_warnings); - - TypedAstNodeContent::ReturnStatement(TypedReturnStatement { expr: res }) - } - Err(mut errs) => { - errors.append(&mut errs); - ERROR_RECOVERY_NODE_CONTENT.clone() - } - } + ERROR_RECOVERY_EXPR.clone(), warnings, errors) + }) } } AstNodeContent::ImplicitReturnExpression(expr) => { - let (typed_expr, mut l_warnings) = match TypedExpression::type_check( + let typed_expr = type_check!( + TypedExpression, expr, namespace.clone(), return_type_annotation, @@ -864,14 +814,10 @@ fn type_check_node<'sc>( "Implicit return must match up with block's type. {}", help_text.into() ), - ) { - Ok(tup) => tup, - Err(mut errs) => { - errors.append(&mut errs); - (ERROR_RECOVERY_EXPR.clone(), Vec::new()) - } - }; - warnings.append(&mut l_warnings); + ERROR_RECOVERY_EXPR.clone(), + warnings, + errors + ); TypedAstNodeContent::ImplicitReturnExpression(typed_expr) } a => { diff --git a/parser/src/types.rs b/parser/src/types.rs index bc02d0c71e6..b89526b9274 100644 --- a/parser/src/types.rs +++ b/parser/src/types.rs @@ -1,9 +1,10 @@ -use crate::error::{ParseResult, Warning}; -use crate::{CodeBlock, ParseError, Rule}; +use crate::error::*; +use crate::{CodeBlock, CompileError, Rule}; use either::Either; use inflector::cases::snakecase::is_snake_case; use pest::iterators::Pair; use pest::Span; + /// Type information without an associated value, used for type inferencing and definition. #[derive(Debug, Clone, PartialEq)] pub enum TypeInfo<'sc> { @@ -28,23 +29,27 @@ pub enum IntegerBits { } impl<'sc> TypeInfo<'sc> { - pub(crate) fn parse_from_pair(input: Pair<'sc, Rule>) -> Result> { + pub(crate) fn parse_from_pair(input: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { let mut r#type = input.into_inner(); Self::parse_from_pair_inner(r#type.next().unwrap()) } - pub(crate) fn parse_from_pair_inner(input: Pair<'sc, Rule>) -> Result> { - Ok(match input.as_str() { - "u8" => TypeInfo::UnsignedInteger(IntegerBits::Eight), - "u16" => TypeInfo::UnsignedInteger(IntegerBits::Sixteen), - "u32" => TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo), - "u64" => TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), - "u128" => TypeInfo::UnsignedInteger(IntegerBits::OneTwentyEight), - "bool" => TypeInfo::Boolean, - "string" => TypeInfo::String, - "unit" => TypeInfo::Unit, - "byte" => TypeInfo::Byte, - other => TypeInfo::Generic { name: other }, - }) + pub(crate) fn parse_from_pair_inner(input: Pair<'sc, Rule>) -> CompileResult<'sc, Self> { + ok( + match input.as_str() { + "u8" => TypeInfo::UnsignedInteger(IntegerBits::Eight), + "u16" => TypeInfo::UnsignedInteger(IntegerBits::Sixteen), + "u32" => TypeInfo::UnsignedInteger(IntegerBits::ThirtyTwo), + "u64" => TypeInfo::UnsignedInteger(IntegerBits::SixtyFour), + "u128" => TypeInfo::UnsignedInteger(IntegerBits::OneTwentyEight), + "bool" => TypeInfo::Boolean, + "string" => TypeInfo::String, + "unit" => TypeInfo::Unit, + "byte" => TypeInfo::Byte, + other => TypeInfo::Generic { name: other }, + }, + Vec::new(), + Vec::new(), + ) } pub(crate) fn is_convertable( @@ -52,12 +57,11 @@ impl<'sc> TypeInfo<'sc> { other: TypeInfo<'sc>, debug_span: Span<'sc>, help_text: impl Into, - ) -> Result>, crate::semantics::error::TypeError<'sc>> { + ) -> Result>, TypeError<'sc>> { let help_text = help_text.into(); if self == TypeInfo::ErrorRecovery || other == TypeInfo::ErrorRecovery { return Ok(None); } - use crate::semantics::error::TypeError; // TODO actually check more advanced conversion rules like upcasting vs downcasting // numbers, emit warnings for loss of precision if self == other {