From 46419956bdd2c72c4bd449f70916d98ab19d457e Mon Sep 17 00:00:00 2001 From: Jeff Date: Sun, 17 Mar 2024 02:51:33 -0400 Subject: [PATCH] Improve positioning --- Cargo.lock | 80 ++++++++++++++++---------------- src/abstract_tree/assignment.rs | 16 +++++-- src/abstract_tree/block.rs | 20 ++++++-- src/abstract_tree/if_else.rs | 31 +++++++------ src/abstract_tree/logic.rs | 42 ++++++++--------- src/abstract_tree/mod.rs | 6 ++- src/abstract_tree/statement.rs | 12 +++-- src/error.rs | 14 ++++-- src/lib.rs | 5 +- src/parser.rs | 82 ++++++++++++++++++++------------- 10 files changed, 180 insertions(+), 128 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe6e8d2..1c03e11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ahash" -version = "0.8.9" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", @@ -96,9 +96,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cc" -version = "1.0.86" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -121,9 +121,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.2" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" +checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813" dependencies = [ "clap_builder", "clap_derive", @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.0" +version = "4.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" +checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f" dependencies = [ "heck", "proc-macro2", @@ -243,15 +243,15 @@ dependencies = [ [[package]] name = "heck" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hermit-abi" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "humantime" @@ -302,9 +302,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "proc-macro2" -version = "1.0.78" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -420,9 +420,9 @@ checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01" [[package]] name = "syn" -version = "2.0.50" +version = "2.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" +checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032" dependencies = [ "proc-macro2", "quote", @@ -499,7 +499,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.4", ] [[package]] @@ -534,17 +534,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", ] [[package]] @@ -561,9 +561,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -579,9 +579,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -597,9 +597,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -615,9 +615,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -633,9 +633,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -651,9 +651,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -669,9 +669,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" [[package]] name = "yansi" diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index 4b1b112..8610b4e 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -126,7 +126,9 @@ mod tests { None, AssignmentOperator::Assign, Positioned { - node: Statement::Expression(Expression::Value(ValueNode::Integer(42))), + node: Statement::Expression( + Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()), + ), position: (0, 0), }, ) @@ -152,7 +154,9 @@ mod tests { None, AssignmentOperator::AddAssign, Positioned { - node: Statement::Expression(Expression::Value(ValueNode::Integer(41))), + node: Statement::Expression( + Expression::Value(ValueNode::Integer(41)).positioned((0..1).into()), + ), position: (0, 0), }, ) @@ -178,7 +182,9 @@ mod tests { None, AssignmentOperator::SubAssign, Positioned { - node: Statement::Expression(Expression::Value(ValueNode::Integer(1))), + node: Statement::Expression( + Expression::Value(ValueNode::Integer(1)).positioned((0..1).into()), + ), position: (0, 0), }, ) @@ -201,7 +207,9 @@ mod tests { }), AssignmentOperator::Assign, Positioned { - node: Statement::Expression(Expression::Value(ValueNode::Integer(42))), + node: Statement::Expression( + Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()), + ), position: (0, 0), }, ) diff --git a/src/abstract_tree/block.rs b/src/abstract_tree/block.rs index 57e62a8..473fff5 100644 --- a/src/abstract_tree/block.rs +++ b/src/abstract_tree/block.rs @@ -61,9 +61,15 @@ mod tests { #[test] fn run_returns_value_of_final_statement() { let block = Block::new(vec![ - Statement::Expression(Expression::Value(ValueNode::Integer(1))), - Statement::Expression(Expression::Value(ValueNode::Integer(2))), - Statement::Expression(Expression::Value(ValueNode::Integer(42))), + Statement::Expression( + Expression::Value(ValueNode::Integer(1)).positioned((0..1).into()), + ), + Statement::Expression( + Expression::Value(ValueNode::Integer(2)).positioned((0..1).into()), + ), + Statement::Expression( + Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()), + ), ]); assert_eq!( @@ -75,8 +81,12 @@ mod tests { #[test] fn expected_type_returns_type_of_final_statement() { let block = Block::new(vec![ - Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))), - Statement::Expression(Expression::Value(ValueNode::Integer(42))), + Statement::Expression( + Expression::Value(ValueNode::String("42".to_string())).positioned((0..0).into()), + ), + Statement::Expression( + Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()), + ), ]); assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer)) diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index bfea19e..5cca1eb 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -83,11 +83,12 @@ mod tests { fn simple_if() { assert_eq!( IfElse::new( - Expression::Value(ValueNode::Boolean(true)).positioned((0, 0)), - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("foo".to_string()) - ),)]) - .positioned((0, 0)), + Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), + Block::new(vec![Statement::Expression( + Expression::Value(ValueNode::String("foo".to_string())) + .positioned((0..0).into()) + )]) + .positioned((0..0).into()), None ) .run(&Context::new()), @@ -99,16 +100,18 @@ mod tests { fn simple_if_else() { assert_eq!( IfElse::new( - Expression::Value(ValueNode::Boolean(false)).positioned((0, 0)), - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("foo".to_string()) - ))]) - .positioned((0, 0)), + Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()), + Block::new(vec![Statement::Expression( + Expression::Value(ValueNode::String("foo".to_string())) + .positioned((0..0).into()) + )]) + .positioned((0..0).into()), Some( - Block::new(vec![Statement::Expression(Expression::Value( - ValueNode::String("bar".to_string()) - ))]) - .positioned((0, 0)) + Block::new(vec![Statement::Expression( + Expression::Value(ValueNode::String("bar".to_string())) + .positioned((0..0).into()) + )]) + .positioned((0..0).into()) ) ) .run(&Context::new()), diff --git a/src/abstract_tree/logic.rs b/src/abstract_tree/logic.rs index f86c598..4e0da20 100644 --- a/src/abstract_tree/logic.rs +++ b/src/abstract_tree/logic.rs @@ -139,8 +139,8 @@ mod tests { #[test] fn equal() { assert!(Logic::Equal( - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -153,8 +153,8 @@ mod tests { #[test] fn not_equal() { assert!(Logic::NotEqual( - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), - Expression::Value(ValueNode::Integer(43)).positioned((0, 0)), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -167,8 +167,8 @@ mod tests { #[test] fn greater() { assert!(Logic::Greater( - Expression::Value(ValueNode::Integer(43)).positioned((0, 0)), - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), + Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -181,8 +181,8 @@ mod tests { #[test] fn less() { assert!(Logic::Less( - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), - Expression::Value(ValueNode::Integer(43)).positioned((0, 0)), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -195,8 +195,8 @@ mod tests { #[test] fn greater_or_equal() { assert!(Logic::GreaterOrEqual( - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), - Expression::Value(ValueNode::Integer(41)).positioned((0, 0)), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(41)).positioned((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -206,8 +206,8 @@ mod tests { .unwrap()); assert!(Logic::GreaterOrEqual( - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -220,8 +220,8 @@ mod tests { #[test] fn less_or_equal() { assert!(Logic::LessOrEqual( - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), - Expression::Value(ValueNode::Integer(43)).positioned((0, 0)), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -231,8 +231,8 @@ mod tests { .unwrap()); assert!(Logic::LessOrEqual( - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), - Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), + Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -245,8 +245,8 @@ mod tests { #[test] fn and() { assert!(Logic::And( - Expression::Value(ValueNode::Boolean(true)).positioned((0, 0)), - Expression::Value(ValueNode::Boolean(true)).positioned((0, 0)), + Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), + Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -259,8 +259,8 @@ mod tests { #[test] fn or() { assert!(Logic::Or( - Expression::Value(ValueNode::Boolean(true)).positioned((0, 0)), - Expression::Value(ValueNode::Boolean(false)).positioned((0, 0)), + Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()), + Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()), ) .run(&Context::new()) .unwrap() @@ -273,7 +273,7 @@ mod tests { #[test] fn not() { assert!( - Logic::Not(Expression::Value(ValueNode::Boolean(false)).positioned((0, 0))) + Logic::Not(Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into())) .run(&Context::new()) .unwrap() .as_return_value() diff --git a/src/abstract_tree/mod.rs b/src/abstract_tree/mod.rs index 695bb13..be2e874 100644 --- a/src/abstract_tree/mod.rs +++ b/src/abstract_tree/mod.rs @@ -13,6 +13,8 @@ pub mod r#type; pub mod value_node; pub mod r#while; +use chumsky::span::{SimpleSpan, Span}; + pub use self::{ assignment::{Assignment, AssignmentOperator}, block::Block, @@ -47,10 +49,10 @@ pub trait AbstractTree: Sized { fn validate(&self, context: &Context) -> Result<(), ValidationError>; fn run(self, context: &Context) -> Result; - fn positioned(self, position: (usize, usize)) -> Positioned { + fn positioned(self, span: SimpleSpan) -> Positioned { Positioned { node: self, - position, + position: (span.start(), span.end()), } } } diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index af8afd6..8a03245 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -3,14 +3,16 @@ use crate::{ error::{RuntimeError, ValidationError}, }; -use super::{AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Type, While}; +use super::{ + AbstractTree, Action, Assignment, Block, Expression, IfElse, Loop, Positioned, Type, While, +}; #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Statement { Assignment(Assignment), Block(Block), Break, - Expression(Expression), + Expression(Positioned), IfElse(IfElse), Loop(Loop), While(While), @@ -22,7 +24,7 @@ impl AbstractTree for Statement { Statement::Assignment(assignment) => assignment.expected_type(_context), Statement::Block(block) => block.expected_type(_context), Statement::Break => Ok(Type::None), - Statement::Expression(expression) => expression.expected_type(_context), + Statement::Expression(expression) => expression.node.expected_type(_context), Statement::IfElse(if_else) => if_else.expected_type(_context), Statement::Loop(r#loop) => r#loop.expected_type(_context), Statement::While(r#while) => r#while.expected_type(_context), @@ -34,7 +36,7 @@ impl AbstractTree for Statement { Statement::Assignment(assignment) => assignment.validate(_context), Statement::Block(block) => block.validate(_context), Statement::Break => Ok(()), - Statement::Expression(expression) => expression.validate(_context), + Statement::Expression(expression) => expression.node.validate(_context), Statement::IfElse(if_else) => if_else.validate(_context), Statement::Loop(r#loop) => r#loop.validate(_context), Statement::While(r#while) => r#while.validate(_context), @@ -46,7 +48,7 @@ impl AbstractTree for Statement { Statement::Assignment(assignment) => assignment.run(_context), Statement::Block(block) => block.run(_context), Statement::Break => Ok(Action::Break), - Statement::Expression(expression) => expression.run(_context), + Statement::Expression(expression) => expression.node.run(_context), Statement::IfElse(if_else) => if_else.run(_context), Statement::Loop(r#loop) => r#loop.run(_context), Statement::While(r#while) => r#while.run(_context), diff --git a/src/error.rs b/src/error.rs index dd15538..1c60601 100644 --- a/src/error.rs +++ b/src/error.rs @@ -19,7 +19,7 @@ pub enum Error { span: (usize, usize), }, Runtime(RuntimeError), - Validation(ValidationError), + Validation(ValidationError, (usize, usize)), } impl Error { @@ -46,9 +46,15 @@ impl Error { .finish() } Error::Runtime(_) => todo!(), - Error::Validation(validation_error) => { - let mut report = - Report::build(ReportKind::Custom("Validation Error", Color::White), (), 0); + Error::Validation(validation_error, position) => { + let mut report = Report::build( + ReportKind::Custom("Validation Error: The code was not run.", Color::White), + (), + 0, + ) + .with_label( + Label::new(position.0..position.1).with_message("Error found in this item."), + ); match validation_error { ValidationError::ExpectedBoolean => { diff --git a/src/lib.rs b/src/lib.rs index 90a44f6..da678f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,9 +35,10 @@ impl Interpreter { .iter() .filter_map(|statement| { statement + .node .validate(&self.context) .err() - .map(|validation_error| Error::Validation(validation_error)) + .map(|validation_error| Error::Validation(validation_error, statement.position)) }) .collect::>(); @@ -48,7 +49,7 @@ impl Interpreter { let mut value = None; for statement in statements { - value = match statement.run(&self.context) { + value = match statement.node.run(&self.context) { Ok(action) => match action { Action::Break => None, Action::Return(value) => Some(value), diff --git a/src/parser.rs b/src/parser.rs index 14be7ee..6f6d3c2 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -12,7 +12,7 @@ pub type DustParser<'src> = Boxed< 'src, 'src, ParserInput<'src>, - Vec, + Vec>, extra::Err, SimpleSpan>>, >; @@ -21,7 +21,7 @@ pub type ParserInput<'src> = pub fn parse<'src>( tokens: &'src [(Token<'src>, SimpleSpan)], -) -> Result, Vec> { +) -> Result>, Vec> { parser() .parse(tokens.spanned((tokens.len()..tokens.len()).into())) .into_result() @@ -111,6 +111,9 @@ pub fn parser<'src>() -> DustParser<'src> { just(Token::Control(Control::Colon)).ignore_then(r#type) }); + let positioned_type = + type_specification.map_with(|r#type, state| r#type.positioned(state.span())); + let statement = recursive(|statement| { let block = statement .clone() @@ -122,6 +125,10 @@ pub fn parser<'src>() -> DustParser<'src> { ) .map(|statements| Block::new(statements)); + let positioned_block = block + .clone() + .map_with(|block, state| block.positioned(state.span())); + let expression = recursive(|expression| { let identifier_expression = identifier .clone() @@ -154,10 +161,17 @@ pub fn parser<'src>() -> DustParser<'src> { let map_assignment = identifier .clone() - .then(type_specification.clone().or_not()) + .then( + type_specification + .map_with(|r#type, state| r#type.positioned(state.span())) + .clone() + .or_not(), + ) .then_ignore(just(Token::Operator(Operator::Assign))) .then(expression.clone()) - .map(|((identifier, r#type), expression)| (identifier, r#type, expression)); + .map_with(|((identifier, r#type), expression), state| { + (identifier, r#type, expression.positioned(state.span())) + }); let map = map_assignment .separated_by(just(Token::Control(Control::Comma)).or_not()) @@ -180,11 +194,11 @@ pub fn parser<'src>() -> DustParser<'src> { ) .then(type_specification.clone()) .then(block.clone()) - .map(|((parameters, return_type), body)| { + .map_with(|((parameters, return_type), body), state| { Expression::Value(ValueNode::Function { parameters, - return_type, - body, + return_type: return_type.positioned(state.span()), + body: body.positioned(state.span()), }) }) .boxed(); @@ -216,7 +230,8 @@ pub fn parser<'src>() -> DustParser<'src> { just(Token::Control(Control::ParenOpen)), just(Token::Control(Control::ParenClose)), ), - )); + )) + .map_with(|expression, state| expression.positioned(state.span())); use Operator::*; @@ -280,6 +295,7 @@ pub fn parser<'src>() -> DustParser<'src> { choice(( function, + function_call, range, logic_math_and_index, identifier_expression, @@ -290,17 +306,22 @@ pub fn parser<'src>() -> DustParser<'src> { .boxed() }); + let positioned_expression = expression + .clone() + .map_with(|expression, state| expression.positioned(state.span())); + let expression_statement = expression .clone() - .map_with(|expression, state| Statement::expression(expression, state.span())) + .map_with(|expression, state| { + Statement::Expression(expression.positioned(state.span())) + }) .boxed(); - let r#break = - just(Token::Keyword("break")).map_with(|_, state| Statement::r#break(state.span())); + let r#break = just(Token::Keyword("break")).to(Statement::Break); let assignment = identifier .clone() - .then(type_specification.clone().or_not()) + .then(positioned_type.clone().or_not()) .then(choice(( just(Token::Operator(Operator::Assign)).to(AssignmentOperator::Assign), just(Token::Operator(Operator::AddAssign)).to(AssignmentOperator::AddAssign), @@ -308,16 +329,18 @@ pub fn parser<'src>() -> DustParser<'src> { ))) .then(statement.clone()) .map_with(|(((identifier, r#type), operator), statement), state| { - Statement::assignment( - Assignment::new(identifier, r#type, operator, statement), - state.span(), - ) + Statement::Assignment(Assignment::new( + identifier, + r#type, + operator, + statement.positioned(state.span()), + )) }) .boxed(); let block_statement = block .clone() - .map_with(|block, state| Statement::block(block, state.span())); + .map_with(|block, state| Statement::Block(block)); let r#loop = statement .clone() @@ -328,29 +351,24 @@ pub fn parser<'src>() -> DustParser<'src> { just(Token::Keyword("loop")).then(just(Token::Control(Control::CurlyOpen))), just(Token::Control(Control::CurlyClose)), ) - .map_with(|statements, state| Statement::r#loop(Loop::new(statements), state.span())) + .map_with(|statements, state| Statement::Loop(Loop::new(statements))) .boxed(); let r#while = just(Token::Keyword("while")) .ignore_then(expression.clone()) .then(block.clone()) - .map_with(|(expression, block), state| { - Statement::r#while(While::new(expression, block), state.span()) - }); + .map_with(|(expression, block), state| Statement::While(While::new(expression, block))); let if_else = just(Token::Keyword("if")) - .ignore_then(expression.clone()) - .then(block.clone()) + .ignore_then(positioned_expression.clone()) + .then(positioned_block.clone()) .then( just(Token::Keyword("else")) - .ignore_then(block.clone()) + .ignore_then(positioned_block.clone()) .or_not(), ) .map_with(|((if_expression, if_block), else_block), state| { - Statement::if_else( - IfElse::new(if_expression, if_block, else_block), - state.span(), - ) + Statement::IfElse(IfElse::new(if_expression, if_block, else_block)) }) .boxed(); @@ -367,13 +385,15 @@ pub fn parser<'src>() -> DustParser<'src> { .boxed() }); - statement.repeated().collect().boxed() + statement + .map_with(|statement, state| statement.positioned(state.span())) + .repeated() + .collect() + .boxed() } #[cfg(test)] mod tests { - use tests::statement::StatementInner; - use crate::lexer::lex; use super::*;