difftreelog
feat allow both parsers at the same time
in: master
4 files changed
crates/jrsonnet-evaluator/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-evaluator/Cargo.toml
+++ b/crates/jrsonnet-evaluator/Cargo.toml
@@ -18,24 +18,26 @@
explaining-traces = ["annotate-snippets", "hi-doc"]
# Allows library authors to throw custom errors
anyhow-error = ["anyhow"]
-# Use hand-written recursive descent parser instead of PEG parser
+# Use hand-written recursive descent parser
ir-parser = ["dep:jrsonnet-ir-parser"]
+# Use PEG parser
+peg-parser = ["dep:jrsonnet-peg-parser"]
# Allows to preserve field order in objects
exp-preserve-order = []
# Implements field destructuring
-exp-destruct = ["jrsonnet-peg-parser/exp-destruct"]
+exp-destruct = ["jrsonnet-peg-parser?/exp-destruct", "jrsonnet-ir-parser?/exp-destruct"]
# Iteration over objects yields [key, value] elements
exp-object-iteration = []
# Bigint type
exp-bigint = ["num-bigint", "jrsonnet-types/exp-bigint"]
# obj?.field, obj?.['field']
-exp-null-coaelse = ["jrsonnet-peg-parser/exp-null-coaelse", "jrsonnet-ir-parser?/exp-null-coaelse"]
+exp-null-coaelse = ["jrsonnet-peg-parser?/exp-null-coaelse", "jrsonnet-ir-parser?/exp-null-coaelse"]
[dependencies]
jrsonnet-interner.workspace = true
jrsonnet-ir.workspace = true
-jrsonnet-peg-parser.workspace = true
+jrsonnet-peg-parser = { workspace = true, optional = true }
jrsonnet-ir-parser = { workspace = true, optional = true }
jrsonnet-types.workspace = true
jrsonnet-macros.workspace = true
crates/jrsonnet-evaluator/src/async_import.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/async_import.rs
+++ b/crates/jrsonnet-evaluator/src/async_import.rs
@@ -7,10 +7,6 @@
FieldMember, FieldName, ForSpecData, IfElse, IfSpecData, ImportKind, ObjBody, Slice, SliceDesc,
Source, SourcePath, Spanned,
};
-#[cfg(feature = "ir-parser")]
-use jrsonnet_ir_parser::ParserSettings;
-#[cfg(not(feature = "ir-parser"))]
-use jrsonnet_peg_parser::ParserSettings;
use rustc_hash::FxHashMap;
use crate::{AsPathLike, FileData, ImportResolver, ResolvePathOwned, State};
@@ -326,7 +322,7 @@
};
let source = Source::new(path.clone(), code.clone());
// If failed - then skip import
- file.parsed = crate::parse_jsonnet(&code, &ParserSettings { source })
+ file.parsed = crate::parse_jsonnet(&code, source)
.map(Rc::new)
.ok();
if let Some(parsed) = &file.parsed {
crates/jrsonnet-evaluator/src/error.rsdiffbeforeafterboth14 ObjValue, ResolvePathOwned,14 ObjValue, ResolvePathOwned,15};15};1617#[derive(Debug, Clone)]18pub struct SyntaxErrorLocation {19 pub offset: usize,20}2122#[derive(Debug, Clone)]23pub struct SyntaxError {24 pub message: String,25 pub location: SyntaxErrorLocation,26}27impl fmt::Display for SyntaxError {28 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {29 write!(f, "{}", self.message)30 }31}163217pub(crate) fn format_found(list: &[IStr], what: &str) -> String {33pub(crate) fn format_found(list: &[IStr], what: &str) -> String {18 if list.is_empty() {34 if list.is_empty() {154 ImportNotSupported(SourcePath, ResolvePathOwned),170 ImportNotSupported(SourcePath, ResolvePathOwned),155 #[error("can't import from virtual file")]171 #[error("can't import from virtual file")]156 CantImportFromVirtualFile,172 CantImportFromVirtualFile,157 #[cfg(not(feature = "ir-parser"))]158 #[error(159 "syntax error: {}",160 // Peg has no fancier way to handle critical parsing errors https://github.com/kevinmehall/rust-peg/issues/225161 {.error.expected.tokens().find(|t| t.starts_with("!!!")).map_or_else(|| {162 format!(163 "expected {}, got {:?}",164 .error.expected,165 .path.code().chars().nth(error.location.offset)166 .map_or_else(|| "EOF".into(), |c| c.to_string())167 )168 }, |v| v[3..].into())}169 )]170 ImportSyntaxError {171 path: Source,172 #[trace(skip)]173 error: Box<jrsonnet_peg_parser::ParseError>,174 },175176 #[cfg(feature = "ir-parser")]177 #[error("syntax error: {error}")]173 #[error("syntax error: {error}")]178 ImportSyntaxError {174 ImportSyntaxError {179 path: Source,175 path: Source,180 #[trace(skip)]176 #[trace(skip)]181 error: Box<jrsonnet_ir_parser::ParseError>,177 error: Box<SyntaxError>,182 },178 },183179184 #[error("runtime error: {}", format_empty_str(.0))]180 #[error("runtime error: {}", format_empty_str(.0))]crates/jrsonnet-evaluator/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/lib.rs
+++ b/crates/jrsonnet-evaluator/src/lib.rs
@@ -46,10 +46,11 @@
use jrsonnet_ir::{Expr, Source, SourcePath};
#[doc(hidden)]
pub use jrsonnet_macros;
-#[cfg(feature = "ir-parser")]
-use jrsonnet_ir_parser::ParserSettings;
-#[cfg(not(feature = "ir-parser"))]
-use jrsonnet_peg_parser::ParserSettings;
+
+#[cfg(not(any(feature = "ir-parser", feature = "peg-parser")))]
+compile_error!("at least one of `ir-parser` or `peg-parser` features must be enabled");
+
+pub use error::{SyntaxError, SyntaxErrorLocation};
pub use obj::*;
pub use rustc_hash;
use rustc_hash::FxHashMap;
@@ -59,20 +60,64 @@
use crate::gc::WithCapacityExt as _;
+pub(crate) fn parse_jsonnet(code: &str, source: Source) -> Result<Expr, SyntaxError> {
+ #[cfg(all(feature = "ir-parser", feature = "peg-parser"))]
+ {
+ if std::env::var_os("JRSONNET_LEGACY_PARSER").is_some() {
+ return parse_peg(code, source);
+ }
+ return parse_ir(code, source);
+ }
+ #[cfg(all(feature = "ir-parser", not(feature = "peg-parser")))]
+ {
+ return parse_ir(code, source);
+ }
+ #[cfg(all(feature = "peg-parser", not(feature = "ir-parser")))]
+ {
+ return parse_peg(code, source);
+ }
+}
+
#[cfg(feature = "ir-parser")]
-pub(crate) fn parse_jsonnet(
- code: &str,
- settings: &ParserSettings,
-) -> Result<Expr, jrsonnet_ir_parser::ParseError> {
- jrsonnet_ir_parser::parse(code, settings)
+fn parse_ir(code: &str, source: Source) -> Result<Expr, SyntaxError> {
+ jrsonnet_ir_parser::parse(code, &jrsonnet_ir_parser::ParserSettings { source }).map_err(
+ |e| SyntaxError {
+ message: e.message,
+ location: SyntaxErrorLocation {
+ offset: e.location.offset,
+ },
+ },
+ )
}
-#[cfg(not(feature = "ir-parser"))]
-pub(crate) fn parse_jsonnet(
- code: &str,
- settings: &ParserSettings,
-) -> Result<Expr, jrsonnet_peg_parser::ParseError> {
- jrsonnet_peg_parser::parse(code, settings)
+#[cfg(feature = "peg-parser")]
+fn parse_peg(code: &str, source: Source) -> Result<Expr, SyntaxError> {
+ jrsonnet_peg_parser::parse(code, &jrsonnet_peg_parser::ParserSettings { source }).map_err(
+ |e| {
+ let message = e
+ .expected
+ .tokens()
+ .find(|t| t.starts_with("!!!"))
+ .map_or_else(
+ || {
+ format!(
+ "expected {}, got {:?}",
+ e.expected,
+ code.chars()
+ .nth(e.location.offset)
+ .map_or_else(|| "EOF".into(), |c: char| c.to_string())
+ )
+ },
+ |v| v[3..].into(),
+ );
+ SyntaxError {
+ message,
+ location: SyntaxErrorLocation {
+ offset: e.location.offset,
+ },
+ }
+ },
+ )
}
cc_dyn!(
@@ -364,12 +409,7 @@
let file_name = Source::new(path.clone(), code.clone());
if file.parsed.is_none() {
file.parsed = Some(
- parse_jsonnet(
- &code,
- &ParserSettings {
- source: file_name.clone(),
- },
- )
+ parse_jsonnet(&code, file_name.clone())
.map(Rc::new)
.map_err(|e| ImportSyntaxError {
path: file_name.clone(),
@@ -480,12 +520,7 @@
pub fn evaluate_snippet(&self, name: impl Into<IStr>, code: impl Into<IStr>) -> Result<Val> {
let code = code.into();
let source = Source::new_virtual(name.into(), code.clone());
- let parsed = parse_jsonnet(
- &code,
- &ParserSettings {
- source: source.clone(),
- },
- )
+ let parsed = parse_jsonnet(&code, source.clone())
.map_err(|e| ImportSyntaxError {
path: source.clone(),
error: Box::new(e),
@@ -501,12 +536,7 @@
) -> Result<Val> {
let code = code.into();
let source = Source::new_virtual(name.into(), code.clone());
- let parsed = parse_jsonnet(
- &code,
- &ParserSettings {
- source: source.clone(),
- },
- )
+ let parsed = parse_jsonnet(&code, source.clone())
.map_err(|e| ImportSyntaxError {
path: source.clone(),
error: Box::new(e),