Improve positioning

This commit is contained in:
Jeff 2024-03-17 02:51:33 -04:00
parent 3224c04f72
commit 46419956bd
10 changed files with 180 additions and 128 deletions

80
Cargo.lock generated
View File

@ -4,9 +4,9 @@ version = 3
[[package]] [[package]]
name = "ahash" name = "ahash"
version = "0.8.9" version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d713b3834d76b85304d4d525563c1276e2e30dc97cc67bfb4585a4a29fc2c89f" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
@ -96,9 +96,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.86" version = "1.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f9fa1897e4325be0d68d48df6aa1a71ac2ed4d27723887e7754192705350730" checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -121,9 +121,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.2" version = "4.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651" checksum = "949626d00e063efc93b6dca932419ceb5432f99769911c0b995f7e884c778813"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -143,9 +143,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.5.0" version = "4.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47" checksum = "90239a040c80f5e14809ca132ddc4176ab33d5e17e49691793296e3fcb34d72f"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
@ -243,15 +243,15 @@ dependencies = [
[[package]] [[package]]
name = "heck" name = "heck"
version = "0.4.1" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.3.6" version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]] [[package]]
name = "humantime" name = "humantime"
@ -302,9 +302,9 @@ checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.78" version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -420,9 +420,9 @@ checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.50" version = "2.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74f1bdc9872430ce9b75da68329d1c1746faf50ffac5f19e02b71e37ff881ffb" checksum = "7383cd0e49fff4b6b90ca5670bfd3e9d6a733b3f90c686605aa7eec8c4996032"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -499,7 +499,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [ dependencies = [
"windows-targets 0.52.0", "windows-targets 0.52.4",
] ]
[[package]] [[package]]
@ -534,17 +534,17 @@ dependencies = [
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm 0.52.0", "windows_aarch64_gnullvm 0.52.4",
"windows_aarch64_msvc 0.52.0", "windows_aarch64_msvc 0.52.4",
"windows_i686_gnu 0.52.0", "windows_i686_gnu 0.52.4",
"windows_i686_msvc 0.52.0", "windows_i686_msvc 0.52.4",
"windows_x86_64_gnu 0.52.0", "windows_x86_64_gnu 0.52.4",
"windows_x86_64_gnullvm 0.52.0", "windows_x86_64_gnullvm 0.52.4",
"windows_x86_64_msvc 0.52.0", "windows_x86_64_msvc 0.52.4",
] ]
[[package]] [[package]]
@ -561,9 +561,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
@ -579,9 +579,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
@ -597,9 +597,9 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
@ -615,9 +615,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
@ -633,9 +633,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
@ -651,9 +651,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
@ -669,9 +669,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.0" version = "0.52.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
[[package]] [[package]]
name = "yansi" name = "yansi"

View File

@ -126,7 +126,9 @@ mod tests {
None, None,
AssignmentOperator::Assign, AssignmentOperator::Assign,
Positioned { Positioned {
node: Statement::Expression(Expression::Value(ValueNode::Integer(42))), node: Statement::Expression(
Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()),
),
position: (0, 0), position: (0, 0),
}, },
) )
@ -152,7 +154,9 @@ mod tests {
None, None,
AssignmentOperator::AddAssign, AssignmentOperator::AddAssign,
Positioned { Positioned {
node: Statement::Expression(Expression::Value(ValueNode::Integer(41))), node: Statement::Expression(
Expression::Value(ValueNode::Integer(41)).positioned((0..1).into()),
),
position: (0, 0), position: (0, 0),
}, },
) )
@ -178,7 +182,9 @@ mod tests {
None, None,
AssignmentOperator::SubAssign, AssignmentOperator::SubAssign,
Positioned { Positioned {
node: Statement::Expression(Expression::Value(ValueNode::Integer(1))), node: Statement::Expression(
Expression::Value(ValueNode::Integer(1)).positioned((0..1).into()),
),
position: (0, 0), position: (0, 0),
}, },
) )
@ -201,7 +207,9 @@ mod tests {
}), }),
AssignmentOperator::Assign, AssignmentOperator::Assign,
Positioned { Positioned {
node: Statement::Expression(Expression::Value(ValueNode::Integer(42))), node: Statement::Expression(
Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()),
),
position: (0, 0), position: (0, 0),
}, },
) )

View File

