difftreelog
feat std.decodeUTF8 builtin
in: master
3 files changed
crates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -112,6 +112,7 @@
("range".into(), builtin_range),
("char".into(), builtin_char),
("encodeUTF8".into(), builtin_encode_utf8),
+ ("decodeUTF8".into(), builtin_decode_utf8),
("md5".into(), builtin_md5),
("base64".into(), builtin_base64),
("base64DecodeBytes".into(), builtin_base64_decode_bytes),
@@ -585,6 +586,23 @@
})
}
+fn builtin_decode_utf8(
+ context: Context,
+ _loc: Option<&ExprLocation>,
+ args: &ArgsDesc,
+) -> Result<Val> {
+ parse_args!(context, "decodeUTF8", args, 1, [
+ 0, arr: ty!((Array<ubyte>)) => Val::Arr;
+ ], {
+ let data: Result<Vec<u8>> = arr.iter().map(|v| v.map(|v| match v{
+ Val::Num(n) => n as u8,
+ _ => unreachable!(),
+ })).collect();
+ let data = data?;
+ Ok(Val::Str(String::from_utf8(data).map_err(|_| RuntimeError("bad utf8".into()))?.into()))
+ })
+}
+
fn builtin_md5(context: Context, _loc: Option<&ExprLocation>, args: &ArgsDesc) -> Result<Val> {
parse_args!(context, "md5", args, 1, [
0, str: ty!(string) => Val::Str;
crates/jrsonnet-stdlib/src/std.jsonnetdiffbeforeafterboth--- a/crates/jrsonnet-stdlib/src/std.jsonnet
+++ b/crates/jrsonnet-stdlib/src/std.jsonnet
@@ -18,6 +18,7 @@
filter:: $intrinsic(filter),
char:: $intrinsic(char),
encodeUTF8:: $intrinsic(encodeUTF8),
+ decodeUTF8:: $intrinsic(decodeUTF8),
md5:: $intrinsic(md5),
trace:: $intrinsic(trace),
id:: $intrinsic(id),
crates/jrsonnet-types/src/lib.rsdiffbeforeafterboth1#![allow(clippy::redundant_closure_call)]23use jrsonnet_gc::Trace;4use std::fmt::Display;56#[macro_export]7macro_rules! ty {8 ((Array<number>)) => {{9 $crate::ComplexValType::ArrayRef(&$crate::ComplexValType::Simple($crate::ValType::Num))10 }};11 (array) => {12 $crate::ComplexValType::Simple($crate::ValType::Arr)13 };14 (boolean) => {15 $crate::ComplexValType::Simple($crate::ValType::Bool)16 };17 (null) => {18 $crate::ComplexValType::Simple($crate::ValType::Null)19 };20 (string) => {21 $crate::ComplexValType::Simple($crate::ValType::Str)22 };23 (char) => {24 $crate::ComplexValType::Char25 };26 (number) => {27 $crate::ComplexValType::Simple($crate::ValType::Num)28 };29 (BoundedNumber<($min:expr), ($max:expr)>) => {{30 $crate::ComplexValType::BoundedNumber($min, $max)31 }};32 (object) => {33 $crate::ComplexValType::Simple($crate::ValType::Obj)34 };35 (any) => {36 $crate::ComplexValType::Any37 };38 (function) => {39 $crate::ComplexValType::Simple($crate::ValType::Func)40 };41 (($($a:tt) |+)) => {{42 static CONTENTS: &'static [$crate::ComplexValType] = &[43 $(ty!($a)),+44 ];45 $crate::ComplexValType::UnionRef(CONTENTS)46 }};47 (($($a:tt) &+)) => {{48 static CONTENTS: &'static [$crate::ComplexValType] = &[49 $(ty!($a)),+50 ];51 $crate::ComplexValType::SumRef(CONTENTS)52 }};53}5455#[test]56fn test() {57 assert_eq!(58 ty!((Array<number>)),59 ComplexValType::ArrayRef(&ComplexValType::Simple(ValType::Num))60 );61 assert_eq!(ty!(array), ComplexValType::Simple(ValType::Arr));62 assert_eq!(ty!(any), ComplexValType::Any);63 assert_eq!(64 ty!((string | number)),65 ComplexValType::UnionRef(&[66 ComplexValType::Simple(ValType::Str),67 ComplexValType::Simple(ValType::Num)68 ])69 );70 assert_eq!(71 format!("{}", ty!(((string & number) | (object & null)))),72 "string & number | object & null"73 );74 assert_eq!(format!("{}", ty!((string | array))), "string | array");75 assert_eq!(76 format!("{}", ty!(((string & number) | array))),77 "string & number | array"78 );79}8081#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]82#[trivially_drop]83pub enum ValType {84 Bool,85 Null,86 Str,87 Num,88 Arr,89 Obj,90 Func,91}9293impl ValType {94 pub const fn name(&self) -> &'static str {95 use ValType::*;96 match self {97 Bool => "boolean",98 Null => "null",99 Str => "string",100 Num => "number",101 Arr => "array",102 Obj => "object",103 Func => "function",104 }105 }106}107108impl Display for ValType {109 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {110 write!(f, "{}", self.name())111 }112}113114#[derive(Debug, Clone, PartialEq, Trace)]115#[trivially_drop]116pub enum ComplexValType {117 Any,118 Char,119 Simple(ValType),120 BoundedNumber(Option<f64>, Option<f64>),121 Array(Box<ComplexValType>),122 ArrayRef(&'static ComplexValType),123 ObjectRef(&'static [(&'static str, ComplexValType)]),124 Union(Vec<ComplexValType>),125 UnionRef(&'static [ComplexValType]),126 Sum(Vec<ComplexValType>),127 SumRef(&'static [ComplexValType]),128}129130impl From<ValType> for ComplexValType {131 fn from(s: ValType) -> Self {132 Self::Simple(s)133 }134}135136fn write_union(137 f: &mut std::fmt::Formatter<'_>,138 is_union: bool,139 union: &[ComplexValType],140) -> std::fmt::Result {141 for (i, v) in union.iter().enumerate() {142 let should_add_braces =143 matches!(v, ComplexValType::UnionRef(_) | ComplexValType::Union(_) if !is_union);144 if i != 0 {145 write!(f, " {} ", if is_union { '|' } else { '&' })?;146 }147 if should_add_braces {148 write!(f, "(")?;149 }150 write!(f, "{}", v)?;151 if should_add_braces {152 write!(f, ")")?;153 }154 }155 Ok(())156}157158fn print_array(a: &ComplexValType, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {159 if *a == ComplexValType::Any {160 write!(f, "array")?161 } else {162 write!(f, "Array<{}>", a)?163 }164 Ok(())165}166167impl Display for ComplexValType {168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {169 match self {170 ComplexValType::Any => write!(f, "any")?,171 ComplexValType::Simple(s) => write!(f, "{}", s)?,172 ComplexValType::Char => write!(f, "char")?,173 ComplexValType::BoundedNumber(a, b) => write!(174 f,175 "BoundedNumber<{}, {}>",176 a.map(|e| e.to_string()).unwrap_or_else(|| "".into()),177 b.map(|e| e.to_string()).unwrap_or_else(|| "".into())178 )?,179 ComplexValType::ArrayRef(a) => print_array(a, f)?,180 ComplexValType::Array(a) => print_array(a, f)?,181 ComplexValType::ObjectRef(fields) => {182 write!(f, "{{")?;183 for (i, (k, v)) in fields.iter().enumerate() {184 if i != 0 {185 write!(f, ", ")?;186 }187 write!(f, "{}: {}", k, v)?;188 }189 write!(f, "}}")?;190 }191 ComplexValType::Union(v) => write_union(f, true, v)?,192 ComplexValType::UnionRef(v) => write_union(f, true, v)?,193 ComplexValType::Sum(v) => write_union(f, false, v)?,194 ComplexValType::SumRef(v) => write_union(f, false, v)?,195 };196 Ok(())197 }198}199200peg::parser! {201pub grammar parser() for str {202 rule number() -> f64203 = n:$(['0'..='9']+) { n.parse().unwrap() }204205 rule any_ty() -> ComplexValType = "any" { ComplexValType::Any }206 rule char_ty() -> ComplexValType = "character" { ComplexValType::Char }207 rule bool_ty() -> ComplexValType = "boolean" { ComplexValType::Simple(ValType::Bool) }208 rule null_ty() -> ComplexValType = "null" { ComplexValType::Simple(ValType::Null) }209 rule str_ty() -> ComplexValType = "string" { ComplexValType::Simple(ValType::Str) }210 rule num_ty() -> ComplexValType = "number" { ComplexValType::Simple(ValType::Num) }211 rule simple_array_ty() -> ComplexValType = "array" { ComplexValType::Simple(ValType::Arr) }212 rule simple_object_ty() -> ComplexValType = "object" { ComplexValType::Simple(ValType::Obj) }213 rule simple_function_ty() -> ComplexValType = "function" { ComplexValType::Simple(ValType::Func) }214215 rule array_ty() -> ComplexValType216 = "Array<" t:ty() ">" { ComplexValType::Array(Box::new(t)) }217218 rule bounded_number_ty() -> ComplexValType219 = "BoundedNumber<" a:number() ", " b:number() ">" { ComplexValType::BoundedNumber(Some(a), Some(b)) }220221 rule ty_basic() -> ComplexValType222 = any_ty()223 / char_ty()224 / bool_ty()225 / null_ty()226 / str_ty()227 / num_ty()228 / simple_array_ty()229 / simple_object_ty()230 / simple_function_ty()231 / array_ty()232 / bounded_number_ty()233234 pub rule ty() -> ComplexValType235 = precedence! {236 a:(@) " | " b:@ {237 match a {238 ComplexValType::Union(mut a) => {239 a.push(b);240 ComplexValType::Union(a)241 }242 _ => ComplexValType::Union(vec![a, b]),243 }244 }245 --246 a:(@) " & " b:@ {247 match a {248 ComplexValType::Sum(mut a) => {249 a.push(b);250 ComplexValType::Sum(a)251 }252 _ => ComplexValType::Sum(vec![a, b]),253 }254 }255 --256 "(" t:ty() ")" { t }257 t:ty_basic() { t }258 }259}260}261262#[cfg(test)]263pub mod tests {264 use super::parser;265266 #[test]267 fn precedence() {268 assert_eq!(269 parser::ty("(any & any) | (any | any) & any")270 .unwrap()271 .to_string(),272 "any & any | (any | any) & any"273 );274 }275276 #[test]277 fn array() {278 assert_eq!(parser::ty("Array<any>").unwrap().to_string(), "array");279 assert_eq!(280 parser::ty("Array<number>").unwrap().to_string(),281 "Array<number>"282 );283 }284 #[test]285 fn bounded_number() {286 assert_eq!(287 parser::ty("BoundedNumber<1, 2>").unwrap().to_string(),288 "BoundedNumber<1, 2>"289 );290 }291}1#![allow(clippy::redundant_closure_call)]23use jrsonnet_gc::Trace;4use std::fmt::Display;56#[macro_export]7macro_rules! ty {8 ((Array<number>)) => {{9 $crate::ComplexValType::ArrayRef(&$crate::ComplexValType::Simple($crate::ValType::Num))10 }};11 ((Array<ubyte>)) => {{12 $crate::ComplexValType::ArrayRef(&$crate::ComplexValType::BoundedNumber(Some(0.0), Some(255.0)))13 }};14 (array) => {15 $crate::ComplexValType::Simple($crate::ValType::Arr)16 };17 (boolean) => {18 $crate::ComplexValType::Simple($crate::ValType::Bool)19 };20 (null) => {21 $crate::ComplexValType::Simple($crate::ValType::Null)22 };23 (string) => {24 $crate::ComplexValType::Simple($crate::ValType::Str)25 };26 (char) => {27 $crate::ComplexValType::Char28 };29 (number) => {30 $crate::ComplexValType::Simple($crate::ValType::Num)31 };32 (BoundedNumber<($min:expr), ($max:expr)>) => {{33 $crate::ComplexValType::BoundedNumber($min, $max)34 }};35 (object) => {36 $crate::ComplexValType::Simple($crate::ValType::Obj)37 };38 (any) => {39 $crate::ComplexValType::Any40 };41 (function) => {42 $crate::ComplexValType::Simple($crate::ValType::Func)43 };44 (($($a:tt) |+)) => {{45 static CONTENTS: &'static [$crate::ComplexValType] = &[46 $(ty!($a)),+47 ];48 $crate::ComplexValType::UnionRef(CONTENTS)49 }};50 (($($a:tt) &+)) => {{51 static CONTENTS: &'static [$crate::ComplexValType] = &[52 $(ty!($a)),+53 ];54 $crate::ComplexValType::SumRef(CONTENTS)55 }};56}5758#[test]59fn test() {60 assert_eq!(61 ty!((Array<number>)),62 ComplexValType::ArrayRef(&ComplexValType::Simple(ValType::Num))63 );64 assert_eq!(ty!(array), ComplexValType::Simple(ValType::Arr));65 assert_eq!(ty!(any), ComplexValType::Any);66 assert_eq!(67 ty!((string | number)),68 ComplexValType::UnionRef(&[69 ComplexValType::Simple(ValType::Str),70 ComplexValType::Simple(ValType::Num)71 ])72 );73 assert_eq!(74 format!("{}", ty!(((string & number) | (object & null)))),75 "string & number | object & null"76 );77 assert_eq!(format!("{}", ty!((string | array))), "string | array");78 assert_eq!(79 format!("{}", ty!(((string & number) | array))),80 "string & number | array"81 );82}8384#[derive(Debug, Clone, Copy, PartialEq, Eq, Trace)]85#[trivially_drop]86pub enum ValType {87 Bool,88 Null,89 Str,90 Num,91 Arr,92 Obj,93 Func,94}9596impl ValType {97 pub const fn name(&self) -> &'static str {98 use ValType::*;99 match self {100 Bool => "boolean",101 Null => "null",102 Str => "string",103 Num => "number",104 Arr => "array",105 Obj => "object",106 Func => "function",107 }108 }109}110111impl Display for ValType {112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {113 write!(f, "{}", self.name())114 }115}116117#[derive(Debug, Clone, PartialEq, Trace)]118#[trivially_drop]119pub enum ComplexValType {120 Any,121 Char,122 Simple(ValType),123 BoundedNumber(Option<f64>, Option<f64>),124 Array(Box<ComplexValType>),125 ArrayRef(&'static ComplexValType),126 ObjectRef(&'static [(&'static str, ComplexValType)]),127 Union(Vec<ComplexValType>),128 UnionRef(&'static [ComplexValType]),129 Sum(Vec<ComplexValType>),130 SumRef(&'static [ComplexValType]),131}132133impl From<ValType> for ComplexValType {134 fn from(s: ValType) -> Self {135 Self::Simple(s)136 }137}138139fn write_union(140 f: &mut std::fmt::Formatter<'_>,141 is_union: bool,142 union: &[ComplexValType],143) -> std::fmt::Result {144 for (i, v) in union.iter().enumerate() {145 let should_add_braces =146 matches!(v, ComplexValType::UnionRef(_) | ComplexValType::Union(_) if !is_union);147 if i != 0 {148 write!(f, " {} ", if is_union { '|' } else { '&' })?;149 }150 if should_add_braces {151 write!(f, "(")?;152 }153 write!(f, "{}", v)?;154 if should_add_braces {155 write!(f, ")")?;156 }157 }158 Ok(())159}160161fn print_array(a: &ComplexValType, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {162 if *a == ComplexValType::Any {163 write!(f, "array")?164 } else {165 write!(f, "Array<{}>", a)?166 }167 Ok(())168}169170impl Display for ComplexValType {171 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {172 match self {173 ComplexValType::Any => write!(f, "any")?,174 ComplexValType::Simple(s) => write!(f, "{}", s)?,175 ComplexValType::Char => write!(f, "char")?,176 ComplexValType::BoundedNumber(a, b) => write!(177 f,178 "BoundedNumber<{}, {}>",179 a.map(|e| e.to_string()).unwrap_or_else(|| "".into()),180 b.map(|e| e.to_string()).unwrap_or_else(|| "".into())181 )?,182 ComplexValType::ArrayRef(a) => print_array(a, f)?,183 ComplexValType::Array(a) => print_array(a, f)?,184 ComplexValType::ObjectRef(fields) => {185 write!(f, "{{")?;186 for (i, (k, v)) in fields.iter().enumerate() {187 if i != 0 {188 write!(f, ", ")?;189 }190 write!(f, "{}: {}", k, v)?;191 }192 write!(f, "}}")?;193 }194 ComplexValType::Union(v) => write_union(f, true, v)?,195 ComplexValType::UnionRef(v) => write_union(f, true, v)?,196 ComplexValType::Sum(v) => write_union(f, false, v)?,197 ComplexValType::SumRef(v) => write_union(f, false, v)?,198 };199 Ok(())200 }201}202203peg::parser! {204pub grammar parser() for str {205 rule number() -> f64206 = n:$(['0'..='9']+) { n.parse().unwrap() }207208 rule any_ty() -> ComplexValType = "any" { ComplexValType::Any }209 rule char_ty() -> ComplexValType = "character" { ComplexValType::Char }210 rule bool_ty() -> ComplexValType = "boolean" { ComplexValType::Simple(ValType::Bool) }211 rule null_ty() -> ComplexValType = "null" { ComplexValType::Simple(ValType::Null) }212 rule str_ty() -> ComplexValType = "string" { ComplexValType::Simple(ValType::Str) }213 rule num_ty() -> ComplexValType = "number" { ComplexValType::Simple(ValType::Num) }214 rule simple_array_ty() -> ComplexValType = "array" { ComplexValType::Simple(ValType::Arr) }215 rule simple_object_ty() -> ComplexValType = "object" { ComplexValType::Simple(ValType::Obj) }216 rule simple_function_ty() -> ComplexValType = "function" { ComplexValType::Simple(ValType::Func) }217218 rule array_ty() -> ComplexValType219 = "Array<" t:ty() ">" { ComplexValType::Array(Box::new(t)) }220221 rule bounded_number_ty() -> ComplexValType222 = "BoundedNumber<" a:number() ", " b:number() ">" { ComplexValType::BoundedNumber(Some(a), Some(b)) }223224 rule ty_basic() -> ComplexValType225 = any_ty()226 / char_ty()227 / bool_ty()228 / null_ty()229 / str_ty()230 / num_ty()231 / simple_array_ty()232 / simple_object_ty()233 / simple_function_ty()234 / array_ty()235 / bounded_number_ty()236237 pub rule ty() -> ComplexValType238 = precedence! {239 a:(@) " | " b:@ {240 match a {241 ComplexValType::Union(mut a) => {242 a.push(b);243 ComplexValType::Union(a)244 }245 _ => ComplexValType::Union(vec![a, b]),246 }247 }248 --249 a:(@) " & " b:@ {250 match a {251 ComplexValType::Sum(mut a) => {252 a.push(b);253 ComplexValType::Sum(a)254 }255 _ => ComplexValType::Sum(vec![a, b]),256 }257 }258 --259 "(" t:ty() ")" { t }260 t:ty_basic() { t }261 }262}263}264265#[cfg(test)]266pub mod tests {267 use super::parser;268269 #[test]270 fn precedence() {271 assert_eq!(272 parser::ty("(any & any) | (any | any) & any")273 .unwrap()274 .to_string(),275 "any & any | (any | any) & any"276 );277 }278279 #[test]280 fn array() {281 assert_eq!(parser::ty("Array<any>").unwrap().to_string(), "array");282 assert_eq!(283 parser::ty("Array<number>").unwrap().to_string(),284 "Array<number>"285 );286 }287 #[test]288 fn bounded_number() {289 assert_eq!(290 parser::ty("BoundedNumber<1, 2>").unwrap().to_string(),291 "BoundedNumber<1, 2>"292 );293 }294}