difftreelog
feat peg parsing for types
in: master
3 files changed
crates/jrsonnet-evaluator/src/typed.rsdiffbeforeafterboth158 Err(TypeError::ExpectedGot(self.clone(), value.value_type()).into())158 Err(TypeError::ExpectedGot(self.clone(), value.value_type()).into())159 }159 }160 }160 }161 ComplexValType::Array(elem_type) => match value {162 Val::Arr(a) => {163 for (i, item) in a.iter().enumerate() {164 push_type(165 &None,166 || format!("array index {}", i),167 || ValuePathItem::Index(i as u64),168 || Ok(elem_type.check(&item.clone()?)?),169 )?;170 }171 Ok(())172 }173 v => return Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),174 },161 ComplexValType::ArrayRef(elem_type) => match value {175 ComplexValType::ArrayRef(elem_type) => match value {162 Val::Arr(a) => {176 Val::Arr(a) => {163 for (i, item) in a.iter().enumerate() {177 for (i, item) in a.iter().enumerate() {192 }206 }193 v => return Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),207 v => return Err(TypeError::ExpectedGot(self.clone(), v.value_type()).into()),194 },208 },209 ComplexValType::Union(types) => {210 let mut errors = Vec::new();211 for ty in types.iter() {212 match ty.check(value) {213 Ok(()) => {214 return Ok(());215 }216 Err(e) => match e.error() {217 Error::TypeError(e) => errors.push(e.clone()),218 _ => return Err(e),219 },220 }221 }222 return Err(TypeError::UnionFailed(self.clone(), TypeLocErrorList(errors)).into());223 }195 ComplexValType::UnionRef(types) => {224 ComplexValType::UnionRef(types) => {196 let mut errors = Vec::new();225 let mut errors = Vec::new();197 for ty in types.iter() {226 for ty in types.iter() {207 }236 }208 return Err(TypeError::UnionFailed(self.clone(), TypeLocErrorList(errors)).into());237 return Err(TypeError::UnionFailed(self.clone(), TypeLocErrorList(errors)).into());209 }238 }239 ComplexValType::Sum(types) => {240 for ty in types.iter() {241 ty.check(value)?242 }243 Ok(())244 }210 ComplexValType::SumRef(types) => {245 ComplexValType::SumRef(types) => {211 for ty in types.iter() {246 for ty in types.iter() {212 ty.check(value)?247 ty.check(value)?crates/jrsonnet-types/Cargo.tomldiffbeforeafterboth--- a/crates/jrsonnet-types/Cargo.toml
+++ b/crates/jrsonnet-types/Cargo.toml
@@ -5,3 +5,4 @@
edition = "2018"
[dependencies]
+peg = "0.6.3"
\ No newline at end of file
crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth--- a/crates/jrsonnet-types/src/lib.rs
+++ b/crates/jrsonnet-types/src/lib.rs
@@ -110,9 +110,12 @@
Char,
Simple(ValType),
BoundedNumber(Option<f64>, Option<f64>),
+ Array(Box<ComplexValType>),
ArrayRef(&'static ComplexValType),
ObjectRef(&'static [(&'static str, ComplexValType)]),
+ Union(Vec<ComplexValType>),
UnionRef(&'static [ComplexValType]),
+ Sum(Vec<ComplexValType>),
SumRef(&'static [ComplexValType]),
}
impl From<ValType> for ComplexValType {
@@ -128,7 +131,7 @@
) -> std::fmt::Result {
for (i, v) in union.iter().enumerate() {
let should_add_braces = match v {
- ComplexValType::UnionRef(_) if !is_union => true,
+ ComplexValType::UnionRef(_) | ComplexValType::Union(_) if !is_union => true,
_ => false,
};
if i != 0 {
@@ -145,6 +148,15 @@
Ok(())
}
+fn print_array(a: &ComplexValType, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ if *a == ComplexValType::Any {
+ write!(f, "array")?
+ } else {
+ write!(f, "Array<{}>", a)?
+ }
+ Ok(())
+}
+
impl Display for ComplexValType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
@@ -157,13 +169,8 @@
a.map(|e| e.to_string()).unwrap_or_else(|| "".into()),
b.map(|e| e.to_string()).unwrap_or_else(|| "".into())
)?,
- ComplexValType::ArrayRef(a) => {
- if **a == ComplexValType::Any {
- write!(f, "array")?
- } else {
- write!(f, "Array<{}>", a)?
- }
- }
+ ComplexValType::ArrayRef(a) => print_array(a, f)?,
+ ComplexValType::Array(a) => print_array(a, f)?,
ComplexValType::ObjectRef(fields) => {
write!(f, "{{")?;
for (i, (k, v)) in fields.iter().enumerate() {
@@ -174,9 +181,93 @@
}
write!(f, "}}")?;
}
+ ComplexValType::Union(v) => write_union(f, true, v)?,
ComplexValType::UnionRef(v) => write_union(f, true, v)?,
+ ComplexValType::Sum(v) => write_union(f, false, v)?,
ComplexValType::SumRef(v) => write_union(f, false, v)?,
};
Ok(())
}
}
+
+peg::parser!{
+pub grammar parser() for str {
+ rule number() -> f64
+ = n:$(['0'..='9']+) { n.parse().unwrap() }
+
+ rule any_ty() -> ComplexValType = "any" { ComplexValType::Any }
+ rule char_ty() -> ComplexValType = "character" { ComplexValType::Char }
+ rule bool_ty() -> ComplexValType = "boolean" { ComplexValType::Simple(ValType::Bool) }
+ rule null_ty() -> ComplexValType = "null" { ComplexValType::Simple(ValType::Null) }
+ rule str_ty() -> ComplexValType = "string" { ComplexValType::Simple(ValType::Str) }
+ rule num_ty() -> ComplexValType = "number" { ComplexValType::Simple(ValType::Num) }
+ rule simple_array_ty() -> ComplexValType = "array" { ComplexValType::Simple(ValType::Arr) }
+ rule simple_object_ty() -> ComplexValType = "object" { ComplexValType::Simple(ValType::Obj) }
+ rule simple_function_ty() -> ComplexValType = "function" { ComplexValType::Simple(ValType::Func) }
+
+ rule array_ty() -> ComplexValType
+ = "Array<" t:ty() ">" { ComplexValType::Array(Box::new(t)) }
+
+ rule bounded_number_ty() -> ComplexValType
+ = "BoundedNumber<" a:number() ", " b:number() ">" { ComplexValType::BoundedNumber(Some(a), Some(b)) }
+
+ rule ty_basic() -> ComplexValType
+ = any_ty()
+ / char_ty()
+ / bool_ty()
+ / null_ty()
+ / str_ty()
+ / num_ty()
+ / simple_array_ty()
+ / simple_object_ty()
+ / simple_function_ty()
+ / array_ty()
+ / bounded_number_ty()
+
+ pub rule ty() -> ComplexValType
+ = precedence! {
+ a:(@) " | " b:@ {
+ match a {
+ ComplexValType::Union(mut a) => {
+ a.push(b);
+ ComplexValType::Union(a)
+ }
+ _ => ComplexValType::Union(vec![a, b]),
+ }
+ }
+ --
+ a:(@) " & " b:@ {
+ match a {
+ ComplexValType::Sum(mut a) => {
+ a.push(b);
+ ComplexValType::Sum(a)
+ }
+ _ => ComplexValType::Sum(vec![a, b]),
+ }
+ }
+ --
+ "(" t:ty() ")" { t }
+ t:ty_basic() { t }
+ }
+}
+}
+
+#[cfg(test)]
+pub mod tests {
+ use super::parser;
+
+ #[test]
+ fn precedence() {
+ assert_eq!(parser::ty("(any & any) | (any | any) & any").unwrap().to_string(), "any & any | (any | any) & any");
+ }
+
+ #[test]
+ fn array() {
+ assert_eq!(parser::ty("Array<any>").unwrap().to_string(), "array");
+ assert_eq!(parser::ty("Array<number>").unwrap().to_string(), "Array<number>");
+ }
+ #[test]
+ fn bounded_number() {
+ assert_eq!(parser::ty("BoundedNumber<1, 2>").unwrap().to_string(), "BoundedNumber<1, 2>");
+ }
+}
\ No newline at end of file