Error Message Include File Name (#70) and Minor Fix #154
|
@ -97,10 +97,10 @@ impl Nac3 {
|
||||||
))
|
))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let source = fs::read_to_string(source_file).map_err(|e| {
|
let source = fs::read_to_string(&source_file).map_err(|e| {
|
||||||
exceptions::PyIOError::new_err(format!("failed to read input file: {}", e))
|
exceptions::PyIOError::new_err(format!("failed to read input file: {}", e))
|
||||||
})?;
|
})?;
|
||||||
let parser_result = parser::parse_program(&source)
|
let parser_result = parser::parse_program(&source, source_file.into())
|
||||||
.map_err(|e| exceptions::PySyntaxError::new_err(format!("parse error: {}", e)))?;
|
.map_err(|e| exceptions::PySyntaxError::new_err(format!("parse error: {}", e)))?;
|
||||||
|
|
||||||
for mut stmt in parser_result.into_iter() {
|
for mut stmt in parser_result.into_iter() {
|
||||||
|
@ -476,7 +476,7 @@ impl Nac3 {
|
||||||
arg_names.join(", ")
|
arg_names.join(", ")
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
let mut synthesized = parse_program(&synthesized).unwrap();
|
let mut synthesized = parse_program(&synthesized, Default::default()).unwrap();
|
||||||
let resolver = Arc::new(Resolver(Arc::new(InnerResolver {
|
let resolver = Arc::new(Resolver(Arc::new(InnerResolver {
|
||||||
id_to_type: self.builtins_ty.clone().into(),
|
id_to_type: self.builtins_ty.clone().into(),
|
||||||
id_to_def: self.builtins_def.clone().into(),
|
id_to_def: self.builtins_def.clone().into(),
|
||||||
|
|
|
@ -9,6 +9,6 @@ mod impls;
|
||||||
mod location;
|
mod location;
|
||||||
|
|
||||||
pub use ast_gen::*;
|
pub use ast_gen::*;
|
||||||
pub use location::Location;
|
pub use location::{Location, FileName};
|
||||||
|
|
||||||
pub type Suite<U = ()> = Vec<Stmt<U>>;
|
pub type Suite<U = ()> = Vec<Stmt<U>>;
|
||||||
|
|
|
@ -1,17 +1,32 @@
|
||||||
//! Datatypes to support source location information.
|
//! Datatypes to support source location information.
|
||||||
|
use crate::ast_gen::StrRef;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
pub struct FileName(StrRef);
|
||||||
|
impl Default for FileName {
|
||||||
|
fn default() -> Self {
|
||||||
|
FileName("unknown file".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for FileName {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
FileName(s.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A location somewhere in the sourcecode.
|
/// A location somewhere in the sourcecode.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq)]
|
||||||
pub struct Location {
|
pub struct Location {
|
||||||
row: usize,
|
row: usize,
|
||||||
column: usize,
|
column: usize,
|
||||||
|
file: FileName
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Location {
|
impl fmt::Display for Location {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "line {} column {}", self.row, self.column)
|
write!(f, "{}:{}:{}", self.file.0, self.row, self.column)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,8 +62,8 @@ impl Location {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Location {
|
impl Location {
|
||||||
pub fn new(row: usize, column: usize) -> Self {
|
pub fn new(row: usize, column: usize, file: FileName) -> Self {
|
||||||
Location { row, column }
|
Location { row, column, file }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn row(&self) -> usize {
|
pub fn row(&self) -> usize {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
//! This means source code is translated into separate tokens.
|
//! This means source code is translated into separate tokens.
|
||||||
|
|
||||||
pub use super::token::Tok;
|
pub use super::token::Tok;
|
||||||
use crate::ast::Location;
|
use crate::ast::{Location, FileName};
|
||||||
use crate::error::{LexicalError, LexicalErrorType};
|
use crate::error::{LexicalError, LexicalErrorType};
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use num_traits::identities::Zero;
|
use num_traits::identities::Zero;
|
||||||
|
@ -113,8 +113,8 @@ pub type Spanned = (Location, Tok, Location);
|
||||||
pub type LexResult = Result<Spanned, LexicalError>;
|
pub type LexResult = Result<Spanned, LexicalError>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn make_tokenizer(source: &str) -> impl Iterator<Item = LexResult> + '_ {
|
pub fn make_tokenizer(source: &str, file: FileName) -> impl Iterator<Item = LexResult> + '_ {
|
||||||
make_tokenizer_located(source, Location::new(0, 0))
|
make_tokenizer_located(source, Location::new(0, 0, file))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn make_tokenizer_located(
|
pub fn make_tokenizer_located(
|
||||||
|
@ -1320,6 +1320,8 @@ where
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::default;
|
||||||
|
|
||||||
use super::{make_tokenizer, NewlineHandler, Tok};
|
use super::{make_tokenizer, NewlineHandler, Tok};
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
|
|
||||||
|
@ -1328,7 +1330,7 @@ mod tests {
|
||||||
const UNIX_EOL: &str = "\n";
|
const UNIX_EOL: &str = "\n";
|
||||||
|
|
||||||
pub fn lex_source(source: &str) -> Vec<Tok> {
|
pub fn lex_source(source: &str) -> Vec<Tok> {
|
||||||
let lexer = make_tokenizer(source);
|
let lexer = make_tokenizer(source, Default::default());
|
||||||
lexer.map(|x| x.unwrap().1).collect()
|
lexer.map(|x| x.unwrap().1).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
use std::iter;
|
use std::iter;
|
||||||
|
|
||||||
use crate::ast;
|
use crate::ast::{self, FileName};
|
||||||
use crate::error::ParseError;
|
use crate::error::ParseError;
|
||||||
use crate::lexer;
|
use crate::lexer;
|
||||||
pub use crate::mode::Mode;
|
pub use crate::mode::Mode;
|
||||||
|
@ -20,8 +20,8 @@ use crate::python;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// Parse a full python program, containing usually multiple lines.
|
/// Parse a full python program, containing usually multiple lines.
|
||||||
pub fn parse_program(source: &str) -> Result<ast::Suite, ParseError> {
|
pub fn parse_program(source: &str, file: FileName) -> Result<ast::Suite, ParseError> {
|
||||||
parse(source, Mode::Module).map(|top| match top {
|
parse(source, Mode::Module, file).map(|top| match top {
|
||||||
ast::Mod::Module { body, .. } => body,
|
ast::Mod::Module { body, .. } => body,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
|
@ -64,15 +64,15 @@ pub fn parse_program(source: &str) -> Result<ast::Suite, ParseError> {
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
pub fn parse_expression(source: &str) -> Result<ast::Expr, ParseError> {
|
pub fn parse_expression(source: &str) -> Result<ast::Expr, ParseError> {
|
||||||
parse(source, Mode::Expression).map(|top| match top {
|
parse(source, Mode::Expression, Default::default()).map(|top| match top {
|
||||||
ast::Mod::Expression { body } => *body,
|
ast::Mod::Expression { body } => *body,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse a given source code
|
// Parse a given source code
|
||||||
pub fn parse(source: &str, mode: Mode) -> Result<ast::Mod, ParseError> {
|
pub fn parse(source: &str, mode: Mode, file: FileName) -> Result<ast::Mod, ParseError> {
|
||||||
let lxr = lexer::make_tokenizer(source);
|
let lxr = lexer::make_tokenizer(source, file);
|
||||||
let marker_token = (Default::default(), mode.to_marker(), Default::default());
|
let marker_token = (Default::default(), mode.to_marker(), Default::default());
|
||||||
let tokenizer = iter::once(Ok(marker_token)).chain(lxr);
|
let tokenizer = iter::once(Ok(marker_token)).chain(lxr);
|
||||||
|
|
||||||
|
@ -87,42 +87,42 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_empty() {
|
fn test_parse_empty() {
|
||||||
let parse_ast = parse_program("").unwrap();
|
let parse_ast = parse_program("", Default::default()).unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_print_hello() {
|
fn test_parse_print_hello() {
|
||||||
let source = String::from("print('Hello world')");
|
let source = String::from("print('Hello world')");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, Default::default()).unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_print_2() {
|
fn test_parse_print_2() {
|
||||||
let source = String::from("print('Hello world', 2)");
|
let source = String::from("print('Hello world', 2)");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, Default::default()).unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_kwargs() {
|
fn test_parse_kwargs() {
|
||||||
let source = String::from("my_func('positional', keyword=2)");
|
let source = String::from("my_func('positional', keyword=2)");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, Default::default()).unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_if_elif_else() {
|
fn test_parse_if_elif_else() {
|
||||||
let source = String::from("if 1: 10\nelif 2: 20\nelse: 30");
|
let source = String::from("if 1: 10\nelif 2: 20\nelse: 30");
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, Default::default()).unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_parse_lambda() {
|
fn test_parse_lambda() {
|
||||||
let source = "lambda x, y: x * y"; // lambda(x, y): x * y";
|
let source = "lambda x, y: x * y"; // lambda(x, y): x * y";
|
||||||
let parse_ast = parse_program(&source).unwrap();
|
let parse_ast = parse_program(&source, Default::default()).unwrap();
|
||||||
insta::assert_debug_snapshot!(parse_ast);
|
insta::assert_debug_snapshot!(parse_ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ mod tests {
|
||||||
fn test_parse_tuples() {
|
fn test_parse_tuples() {
|
||||||
let source = "a, b = 4, 5";
|
let source = "a, b = 4, 5";
|
||||||
|
|
||||||
insta::assert_debug_snapshot!(parse_program(&source).unwrap());
|
insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -141,7 +141,7 @@ class Foo(A, B):
|
||||||
pass
|
pass
|
||||||
def method_with_default(self, arg='default'):
|
def method_with_default(self, arg='default'):
|
||||||
pass";
|
pass";
|
||||||
insta::assert_debug_snapshot!(parse_program(&source).unwrap());
|
insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -184,7 +184,7 @@ while i < 2: # nac3: 4
|
||||||
# nac3: if1
|
# nac3: if1
|
||||||
if 1: # nac3: if2
|
if 1: # nac3: if2
|
||||||
3";
|
3";
|
||||||
insta::assert_debug_snapshot!(parse_program(&source).unwrap());
|
insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -197,7 +197,7 @@ while test: # nac3: while3
|
||||||
# nac3: simple assign0
|
# nac3: simple assign0
|
||||||
a = 3 # nac3: simple assign1
|
a = 3 # nac3: simple assign1
|
||||||
";
|
";
|
||||||
insta::assert_debug_snapshot!(parse_program(&source).unwrap());
|
insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -216,7 +216,7 @@ if a: # nac3: small2
|
||||||
for i in a: # nac3: for1
|
for i in a: # nac3: for1
|
||||||
pass
|
pass
|
||||||
";
|
";
|
||||||
insta::assert_debug_snapshot!(parse_program(&source).unwrap());
|
insta::assert_debug_snapshot!(parse_program(&source, Default::default()).unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -225,6 +225,6 @@ for i in a: # nac3: for1
|
||||||
if a: # nac3: something
|
if a: # nac3: something
|
||||||
a = 3
|
a = 3
|
||||||
";
|
";
|
||||||
assert!(parse_program(&source).is_err());
|
assert!(parse_program(&source, Default::default()).is_err());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ fn main() {
|
||||||
|
|
||||||
Target::initialize_all(&InitializationConfig::default());
|
Target::initialize_all(&InitializationConfig::default());
|
||||||
|
|
||||||
let program = match fs::read_to_string(demo_name + ".py") {
|
let program = match fs::read_to_string(demo_name.clone() + ".py") {
|
||||||
Ok(program) => program,
|
Ok(program) => program,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("Cannot open input file: {}", err);
|
println!("Cannot open input file: {}", err);
|
||||||
|
@ -64,7 +64,7 @@ fn main() {
|
||||||
setup_time.duration_since(start).unwrap().as_millis()
|
setup_time.duration_since(start).unwrap().as_millis()
|
||||||
);
|
);
|
||||||
|
|
||||||
let parser_result = parser::parse_program(&program).unwrap();
|
let parser_result = parser::parse_program(&program, format!("{}.py", demo_name).into()).unwrap();
|
||||||
let parse_time = SystemTime::now();
|
let parse_time = SystemTime::now();
|
||||||
println!(
|
println!(
|
||||||
"parse time: {}ms",
|
"parse time: {}ms",
|
||||||
|
|
Loading…
Reference in New Issue