refactor module structure, clean up diagnostic reporting

This commit is contained in:
elkowar 2021-07-18 17:34:58 +02:00
parent e723335db6
commit de9d979ce5
No known key found for this signature in database
GPG key ID: E321AD71B1D1F27F
11 changed files with 222 additions and 227 deletions

158
Cargo.lock generated
View file

@ -20,23 +20,11 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]] [[package]]
name = "ascii-canvas" name = "ascii-canvas"
version = "2.0.0" version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff8eb72df928aafb99fe5d37b383f2fe25bd2a765e3e5f7c365916b6f2463a29" checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
dependencies = [ dependencies = [
"term", "term",
] ]
@ -58,12 +46,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "base64"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
[[package]] [[package]]
name = "beef" name = "beef"
version = "0.5.0" version = "0.5.0"
@ -86,21 +68,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
[[package]] [[package]]
name = "blake2b_simd" name = "bitflags"
version = "0.5.11" version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
]
[[package]]
name = "byteorder"
version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]] [[package]]
name = "cfg-if" name = "cfg-if"
@ -131,29 +102,12 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]] [[package]]
name = "convert_case" name = "convert_case"
version = "0.4.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
[[package]]
name = "crossbeam-utils"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4feb231f0d4d6af81aed15928e58ecf5816aa62a2393e2c82f46973e92a9a278"
dependencies = [
"autocfg",
"cfg-if",
"lazy_static",
]
[[package]] [[package]]
name = "crunchy" name = "crunchy"
version = "0.2.2" version = "0.2.2"
@ -190,10 +144,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
[[package]] [[package]]
name = "dirs" name = "dirs-next"
version = "1.0.5" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
dependencies = [
"cfg-if",
"dirs-sys-next",
]
[[package]]
name = "dirs-sys-next"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
dependencies = [ dependencies = [
"libc", "libc",
"redox_users", "redox_users",
@ -262,9 +226,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.1.16" version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"libc", "libc",
@ -273,9 +237,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.9.1" version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
[[package]] [[package]]
name = "heck" name = "heck"
@ -288,18 +252,18 @@ dependencies = [
[[package]] [[package]]
name = "hermit-abi" name = "hermit-abi"
version = "0.1.18" version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [ dependencies = [
"libc", "libc",
] ]
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "1.6.2" version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "824845a0bf897a9042383849b02c1bc219c2383772efcd5c6f9766fa4b81aef3" checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"hashbrown", "hashbrown",
@ -322,9 +286,9 @@ dependencies = [
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.10.0" version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf"
dependencies = [ dependencies = [
"either", "either",
] ]
@ -337,9 +301,9 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
[[package]] [[package]]
name = "lalrpop" name = "lalrpop"
version = "0.19.5" version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46962a8c71b91c3524b117dfdd70844d4265a173c4c9109f98171aebdcf1195f" checksum = "b15174f1c529af5bf1283c3bc0058266b483a67156f79589fab2a25e23cf8988"
dependencies = [ dependencies = [
"ascii-canvas", "ascii-canvas",
"atty", "atty",
@ -360,9 +324,9 @@ dependencies = [
[[package]] [[package]]
name = "lalrpop-util" name = "lalrpop-util"
version = "0.19.5" version = "0.19.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a708007b751af124d09e9c5d97515257902bc6b486a56b40bcafd939e8ff467" checksum = "d3e58cce361efcc90ba8a0a5f982c741ff86b603495bb15a998412e957dcd278"
dependencies = [ dependencies = [
"regex", "regex",
] ]
@ -375,9 +339,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.94" version = "0.2.98"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
[[package]] [[package]]
name = "linked-hash-map" name = "linked-hash-map"
@ -475,9 +439,9 @@ dependencies = [
[[package]] [[package]]
name = "pico-args" name = "pico-args"
version = "0.4.1" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d7afeb98c5a10e0bffcc7fc16e105b04d06729fac5fd6384aebf7ff5cb5a67d" checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
[[package]] [[package]]
name = "precomputed-hash" name = "precomputed-hash"
@ -517,19 +481,21 @@ dependencies = [
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.1.57" version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" checksum = "5ab49abadf3f9e1c4bc499e8845e152ad87d2ad2d30371841171169e9d75feee"
dependencies = [
"bitflags",
]
[[package]] [[package]]
name = "redox_users" name = "redox_users"
version = "0.3.5" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64"
dependencies = [ dependencies = [
"getrandom", "getrandom",
"redox_syscall", "redox_syscall",
"rust-argon2",
] ]
[[package]] [[package]]
@ -549,18 +515,6 @@ version = "0.6.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rust-argon2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
dependencies = [
"base64",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
]
[[package]] [[package]]
name = "rustc_version" name = "rustc_version"
version = "0.3.3" version = "0.3.3"
@ -570,6 +524,12 @@ dependencies = [
"semver", "semver",
] ]
[[package]]
name = "rustversion"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088"
[[package]] [[package]]
name = "ryu" name = "ryu"
version = "1.0.5" version = "1.0.5"
@ -722,12 +682,12 @@ dependencies = [
[[package]] [[package]]
name = "term" name = "term"
version = "0.5.2" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd106a334b7657c10b7c540a0106114feadeb4dc314513e97df481d5d966f42" checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
dependencies = [ dependencies = [
"byteorder", "dirs-next",
"dirs", "rustversion",
"winapi", "winapi",
] ]
@ -752,18 +712,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.25" version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" checksum = "93119e4feac1cbe6c798c34d3a53ea0026b0b1de6a120deef895137c0529bfe2"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.25" version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" checksum = "060d69a0afe7796bf42e9e2ff91f5ee691fb15c53d38b4b62a9a53eb23164745"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -817,9 +777,9 @@ checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.9.0+wasi-snapshot-preview1" version = "0.10.2+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
[[package]] [[package]]
name = "winapi" name = "winapi"

0
src/config/mod.rs Normal file
View file

View file

@ -1,4 +1,4 @@
use crate::{ use crate::parser::{
ast::{Ast, AstType, Span}, ast::{Ast, AstType, Span},
lexer, parse_error, lexer, parse_error,
}; };

View file

@ -1,42 +1,60 @@
use codespan_reporting::{diagnostic, files}; use codespan_reporting::{diagnostic, files};
use simplexpr::dynval; use simplexpr::dynval;
use crate::{ast::Span, error::AstError, parse_error};
use diagnostic::*; use diagnostic::*;
fn span_to_label(span: Span) -> Label<usize> { use crate::error::AstError;
Label::primary(span.2, span.0..span.1)
use super::parser::{ast::Span, parse_error};
macro_rules! gen_diagnostic {
(
$(msg = $msg:expr)?
$(, label = $span:expr $(=> $label:expr)?)?
$(, note = $note:expr)? $(,)?
) => {
Diagnostic::error()
$(.with_message($msg))?
$(.with_labels(vec![
Label::primary($span.2, $span.0..$span.1)
$(.with_message($label))?
]))?
$(.with_notes(vec![$note]))?
};
($msg:expr $(, $span:expr $(,)?)?) => {{
Diagnostic::error()
.with_message($msg)
$(.with_labels(vec![Label::primary($span.2, $span.0..$span.1)]))?
}};
} }
pub trait ToDiagnostic { pub trait ToDiagnostic {
fn to_diagnostic(&self, files: &files::SimpleFiles<&str, &str>) -> Diagnostic<usize>; fn to_diagnostic(&self) -> Diagnostic<usize>;
} }
impl ToDiagnostic for AstError { impl ToDiagnostic for AstError {
fn to_diagnostic(&self, files: &files::SimpleFiles<&str, &str>) -> Diagnostic<usize> { fn to_diagnostic(&self) -> Diagnostic<usize> {
let diag = Diagnostic::error(); let diag = Diagnostic::error();
if let Some(span) = self.get_span() { if let Some(span) = self.get_span() {
use lalrpop_util::ParseError::*; use lalrpop_util::ParseError::*;
match self { match self {
AstError::InvalidDefinition(_) => todo!(), AstError::InvalidDefinition(_) => todo!(),
AstError::MissingNode(_, expected) => diag AstError::MissingNode(_, expected) => gen_diagnostic! {
.with_message(format!("Missing {}", expected)) msg = format!("Missing {}", expected),
.with_labels(vec![span_to_label(span).with_message(format!("Expected `{}` here", expected))]), label = span => format!("Expected `{}` here", expected),
},
AstError::WrongExprType(_, expected, actual) => diag AstError::WrongExprType(_, expected, actual) => gen_diagnostic! {
.with_message("Wrong type of expression") msg = "Wrong type of expression",
.with_notes(vec![format!("Expected: {}\nGot: {}", expected, actual)]) label = span => format!("Expected a `{}` here", expected),
.with_labels(vec![span_to_label(span).with_message(format!("Expected a `{}` here", expected))]), note = format!("Expected: {}\nGot: {}", expected, actual),
},
AstError::ParseError { file_id, source } => { AstError::ParseError { file_id, source } => lalrpop_error_to_diagnostic(source, span, |error| match error {
lalrpop_error_to_diagnostic(source, diag, span, move |diag, error| match error { parse_error::ParseError::SimplExpr(_, error) => simplexpr_error_to_diagnostic(error, span),
parse_error::ParseError::SimplExpr(_, error) => simplexpr_error_to_diagnostic(error, diag, span), parse_error::ParseError::LexicalError(_) => lexical_error_to_diagnostic(span),
parse_error::ParseError::LexicalError(_) => diag }),
.with_message("Invalid token")
.with_labels(vec![span_to_label(span).with_message("Invalid token")]),
})
}
} }
} else { } else {
diag.with_message(format!("{}", self)) diag.with_message(format!("{}", self))
@ -46,36 +64,47 @@ impl ToDiagnostic for AstError {
fn lalrpop_error_to_diagnostic<T: std::fmt::Display, E>( fn lalrpop_error_to_diagnostic<T: std::fmt::Display, E>(
error: &lalrpop_util::ParseError<usize, T, E>, error: &lalrpop_util::ParseError<usize, T, E>,
diag: Diagnostic<usize>,
span: Span, span: Span,
handle_user_error: impl FnOnce(Diagnostic<usize>, &E) -> Diagnostic<usize>, handle_user_error: impl FnOnce(&E) -> Diagnostic<usize>,
) -> Diagnostic<usize> { ) -> Diagnostic<usize> {
use lalrpop_util::ParseError::*; use lalrpop_util::ParseError::*;
match error { match error {
InvalidToken { location } => diag.with_message("Invalid token").with_labels(vec![span_to_label(span)]), InvalidToken { location } => gen_diagnostic! { msg = "Invalid token", label = span },
UnrecognizedEOF { location, expected } => diag UnrecognizedEOF { location, expected } => gen_diagnostic! {
.with_message("Input ended unexpectedly. Check if you have any unclosed delimiters") msg = "Input ended unexpectedly. Check if you have any unclosed delimiters",
.with_labels(vec![span_to_label(span)]), label = span
UnrecognizedToken { token, expected } => diag },
.with_message(format!("Unexpected token `{}` encoutered", token.1)) UnrecognizedToken { token, expected } => gen_diagnostic! {
.with_labels(vec![span_to_label(span).with_message("Token unexpected")]), msg = format!("Unexpected token `{}` encountered", token.1),
label = span => "Token unexpected",
ExtraToken { token } => diag.with_message(format!("Extra token encountered: `{}`", token.1)), },
User { error } => handle_user_error(diag, error), ExtraToken { token } => gen_diagnostic!(format!("Extra token encountered: `{}`", token.1)),
User { error } => handle_user_error(error),
} }
} }
fn simplexpr_error_to_diagnostic(error: &simplexpr::error::Error, diag: Diagnostic<usize>, span: Span) -> Diagnostic<usize> { fn simplexpr_error_to_diagnostic(error: &simplexpr::error::Error, span: Span) -> Diagnostic<usize> {
use simplexpr::error::Error::*;
match error { match error {
simplexpr::error::Error::ParseError { source } => lalrpop_error_to_diagnostic(source, diag, span, move |diag, error| { ParseError { source } => lalrpop_error_to_diagnostic(source, span, move |error| lexical_error_to_diagnostic(span)),
diag.with_message("Invalid token").with_labels(vec![span_to_label(span).with_message("Invalid token")]) ConversionError(error) => conversion_error_to_diagnostic(error, span),
}), Eval(error) => gen_diagnostic!(format!("{}", error), span),
simplexpr::error::Error::ConversionError(dynval::ConversionError { value, target_type, source }) => diag Other(error) => gen_diagnostic!(format!("{}", error), span),
.with_message(format!("{}", error)) Spanned(_, error) => gen_diagnostic!(format!("{}", error), span),
.with_labels(vec![span_to_label(span).with_message(format!("{} is not of type `{}`", value, target_type))]) }
.with_notes(source.as_ref().map(|x| vec![format!("{}", x)]).unwrap_or_default()), }
simplexpr::error::Error::Spanned(..) => todo!(),
simplexpr::error::Error::Eval(error) => diag.with_message(format!("{}", error)).with_labels(vec![span_to_label(span)]), fn conversion_error_to_diagnostic(error: &dynval::ConversionError, span: Span) -> Diagnostic<usize> {
simplexpr::error::Error::Other(error) => diag.with_message(format!("{}", error)).with_labels(vec![span_to_label(span)]), let diag = gen_diagnostic! {
msg = format!("{}", error),
label = span => format!("{} is not of type `{}`", error.value, error.target_type),
};
diag.with_notes(error.source.as_ref().map(|x| vec![format!("{}", x)]).unwrap_or_default())
}
fn lexical_error_to_diagnostic(span: Span) -> Diagnostic<usize> {
gen_diagnostic! {
msg = "Invalid token",
label = span => "Invalid token"
} }
} }

View file

@ -2,67 +2,8 @@
#![allow(unused)] #![allow(unused)]
#![feature(try_blocks)] #![feature(try_blocks)]
pub mod ast;
pub mod config; pub mod config;
pub mod error; pub mod error;
pub mod format_diagnostic; pub mod format_diagnostic;
mod lexer; pub mod parser;
mod parse_error;
pub mod value; pub mod value;
use ast::Ast;
use error::{AstError, AstResult};
use std::{fmt::Display, ops::Deref};
use itertools::Itertools;
use lalrpop_util::lalrpop_mod;
lalrpop_mod!(
#[allow(clippy::all)]
pub parser
);
pub fn parse_string(file_id: usize, s: &str) -> AstResult<Ast> {
let lexer = lexer::Lexer::new(file_id, s.to_string());
let parser = parser::AstParser::new();
parser.parse(file_id, lexer).map_err(|e| AstError::from_parse_error(file_id, e))
}
macro_rules! test_parser {
($($text:literal),*) => {{
let p = crate::parser::AstParser::new();
use crate::lexer::Lexer;
::insta::with_settings!({sort_maps => true}, {
$(
::insta::assert_debug_snapshot!(p.parse(0, Lexer::new(0, $text.to_string())));
)*
});
}}
}
#[test]
fn test() {
test_parser!(
"1",
"(12)",
"1.2",
"-1.2",
"(1 2)",
"(1 :foo 1)",
"(:foo 1)",
"(:foo->: 1)",
"(foo 1)",
"(lol😄 1)",
r#"(test "hi")"#,
r#"(test "h\"i")"#,
r#"(test " hi ")"#,
"(+ (1 2 (* 2 5)))",
r#"; test"#,
r#"(f arg ; test
arg2)"#,
"\"h\\\"i\""
);
}

View file

@ -2,9 +2,11 @@ use itertools::Itertools;
use simplexpr::ast::SimplExpr; use simplexpr::ast::SimplExpr;
use std::collections::HashMap; use std::collections::HashMap;
use crate::{config::FromAst, error::*};
use std::fmt::Display; use std::fmt::Display;
use super::element::FromAst;
use crate::error::{AstError, AstResult};
#[derive(Eq, PartialEq, Clone, Copy)] #[derive(Eq, PartialEq, Clone, Copy)]
pub struct Span(pub usize, pub usize, pub usize); pub struct Span(pub usize, pub usize, pub usize);
@ -124,15 +126,16 @@ impl std::fmt::Display for Ast {
impl std::fmt::Debug for Ast { impl std::fmt::Debug for Ast {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Ast::*; use Ast::*;
match self { write!(f, "{}", self)
List(span, x) => f.debug_tuple(&format!("List<{}>", span)).field(x).finish(), // match self {
Array(span, x) => f.debug_tuple(&format!("Array<{}>", span)).field(x).finish(), // List(span, x) => f.debug_tuple(&format!("List<{}>", span)).field(x).finish(),
Keyword(span, x) => write!(f, "Number<{}>({})", span, x), // Array(span, x) => f.debug_tuple(&format!("Array<{}>", span)).field(x).finish(),
Symbol(span, x) => write!(f, "Symbol<{}>({})", span, x), // Keyword(span, x) => write!(f, "Number<{}>({})", span, x),
Value(span, x) => write!(f, "Value<{}>({})", span, x), // Symbol(span, x) => write!(f, "Symbol<{}>({})", span, x),
SimplExpr(span, x) => write!(f, "SimplExpr<{}>({})", span, x), // Value(span, x) => write!(f, "Value<{}>({})", span, x),
Comment(span) => write!(f, "Comment<{}>", span), // SimplExpr(span, x) => write!(f, "SimplExpr<{}>({})", span, x),
} // Comment(span) => write!(f, "Comment<{}>", span),
//}
} }
} }

View file

@ -1,8 +1,5 @@
use crate::{ use super::ast::{Ast, AstIterator, AstType, Span};
ast::{Ast, AstIterator, AstType, Span}, use crate::{error::*, parser, spanned};
error::*,
parser, spanned,
};
use itertools::Itertools; use itertools::Itertools;
use std::{ use std::{
collections::{HashMap, LinkedList}, collections::{HashMap, LinkedList},
@ -49,13 +46,17 @@ impl<C: FromAst, A: FromAst> FromAst for Element<C, A> {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::*; use super::super::{
use crate::lexer; ast::Ast,
element::{Element, FromAst},
lexer,
};
use insta; use insta;
#[test] #[test]
fn test() { fn test() {
let parser = parser::AstParser::new(); let parser = super::parser::parser::AstParser::new();
insta::with_settings!({sort_maps => true}, { insta::with_settings!({sort_maps => true}, {
let lexer = lexer::Lexer::new(0, "(box :bar 12 :baz \"hi\" foo (bar))".to_string()); let lexer = lexer::Lexer::new(0, "(box :bar 12 :baz \"hi\" foo (bar))".to_string());
insta::assert_debug_snapshot!( insta::assert_debug_snapshot!(

View file

@ -1,6 +1,6 @@
use regex::{Regex, RegexSet}; use regex::{Regex, RegexSet};
use crate::{ast::Span, parse_error}; use super::{ast::Span, parse_error};
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub enum Token { pub enum Token {

62
src/parser/mod.rs Normal file
View file

@ -0,0 +1,62 @@
use lalrpop_util::lalrpop_mod;
use super::error::{AstError, AstResult};
use ast::Ast;
use std::{fmt::Display, ops::Deref};
use itertools::Itertools;
pub mod ast;
pub mod element;
pub(crate) mod lexer;
pub(crate) mod parse_error;
lalrpop_mod!(
#[allow(clippy::all)]
pub parser,
"/parser/parser.rs"
);
pub fn parse_string(file_id: usize, s: &str) -> AstResult<Ast> {
let lexer = lexer::Lexer::new(file_id, s.to_string());
let parser = parser::AstParser::new();
parser.parse(file_id, lexer).map_err(|e| AstError::from_parse_error(file_id, e))
}
macro_rules! test_parser {
($($text:literal),*) => {{
let p = parser::AstParser::new();
use lexer::Lexer;
::insta::with_settings!({sort_maps => true}, {
$(
::insta::assert_debug_snapshot!(p.parse(0, Lexer::new(0, $text.to_string())));
)*
});
}}
}
#[test]
fn test() {
test_parser!(
"1",
"(12)",
"1.2",
"-1.2",
"(1 2)",
"(1 :foo 1)",
"(:foo 1)",
"(:foo->: 1)",
"(foo 1)",
"(lol😄 1)",
r#"(test "hi")"#,
r#"(test "h\"i")"#,
r#"(test " hi ")"#,
"(+ (1 2 (* 2 5)))",
r#"; test"#,
r#"(f arg ; test
arg2)"#,
"\"h\\\"i\""
);
}

View file

@ -1,4 +1,4 @@
use crate::ast::Span; use super::ast::Span;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum ParseError { pub enum ParseError {

View file

@ -1,6 +1,5 @@
use std::str::FromStr; use std::str::FromStr;
use crate::lexer::{Token}; use crate::parser::{lexer::{Token}, ast::{Ast, Span}, parse_error};
use crate::ast::{Ast, Span};
use simplexpr::ast::SimplExpr; use simplexpr::ast::SimplExpr;
use simplexpr; use simplexpr;
use lalrpop_util::ParseError; use lalrpop_util::ParseError;
@ -9,7 +8,7 @@ grammar(file_id: usize);
extern { extern {
type Location = usize; type Location = usize;
type Error = crate::parse_error::ParseError; type Error = parse_error::ParseError;
enum Token { enum Token {
"(" => Token::LPren, "(" => Token::LPren,
@ -58,7 +57,7 @@ SimplExpr: SimplExpr = {
let expr = x[1..x.len() - 1].to_string(); let expr = x[1..x.len() - 1].to_string();
simplexpr::parse_string(&expr).map_err(|e| { simplexpr::parse_string(&expr).map_err(|e| {
let span = e.get_span().map(|simplexpr::Span(simpl_l, simpl_r)| Span(1 + l + simpl_l, 1 + l + simpl_r, file_id)); let span = e.get_span().map(|simplexpr::Span(simpl_l, simpl_r)| Span(1 + l + simpl_l, 1 + l + simpl_r, file_id));
ParseError::User { error: crate::parse_error::ParseError::SimplExpr(span, e) }}) ParseError::User { error: parse_error::ParseError::SimplExpr(span, e) }})
} }
} }