git.delta.rocks / jrsonnet / refs/commits / 382458604ca4

difftreelog

Merge pull request #89 from CertainLach/parse-intrinsics

Yaroslav Bolyukin2022-11-23parents: #15d127a #1e1f97c.patch.diff
in: master

2 files changed

modifiedcrates/jrsonnet-stdlib/src/lib.rsdiffbeforeafterboth
128 ("asciiUpper", builtin_ascii_upper::INST),128 ("asciiUpper", builtin_ascii_upper::INST),
129 ("asciiLower", builtin_ascii_lower::INST),129 ("asciiLower", builtin_ascii_lower::INST),
130 ("findSubstr", builtin_find_substr::INST),130 ("findSubstr", builtin_find_substr::INST),
131 ("parseInt", builtin_parse_int::INST),
132 ("parseOctal", builtin_parse_octal::INST),
133 ("parseHex", builtin_parse_hex::INST),
131 // Misc134 // Misc
132 ("length", builtin_length::INST),135 ("length", builtin_length::INST),
133 ("startsWith", builtin_starts_with::INST),136 ("startsWith", builtin_starts_with::INST),
312 out.build()315 out.build()
313 }316 }
314 #[cfg(feature = "legacy-this-file")]317 #[cfg(feature = "legacy-this-file")]
315 fn initialize(&self, s: State, source: Source) -> jrsonnet_evaluator::Context {318 fn initialize(&self, s: State, source: Source) -> Context {
316 let mut builder = ObjValueBuilder::new();319 let mut builder = ObjValueBuilder::new();
317 builder.with_super(self.stdlib_obj.clone());320 builder.with_super(self.stdlib_obj.clone());
318 builder321 builder
modifiedcrates/jrsonnet-stdlib/src/strings.rsdiffbeforeafterboth
1use jrsonnet_evaluator::{1use jrsonnet_evaluator::{
2 error::{ErrorKind::*, Result},2 error::{ErrorKind::*, Result},
3 function::builtin,3 function::builtin,
4 throw,
4 typed::{Either2, VecVal, M1},5 typed::{Either2, VecVal, M1},
5 val::ArrValue,6 val::ArrValue,
6 Either, IStr, Val,7 Either, IStr, Val,
74 Ok(out.into())75 Ok(out.into())
75}76}
77
78#[builtin]
79pub fn builtin_parse_int(raw: IStr) -> Result<f64> {
80 if let Some(raw) = raw.strip_prefix('-') {
81 if raw.is_empty() {
82 throw!("integer only consists of a minus")
83 }
84
85 parse_nat::<10>(raw).map(|value| -value)
86 } else {
87 if raw.is_empty() {
88 throw!("empty integer")
89 }
90
91 parse_nat::<10>(raw.as_str())
92 }
93}
94
95#[builtin]
96pub fn builtin_parse_octal(raw: IStr) -> Result<f64> {
97 if raw.is_empty() {
98 throw!("empty octal integer");
99 }
100
101 parse_nat::<8>(raw.as_str())
102}
103
104#[builtin]
105pub fn builtin_parse_hex(raw: IStr) -> Result<f64> {
106 if raw.is_empty() {
107 throw!("empty hexadecimal integer");
108 }
109
110 parse_nat::<16>(raw.as_str())
111}
112
113fn parse_nat<const BASE: u32>(raw: &str) -> Result<f64> {
114 debug_assert!(
115 1 <= BASE && BASE <= 16,
116 "integer base should be between 1 and 16"
117 );
118
119 const ZERO_CODE: u32 = '0' as u32;
120 const UPPER_A_CODE: u32 = 'A' as u32;
121 const LOWER_A_CODE: u32 = 'a' as u32;
122
123 #[inline]
124 fn checked_sub_if(condition: bool, lhs: u32, rhs: u32) -> Option<u32> {
125 if condition {
126 lhs.checked_sub(rhs)
127 } else {
128 None
129 }
130 }
131
132 let base = BASE as f64;
133
134 raw.chars().try_fold(0f64, |aggregate, digit| {
135 let digit = digit as u32;
136 let digit = if let Some(digit) = checked_sub_if(BASE > 10, digit, LOWER_A_CODE) {
137 digit + 10
138 } else if let Some(digit) = checked_sub_if(BASE > 10, digit, UPPER_A_CODE) {
139 digit + 10
140 } else {
141 digit.checked_sub(ZERO_CODE).unwrap_or(BASE)
142 };
143
144 if digit < BASE {
145 Ok(base * aggregate + digit as f64)
146 } else {
147 throw!("{raw:?} is not a base {BASE} integer",);
148 }
149 })
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn parse_nat_base_8() {
158 assert_eq!(parse_nat::<8>("0").unwrap(), 0.);
159 assert_eq!(parse_nat::<8>("5").unwrap(), 5.);
160 assert_eq!(parse_nat::<8>("32").unwrap(), 0o32 as f64);
161 assert_eq!(parse_nat::<8>("761").unwrap(), 0o761 as f64);
162 }
163
164 #[test]
165 fn parse_nat_base_10() {
166 assert_eq!(parse_nat::<10>("0").unwrap(), 0.);
167 assert_eq!(parse_nat::<10>("3").unwrap(), 3.);
168 assert_eq!(parse_nat::<10>("27").unwrap(), 27.);
169 assert_eq!(parse_nat::<10>("123").unwrap(), 123.);
170 }
171
172 #[test]
173 fn parse_nat_base_16() {
174 assert_eq!(parse_nat::<16>("0").unwrap(), 0.);
175 assert_eq!(parse_nat::<16>("A").unwrap(), 10.);
176 assert_eq!(parse_nat::<16>("a9").unwrap(), 0xA9 as f64);
177 assert_eq!(parse_nat::<16>("BbC").unwrap(), 0xBBC as f64);
178 }
179}
76180