convert identifer to span with error

This commit is contained in:
collin 2020-06-19 17:28:50 -07:00
parent c54f1817ce
commit 6922d5dd73
6 changed files with 93 additions and 39 deletions

View File

@ -47,7 +47,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
// Check global scope (function and circuit names)
value.clone()
} else {
return Err(ExpressionError::UndefinedIdentifier(unresolved_identifier.to_string()));
return Err(ExpressionError::undefined_identifier(unresolved_identifier));
};
result_value.resolve_type(expected_types)?;

View File

@ -1,14 +1,13 @@
use crate::errors::{BooleanError, FieldError, FunctionError, GroupError, ValueError};
use leo_types::IntegerError;
use crate::errors::{BooleanError, Error, FieldError, FunctionError, GroupError, ValueError};
use leo_types::{Identifier, IntegerError, Span};
use snarkos_errors::gadgets::SynthesisError;
use std::num::ParseIntError;
#[derive(Debug, Error)]
pub enum ExpressionError {
// Identifiers
#[error("Identifier \"{}\" not found", _0)]
UndefinedIdentifier(String),
#[error("{}", _0)]
Error(#[from] Error),
// Types
#[error("{}", _0)]
@ -87,3 +86,15 @@ pub enum ExpressionError {
#[error("{}", _0)]
SynthesisError(#[from] SynthesisError),
}
impl ExpressionError {
fn new_from_span(message: String, span: Span) -> Self {
ExpressionError::Error(Error::new_from_span(message, span))
}
pub fn undefined_identifier(identifier: Identifier) -> Self {
let message = format!("cannot find value `{}` in this scope", identifier.name);
Self::new_from_span(message, identifier.span)
}
}

View File

@ -86,6 +86,12 @@ impl fmt::Display for Error {
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
&self.message
}
}
#[test]
fn test_error() {
let err = Error {
@ -110,26 +116,3 @@ fn test_error() {
.join("\n")
);
}
#[test]
fn test_from_span() {
use pest::Span as AstSpan;
let text = "aaaa";
let ast_span = AstSpan::new(text, 0, text.len()).unwrap();
let span = Span::from(ast_span);
let err = Error::new_from_span("test message".to_string(), span);
assert_eq!(
format!("{}", err),
vec![
" --> 1:0",
" |",
" 1 | aaaa",
" | ^^^^",
" |",
" = test message",
]
.join("\n")
);
}

View File

@ -1,6 +1,6 @@
use crate::{get_error, parse_program};
use leo_ast::ParserError;
use leo_compiler::errors::CompilerError;
use leo_compiler::errors::{CompilerError, ExpressionError, FunctionError, StatementError};
use leo_inputs::InputParserError;
#[test]
@ -21,7 +21,25 @@ fn test_undefined() {
let error = get_error(program);
println!("{}", error);
match error {
CompilerError::FunctionError(FunctionError::StatementError(StatementError::ExpressionError(
ExpressionError::Error(error),
))) => {
assert_eq!(
format!("{}", error),
vec![
" --> 2:10",
" |",
" 2 | return a",
" | ^",
" |",
" = cannot find value `a` in this scope",
]
.join("\n")
);
}
_ => panic!("expected an undefined identifier error"),
}
}
// #[test]

View File

@ -1,3 +1,4 @@
use crate::Span;
use leo_ast::common::Identifier as AstIdentifier;
use std::fmt;
@ -6,6 +7,7 @@ use std::fmt;
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Identifier {
pub name: String,
pub span: Span,
}
impl Identifier {
@ -16,7 +18,10 @@ impl Identifier {
impl<'ast> From<AstIdentifier<'ast>> for Identifier {
fn from(identifier: AstIdentifier<'ast>) -> Self {
Self { name: identifier.value }
Self {
name: identifier.value,
span: Span::from(identifier.span),
}
}
}

View File

@ -1,4 +1,4 @@
use pest::Span as AstSpan;
use pest::{Position, Span as AstSpan};
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct Span {
@ -14,13 +14,50 @@ pub struct Span {
impl<'ast> From<AstSpan<'ast>> for Span {
fn from(span: AstSpan<'ast>) -> Self {
let line_col = span.start_pos().line_col();
let mut text = " ".to_string();
text.push_str(span.start_pos().line_of().trim_end());
Self {
text: span.as_str().to_string(),
line: line_col.0,
start: span.start(),
end: span.end(),
text,
line: span.start_pos().line_col().0,
start: find_line_start(&span.start_pos()),
end: find_line_end(&span.end_pos()),
}
}
}
pub fn find_line_start(pos: &Position) -> usize {
let input = pos.line_of();
if input.is_empty() {
return 0;
};
// Position's pos is always a UTF-8 border.
let start = input
.char_indices()
.rev()
.skip_while(|&(i, _)| i >= pos.pos())
.find(|&(_, c)| c == '\n');
match start {
Some((i, _)) => i,
None => 0,
}
}
pub fn find_line_end(pos: &Position) -> usize {
let input = pos.line_of();
if input.is_empty() {
0
} else if pos.pos() == input.len() - 1 {
input.len()
} else {
// Position's pos is always a UTF-8 border.
let end = input
.char_indices()
.skip_while(|&(i, _)| i < pos.pos())
.find(|&(_, c)| c == '\n');
match end {
Some((i, _)) => i,
None => input.len(),
}
}
}