git.delta.rocks / jrsonnet / refs/commits / d44593872785

difftreelog

refactor(evaluator) extract json to module

Lach2020-08-15parent: #219ced5.patch.diff
in: master

4 files changed

addedcrates/jrsonnet-evaluator/src/builtin/manifest.rsdiffbeforeafterboth
--- /dev/null
+++ b/crates/jrsonnet-evaluator/src/builtin/manifest.rs
@@ -0,0 +1,150 @@
+use crate::error::Error::*;
+use crate::error::Result;
+use crate::{throw, Val};
+
+#[derive(PartialEq)]
+pub enum ManifestType {
+	// Applied in manifestification
+	Manifest,
+	/// Used for std.manifestJson
+	/// Empty array/objects extends to "[\n\n]" instead of "[ ]" as in manifest
+	Std,
+	// No line breaks, used in `obj+''`
+	ToString,
+}
+
+pub struct ManifestJsonOptions<'s> {
+	pub padding: &'s str,
+	pub mtype: ManifestType,
+}
+
+pub(crate) fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {
+	let mut out = String::new();
+	manifest_json_ex_buf(val, &mut out, &mut String::new(), options)?;
+	Ok(out)
+}
+fn manifest_json_ex_buf(
+	val: &Val,
+	buf: &mut String,
+	cur_padding: &mut String,
+	options: &ManifestJsonOptions<'_>,
+) -> Result<()> {
+	use std::fmt::Write;
+	match val.unwrap_if_lazy()? {
+		Val::Bool(v) => {
+			if v {
+				buf.push_str("true");
+			} else {
+				buf.push_str("false");
+			}
+		}
+		Val::Null => buf.push_str("null"),
+		Val::Str(s) => buf.push_str(&escape_string_json(&s)),
+		Val::Num(n) => write!(buf, "{}", n).unwrap(),
+		Val::Arr(items) => {
+			buf.push('[');
+			if !items.is_empty() {
+				if options.mtype != ManifestType::ToString {
+					buf.push('\n');
+				}
+
+				let old_len = cur_padding.len();
+				cur_padding.push_str(options.padding);
+				for (i, item) in items.iter().enumerate() {
+					if i != 0 {
+						buf.push(',');
+						if options.mtype == ManifestType::ToString {
+							buf.push(' ');
+						} else {
+							buf.push('\n');
+						}
+					}
+					buf.push_str(cur_padding);
+					manifest_json_ex_buf(item, buf, cur_padding, options)?;
+				}
+				cur_padding.truncate(old_len);
+
+				if options.mtype != ManifestType::ToString {
+					buf.push('\n');
+					buf.push_str(cur_padding);
+				}
+			} else if options.mtype == ManifestType::Std {
+				buf.push_str("\n\n");
+				buf.push_str(cur_padding);
+			} else if options.mtype == ManifestType::ToString {
+				buf.push(' ');
+			}
+			buf.push(']');
+		}
+		Val::Obj(obj) => {
+			buf.push('{');
+			let fields = obj.visible_fields();
+			if !fields.is_empty() {
+				if options.mtype != ManifestType::ToString {
+					buf.push('\n');
+				}
+
+				let old_len = cur_padding.len();
+				cur_padding.push_str(options.padding);
+				for (i, field) in fields.into_iter().enumerate() {
+					if i != 0 {
+						buf.push(',');
+						if options.mtype == ManifestType::ToString {
+							buf.push(' ');
+						} else {
+							buf.push('\n');
+						}
+					}
+					buf.push_str(cur_padding);
+					buf.push_str(&escape_string_json(&field));
+					buf.push_str(": ");
+					manifest_json_ex_buf(&obj.get(field)?.unwrap(), buf, cur_padding, options)?;
+				}
+				cur_padding.truncate(old_len);
+
+				if options.mtype != ManifestType::ToString {
+					buf.push('\n');
+					buf.push_str(cur_padding);
+				}
+			} else if options.mtype == ManifestType::Std {
+				buf.push_str("\n\n");
+				buf.push_str(cur_padding);
+			} else if options.mtype == ManifestType::ToString {
+				buf.push(' ');
+			}
+			buf.push('}');
+		}
+		Val::Func(_) | Val::Intristic(_, _) => {
+			throw!(RuntimeError("tried to manifest function".into()))
+		}
+		Val::Lazy(_) => unreachable!(),
+	};
+	Ok(())
+}
+pub fn escape_string_json(s: &str) -> String {
+	use std::fmt::Write;
+	let mut out = String::new();
+	out.push('"');
+	for c in s.chars() {
+		match c {
+			'"' => out.push_str("\\\""),
+			'\\' => out.push_str("\\\\"),
+			'\u{0008}' => out.push_str("\\b"),
+			'\u{000c}' => out.push_str("\\f"),
+			'\n' => out.push_str("\\n"),
+			'\r' => out.push_str("\\r"),
+			'\t' => out.push_str("\\t"),
+			c if c < 32 as char || (c >= 127 as char && c <= 159 as char) => {
+				write!(out, "\\u{:04x}", c as u32).unwrap()
+			}
+			c => out.push(c),
+		}
+	}
+	out.push('"');
+	out
+}
+
+#[test]
+fn json_test() {
+	assert_eq!(escape_string_json("\u{001f}"), "\"\\u001f\"")
+}
modifiedcrates/jrsonnet-evaluator/src/builtin/mod.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/builtin/mod.rs
+++ b/crates/jrsonnet-evaluator/src/builtin/mod.rs
@@ -2,3 +2,4 @@
 pub use stdlib::*;
 
 pub mod format;
