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]]
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"

View File

@ -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),
},
)

View File

@ -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))

View File

@ -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()),

View File

@ -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()

View File

@ -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<Action, RuntimeError>;
fn positioned(self, position: (usize, usize)) -> Positioned<Self> {
fn positioned(self, span: SimpleSpan) -> Positioned<Self> {
Positioned {
node: self,
position,
position: (span.start(), span.end()),
}
}
}

View File

@ -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<Expression>),
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),

View File

@ -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 => {

View File

@ -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::<Vec<Error>>();
@ -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),

View File

@ -12,7 +12,7 @@ pub type DustParser<'src> = Boxed<
'src,
'src,
ParserInput<'src>,
Vec<Statement>,
Vec<Positioned<Statement>>,
extra::Err<Rich<'src, Token<'src>, SimpleSpan>>,
>;
@ -21,7 +21,7 @@ pub type ParserInput<'src> =
pub fn parse<'src>(
tokens: &'src [(Token<'src>, SimpleSpan)],
) -> Result<Vec<Statement>, Vec<Error>> {
) -> Result<Vec<Positioned<Statement>>, Vec<Error>> {
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::*;