@ -61,9 +61,15 @@ mod tests {
#[test] #[test]
fn run_returns_value_of_final_statement() { fn run_returns_value_of_final_statement() {
let block = Block::new(vec![ let block = Block::new(vec![
Statement::Expression(Expression::Value(ValueNode::Integer(1))), Statement::Expression(
Statement::Expression(Expression::Value(ValueNode::Integer(2))), Expression::Value(ValueNode::Integer(1)).positioned((0..1).into()),
Statement::Expression(Expression::Value(ValueNode::Integer(42))), ),
Statement::Expression(
Expression::Value(ValueNode::Integer(2)).positioned((0..1).into()),
),
Statement::Expression(
Expression::Value(ValueNode::Integer(42)).positioned((0..1).into()),
),
]); ]);
assert_eq!( assert_eq!(
@ -75,8 +81,12 @@ mod tests {
#[test] #[test]
fn expected_type_returns_type_of_final_statement() { fn expected_type_returns_type_of_final_statement() {
let block = Block::new(vec![ let block = Block::new(vec![
Statement::Expression(Expression::Value(ValueNode::String("42".to_string()))), Statement::Expression(
Statement::Expression(Expression::Value(ValueNode::Integer(42))), 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)) assert_eq!(block.expected_type(&Context::new()), Ok(Type::Integer))

View File

@ -83,11 +83,12 @@ mod tests {
fn simple_if() { fn simple_if() {
assert_eq!( assert_eq!(
IfElse::new( IfElse::new(
Expression::Value(ValueNode::Boolean(true)).positioned((0, 0)), Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
Block::new(vec![Statement::Expression(Expression::Value( Block::new(vec![Statement::Expression(
ValueNode::String("foo".to_string()) Expression::Value(ValueNode::String("foo".to_string()))
),)]) .positioned((0..0).into())
.positioned((0, 0)), )])
.positioned((0..0).into()),
None None
) )
.run(&Context::new()), .run(&Context::new()),
@ -99,16 +100,18 @@ mod tests {
fn simple_if_else() { fn simple_if_else() {
assert_eq!( assert_eq!(
IfElse::new( IfElse::new(
Expression::Value(ValueNode::Boolean(false)).positioned((0, 0)), Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()),
Block::new(vec![Statement::Expression(Expression::Value( Block::new(vec![Statement::Expression(
ValueNode::String("foo".to_string()) Expression::Value(ValueNode::String("foo".to_string()))
))]) .positioned((0..0).into())
.positioned((0, 0)), )])
.positioned((0..0).into()),
Some( Some(
Block::new(vec![Statement::Expression(Expression::Value( Block::new(vec![Statement::Expression(
ValueNode::String("bar".to_string()) Expression::Value(ValueNode::String("bar".to_string()))
))]) .positioned((0..0).into())
.positioned((0, 0)) )])
.positioned((0..0).into())
) )
) )
.run(&Context::new()), .run(&Context::new()),

View File

@ -139,8 +139,8 @@ mod tests {
#[test] #[test]
fn equal() { fn equal() {
assert!(Logic::Equal( assert!(Logic::Equal(
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)), Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -153,8 +153,8 @@ mod tests {
#[test] #[test]
fn not_equal() { fn not_equal() {
assert!(Logic::NotEqual( assert!(Logic::NotEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(43)).positioned((0, 0)), Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -167,8 +167,8 @@ mod tests {
#[test] #[test]
fn greater() { fn greater() {
assert!(Logic::Greater( assert!(Logic::Greater(
Expression::Value(ValueNode::Integer(43)).positioned((0, 0)), Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -181,8 +181,8 @@ mod tests {
#[test] #[test]
fn less() { fn less() {
assert!(Logic::Less( assert!(Logic::Less(
Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(43)).positioned((0, 0)), Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -195,8 +195,8 @@ mod tests {
#[test] #[test]
fn greater_or_equal() { fn greater_or_equal() {
assert!(Logic::GreaterOrEqual( assert!(Logic::GreaterOrEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(41)).positioned((0, 0)), Expression::Value(ValueNode::Integer(41)).positioned((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -206,8 +206,8 @@ mod tests {
.unwrap()); .unwrap());
assert!(Logic::GreaterOrEqual( assert!(Logic::GreaterOrEqual(
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)), Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -220,8 +220,8 @@ mod tests {
#[test] #[test]
fn less_or_equal() { fn less_or_equal() {
assert!(Logic::LessOrEqual( assert!(Logic::LessOrEqual(
Expression::Value(ValueNode::Integer(42)).positioned((0, 0)), Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
Expression::Value(ValueNode::Integer(43)).positioned((0, 0)), Expression::Value(ValueNode::Integer(43)).positioned((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -231,8 +231,8 @@ mod tests {
.unwrap()); .unwrap());
assert!(Logic::LessOrEqual( assert!(Logic::LessOrEqual(
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)), Expression::Value(ValueNode::Integer(42)).positioned((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -245,8 +245,8 @@ mod tests {
#[test] #[test]
fn and() { fn and() {
assert!(Logic::And( assert!(Logic::And(
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)), Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -259,8 +259,8 @@ mod tests {
#[test] #[test]
fn or() { fn or() {
assert!(Logic::Or( assert!(Logic::Or(
Expression::Value(ValueNode::Boolean(true)).positioned((0, 0)), Expression::Value(ValueNode::Boolean(true)).positioned((0..0).into()),
Expression::Value(ValueNode::Boolean(false)).positioned((0, 0)), Expression::Value(ValueNode::Boolean(false)).positioned((0..0).into()),
) )
.run(&Context::new()) .run(&Context::new())
.unwrap() .unwrap()
@ -273,7 +273,7 @@ mod tests {
#[test] #[test]
fn not() { fn not() {
assert!( 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()) .run(&Context::new())
.unwrap() .unwrap()
.as_return_value() .as_return_value()

View File

@ -13,6 +13,8 @@ pub mod r#type;
pub mod value_node; pub mod value_node;
pub mod r#while; pub mod r#while;
use chumsky::span::{SimpleSpan, Span};
pub use self::{ pub use self::{
assignment::{Assignment, AssignmentOperator}, assignment::{Assignment, AssignmentOperator},
block::Block, block::Block,
@ -47,10 +49,10 @@ pub trait AbstractTree: Sized {
fn validate(&self, context: &Context) -> Result<(), ValidationError>; fn validate(&self, context: &Context) -> Result<(), ValidationError>;
fn run(self, context: &Context) -> Result<Action, RuntimeError>; fn run(self, context: &Context) -> Result<Action, RuntimeError>;
fn positioned(self, position: (usize, usize)) -> Positioned<Self> { fn positioned(self, span: SimpleSpan) -> Positioned<Self> {
Positioned { Positioned {
node: self, node: self,
position, position: (span.start(), span.end()),
} }
} }
} }

View File

@ -3,14 +3,16 @@ use crate::{
error::{RuntimeError, ValidationError}, 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)] #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Statement { pub enum Statement {
Assignment(Assignment), Assignment(Assignment),
Block(Block), Block(Block),
Break, Break,
Expression(Expression), Expression(Positioned<Expression>),
IfElse(IfElse), IfElse(IfElse),
Loop(Loop), Loop(Loop),
While(While), While(While),
@ -22,7 +24,7 @@ impl AbstractTree for Statement {
Statement::Assignment(assignment) => assignment.expected_type(_context), Statement::Assignment(assignment) => assignment.expected_type(_context),
Statement::Block(block) => block.expected_type(_context), Statement::Block(block) => block.expected_type(_context),
Statement::Break => Ok(Type::None), 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::IfElse(if_else) => if_else.expected_type(_context),
Statement::Loop(r#loop) => r#loop.expected_type(_context), Statement::Loop(r#loop) => r#loop.expected_type(_context),
Statement::While(r#while) => r#while.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::Assignment(assignment) => assignment.validate(_context),
Statement::Block(block) => block.validate(_context), Statement::Block(block) => block.validate(_context),
Statement::Break => Ok(()), 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::IfElse(if_else) => if_else.validate(_context),
Statement::Loop(r#loop) => r#loop.validate(_context), Statement::Loop(r#loop) => r#loop.validate(_context),
Statement::While(r#while) => r#while.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::Assignment(assignment) => assignment.run(_context),
Statement::Block(block) => block.run(_context), Statement::Block(block) => block.run(_context),
Statement::Break => Ok(Action::Break), 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::IfElse(if_else) => if_else.run(_context),
Statement::Loop(r#loop) => r#loop.run(_context), Statement::Loop(r#loop) => r#loop.run(_context),
Statement::While(r#while) => r#while.run(_context), Statement::While(r#while) => r#while.run(_context),

View File

@ -19,7 +19,7 @@ pub enum Error {
span: (usize, usize), span: (usize, usize),
}, },
Runtime(RuntimeError), Runtime(RuntimeError),
Validation(ValidationError), Validation(ValidationError, (usize, usize)),
} }
impl Error { impl Error {
@ -46,9 +46,15 @@ impl Error {
.finish() .finish()
} }
Error::Runtime(_) => todo!(), Error::Runtime(_) => todo!(),
Error::Validation(validation_error) => { Error::Validation(validation_error, position) => {
let mut report = let mut report = Report::build(
Report::build(ReportKind::Custom("Validation Error", Color::White), (), 0); 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 { match validation_error {
ValidationError::ExpectedBoolean => { ValidationError::ExpectedBoolean => {

View File

@ -35,9 +35,10 @@ impl Interpreter {
.iter() .iter()
.filter_map(|statement| { .filter_map(|statement| {
statement statement
.node
.validate(&self.context) .validate(&self.context)
.err() .err()
.map(|validation_error| Error::Validation(validation_error)) .map(|validation_error| Error::Validation(validation_error, statement.position))
}) })
.collect::<Vec<Error>>(); .collect::<Vec<Error>>();
@ -48,7 +49,7 @@ impl Interpreter {
let mut value = None; let mut value = None;
for statement in statements { for statement in statements {
value = match statement.run(&self.context) { value = match statement.node.run(&self.context) {
Ok(action) => match action { Ok(action) => match action {
Action::Break => None, Action::Break => None,
Action::Return(value) => Some(value), Action::Return(value) => Some(value),

View File

@ -12,7 +12,7 @@ pub type DustParser<'src> = Boxed<
'src, 'src,
'src, 'src,
ParserInput<'src>, ParserInput<'src>,
Vec<Statement>, Vec<Positioned<Statement>>,
extra::Err<Rich<'src, Token<'src>, SimpleSpan>>, extra::Err<Rich<'src, Token<'src>, SimpleSpan>>,
>; >;
@ -21,7 +21,7 @@ pub type ParserInput<'src> =
pub fn parse<'src>( pub fn parse<'src>(
tokens: &'src [(Token<'src>, SimpleSpan)], tokens: &'src [(Token<'src>, SimpleSpan)],
) -> Result<Vec<Statement>, Vec<Error>> { ) -> Result<Vec<Positioned<Statement>>, Vec<Error>> {
parser() parser()
.parse(tokens.spanned((tokens.len()..tokens.len()).into())) .parse(tokens.spanned((tokens.len()..tokens.len()).into()))
.into_result() .into_result()
@ -111,6 +111,9 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Control(Control::Colon)).ignore_then(r#type) 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 statement = recursive(|statement| {
let block = statement let block = statement
.clone() .clone()
@ -122,6 +125,10 @@ pub fn parser<'src>() -> DustParser<'src> {
) )
.map(|statements| Block::new(statements)); .map(|statements| Block::new(statements));
let positioned_block = block
.clone()
.map_with(|block, state| block.positioned(state.span()));
let expression = recursive(|expression| { let expression = recursive(|expression| {
let identifier_expression = identifier let identifier_expression = identifier
.clone() .clone()
@ -154,10 +161,17 @@ pub fn parser<'src>() -> DustParser<'src> {
let map_assignment = identifier let map_assignment = identifier
.clone() .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_ignore(just(Token::Operator(Operator::Assign)))
.then(expression.clone()) .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 let map = map_assignment
.separated_by(just(Token::Control(Control::Comma)).or_not()) .separated_by(just(Token::Control(Control::Comma)).or_not())
@ -180,11 +194,11 @@ pub fn parser<'src>() -> DustParser<'src> {
) )
.then(type_specification.clone()) .then(type_specification.clone())
.then(block.clone()) .then(block.clone())
.map(|((parameters, return_type), body)| { .map_with(|((parameters, return_type), body), state| {
Expression::Value(ValueNode::Function { Expression::Value(ValueNode::Function {
parameters, parameters,
return_type, return_type: return_type.positioned(state.span()),
body, body: body.positioned(state.span()),
}) })
}) })
.boxed(); .boxed();
@ -216,7 +230,8 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Control(Control::ParenOpen)), just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)), just(Token::Control(Control::ParenClose)),
), ),
)); ))
.map_with(|expression, state| expression.positioned(state.span()));
use Operator::*; use Operator::*;
@ -280,6 +295,7 @@ pub fn parser<'src>() -> DustParser<'src> {
choice(( choice((
function, function,
function_call,
range, range,
logic_math_and_index, logic_math_and_index,
identifier_expression, identifier_expression,
@ -290,17 +306,22 @@ pub fn parser<'src>() -> DustParser<'src> {
.boxed() .boxed()
}); });
let positioned_expression = expression
.clone()
.map_with(|expression, state| expression.positioned(state.span()));
let expression_statement = expression let expression_statement = expression
.clone() .clone()
.map_with(|expression, state| Statement::expression(expression, state.span())) .map_with(|expression, state| {
Statement::Expression(expression.positioned(state.span()))
})
.boxed(); .boxed();
let r#break = let r#break = just(Token::Keyword("break")).to(Statement::Break);
just(Token::Keyword("break")).map_with(|_, state| Statement::r#break(state.span()));
let assignment = identifier let assignment = identifier
.clone() .clone()
.then(type_specification.clone().or_not()) .then(positioned_type.clone().or_not())
.then(choice(( .then(choice((
just(Token::Operator(Operator::Assign)).to(AssignmentOperator::Assign), just(Token::Operator(Operator::Assign)).to(AssignmentOperator::Assign),
just(Token::Operator(Operator::AddAssign)).to(AssignmentOperator::AddAssign), just(Token::Operator(Operator::AddAssign)).to(AssignmentOperator::AddAssign),
@ -308,16 +329,18 @@ pub fn parser<'src>() -> DustParser<'src> {
))) )))
.then(statement.clone()) .then(statement.clone())
.map_with(|(((identifier, r#type), operator), statement), state| { .map_with(|(((identifier, r#type), operator), statement), state| {
Statement::assignment( Statement::Assignment(Assignment::new(
Assignment::new(identifier, r#type, operator, statement), identifier,
state.span(), r#type,
) operator,
statement.positioned(state.span()),
))
}) })
.boxed(); .boxed();
let block_statement = block let block_statement = block
.clone() .clone()
.map_with(|block, state| Statement::block(block, state.span())); .map_with(|block, state| Statement::Block(block));
let r#loop = statement let r#loop = statement
.clone() .clone()
@ -328,29 +351,24 @@ pub fn parser<'src>() -> DustParser<'src> {
just(Token::Keyword("loop")).then(just(Token::Control(Control::CurlyOpen))), just(Token::Keyword("loop")).then(just(Token::Control(Control::CurlyOpen))),
just(Token::Control(Control::CurlyClose)), 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(); .boxed();
let r#while = just(Token::Keyword("while")) let r#while = just(Token::Keyword("while"))
.ignore_then(expression.clone()) .ignore_then(expression.clone())
.then(block.clone()) .then(block.clone())
.map_with(|(expression, block), state| { .map_with(|(expression, block), state| Statement::While(While::new(expression, block)));
Statement::r#while(While::new(expression, block), state.span())
});
let if_else = just(Token::Keyword("if")) let if_else = just(Token::Keyword("if"))
.ignore_then(expression.clone()) .ignore_then(positioned_expression.clone())
.then(block.clone()) .then(positioned_block.clone())
.then( .then(
just(Token::Keyword("else")) just(Token::Keyword("else"))
.ignore_then(block.clone()) .ignore_then(positioned_block.clone())
.or_not(), .or_not(),
) )
.map_with(|((if_expression, if_block), else_block), state| { .map_with(|((if_expression, if_block), else_block), state| {
Statement::if_else( Statement::IfElse(IfElse::new(if_expression, if_block, else_block))
IfElse::new(if_expression, if_block, else_block),
state.span(),
)
}) })
.boxed(); .boxed();
@ -367,13 +385,15 @@ pub fn parser<'src>() -> DustParser<'src> {
.boxed() .boxed()
}); });
statement.repeated().collect().boxed() statement
.map_with(|statement, state| statement.positioned(state.span()))
.repeated()
.collect()
.boxed()
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use tests::statement::StatementInner;
use crate::lexer::lex; use crate::lexer::lex;
use super::*; use super::*;