+pub mod manifest;
modifiedcrates/jrsonnet-evaluator/src/evaluate.rsdiffbeforeafterboth
--- a/crates/jrsonnet-evaluator/src/evaluate.rs
+++ b/crates/jrsonnet-evaluator/src/evaluate.rs
@@ -1,12 +1,13 @@
 use crate::{
-	builtin::format::{format_arr, format_obj},
+	builtin::{
+		format::{format_arr, format_obj},
+		manifest::{escape_string_json, manifest_json_ex, ManifestJsonOptions, ManifestType},
+	},
 	context_creator, equals,
 	error::Error::*,
-	escape_string_json, future_wrapper, lazy_val, manifest_json_ex, parse_args, primitive_equals,
-	push, throw,
-	val::ManifestJsonOptions,
-	with_state, Context, ContextCreator, FuncDesc, LazyBinding, LazyVal, LocError, ManifestType,
-	ObjMember, ObjValue, Result, Val, ValType,
+	future_wrapper, lazy_val, parse_args, primitive_equals, push, throw, with_state, Context,
+	ContextCreator, FuncDesc, LazyBinding, LazyVal, LocError, ObjMember, ObjValue, Result, Val,
+	ValType,
 };
 use closure::closure;
 use jrsonnet_parser::{
modifiedcrates/jrsonnet-evaluator/src/val.rsdiffbeforeafterboth
1use crate::{1use crate::{
2 builtin::manifest::{manifest_json_ex, ManifestJsonOptions, ManifestType},
2 error::Error::*,3 error::Error::*,
3 evaluate,4 evaluate,
4 function::{parse_function_call, parse_function_call_map, place_args},5 function::{parse_function_call, parse_function_call_map, place_args},
354 }355 }
355}356}
356
357#[derive(PartialEq)]
358pub enum ManifestType {
359 // Applied in manifestification
360 Manifest,
361 /// Used for std.manifestJson
362 /// Empty array/objects extends to "[\n\n]" instead of "[ ]" as in manifest
363 Std,
364 // No line breaks, used in `obj+''`
365 ToString,
366}
367
368pub struct ManifestJsonOptions<'s> {
369 pub padding: &'s str,
370 pub mtype: ManifestType,
371}
372
373pub fn manifest_json_ex(val: &Val, options: &ManifestJsonOptions<'_>) -> Result<String> {
374 let mut out = String::new();
375 manifest_json_ex_buf(val, &mut out, &mut String::new(), options)?;
376 Ok(out)
377}
378fn manifest_json_ex_buf(
379 val: &Val,
380 buf: &mut String,
381 cur_padding: &mut String,
382 options: &ManifestJsonOptions<'_>,
383) -> Result<()> {
384 use std::fmt::Write;
385 match val.unwrap_if_lazy()? {
386 Val::Bool(v) => {
387 if v {
388 buf.push_str("true");
389 } else {
390 buf.push_str("false");
391 }
392 }
393 Val::Null => buf.push_str("null"),
394 Val::Str(s) => buf.push_str(&escape_string_json(&s)),
395 Val::Num(n) => write!(buf, "{}", n).unwrap(),
396 Val::Arr(items) => {
397 buf.push('[');
398 if !items.is_empty() {
399 if options.mtype != ManifestType::ToString {
400 buf.push('\n');
401 }
402
403 let old_len = cur_padding.len();
404 cur_padding.push_str(options.padding);
405 for (i, item) in items.iter().enumerate() {
406 if i != 0 {
407 buf.push(',');
408 if options.mtype == ManifestType::ToString {
409 buf.push(' ');
410 } else {
411 buf.push('\n');
412 }
413 }
414 buf.push_str(cur_padding);
415 manifest_json_ex_buf(item, buf, cur_padding, options)?;
416 }
417 cur_padding.truncate(old_len);
418
419 if options.mtype != ManifestType::ToString {
420 buf.push('\n');
421 buf.push_str(cur_padding);
422 }
423 } else if options.mtype == ManifestType::Std {
424 buf.push_str("\n\n");
425 buf.push_str(cur_padding);
426 } else if options.mtype == ManifestType::ToString {
427 buf.push(' ');
428 }
429 buf.push(']');
430 }
431 Val::Obj(obj) => {
432 buf.push('{');
433 let fields = obj.visible_fields();
434 if !fields.is_empty() {
435 if options.mtype != ManifestType::ToString {
436 buf.push('\n');
437 }
438
439 let old_len = cur_padding.len();
440 cur_padding.push_str(options.padding);
441 for (i, field) in fields.into_iter().enumerate() {
442 if i != 0 {
443 buf.push(',');
444 if options.mtype == ManifestType::ToString {
445 buf.push(' ');
446 } else {
447 buf.push('\n');
448 }
449 }
450 buf.push_str(cur_padding);
451 buf.push_str(&escape_string_json(&field));
452 buf.push_str(": ");
453 manifest_json_ex_buf(&obj.get(field)?.unwrap(), buf, cur_padding, options)?;
454 }
455 cur_padding.truncate(old_len);
456
457 if options.mtype != ManifestType::ToString {
458 buf.push('\n');
459 buf.push_str(cur_padding);
460 }
461 } else if options.mtype == ManifestType::Std {
462 buf.push_str("\n\n");
463 buf.push_str(cur_padding);
464 } else if options.mtype == ManifestType::ToString {
465 buf.push(' ');
466 }
467 buf.push('}');
468 }
469 Val::Func(_) | Val::Intristic(_, _) => {
470 throw!(RuntimeError("tried to manifest function".into()))
471 }
472 Val::Lazy(_) => unreachable!(),
473 };
474 Ok(())
475}
476pub fn escape_string_json(s: &str) -> String {
477 use std::fmt::Write;
478 let mut out = String::new();
479 out.push('"');
480 for c in s.chars() {
481 match c {
482 '"' => out.push_str("\\\""),
483 '\\' => out.push_str("\\\\"),
484 '\u{0008}' => out.push_str("\\b"),
485 '\u{000c}' => out.push_str("\\f"),
486 '\n' => out.push_str("\\n"),
487 '\r' => out.push_str("\\r"),
488 '\t' => out.push_str("\\t"),
489 c if c < 32 as char || (c >= 127 as char && c <= 159 as char) => {
490 write!(out, "\\u{:04x}", c as u32).unwrap()
491 }
492 c => out.push(c),
493 }
494 }
495 out.push('"');
496 out
497}
498
499#[test]
500fn json_test() {
501 assert_eq!(escape_string_json("\u{001f}"), "\"\\u001f\"")
502}
503357