// Portions adapted from google/go-jsonnet v0.21.0 (Apache-2.0).
// https://github.com/google/go-jsonnet/tree/67968688d9952f50662e979fab1bef889d0d3e57
// Source: internal/formatter/enforce_string_style.go
// Source: internal/parser/string_util.go
// Copyright 2019 Google Inc. All rights reserved.
// Copyright 2016 Google Inc. All rights reserved.
// Modifications: Ported string-style conversion to local source tokens and MoonBit strings.
// License and retained attribution: LICENSE and NOTICE at the module root.
// String style and escaping follow the pinned Go formatter/parser.
// Copyright Google Inc.; Apache-2.0; see NOTICE.
///|
fn FormatOutput::write_block(
self : FormatOutput,
token : Token,
indent : Int,
base : Int,
) -> Unit raise JsonnetError {
if indent <= 0 {
for c in token.raw.to_array() {
if c != '\r' {
self.write(c.to_string())
}
}
return
}
guard token.value is Some(String(value)) else {
self.write(token.raw)
return
}
if indent > self.limits.output_bytes ||
base > self.limits.output_bytes - indent {
raise problem(Limit, token.loc, "format output byte limit exceeded")
}
let characters = value.to_array()
let chomp = !value.has_suffix("\n")
self.write(if chomp { "|||-\n" } else { "|||\n" })
if characters.get(0) != Some('\n') {
self.indent(base + indent)
}
for i, c in characters {
if c == '\r' {
continue
}
self.write(c.to_string())
if c == '\n' && i + 1 < characters.length() && characters[i + 1] != '\n' {
self.indent(base + indent)
}
}
if chomp {
self.write("\n")
}
self.indent(base)
self.write("|||")
}
///|
fn format_string(
token : Token,
style : FormatStringStyle,
) -> String raise JsonnetError {
if style == PreserveQuotes ||
token.text != "" ||
token.raw.has_prefix("@") {
return token.raw
}
guard token.literal_kind() is Literal(String(value)) else { return token.raw }
let single = value.contains("'")
let double = value.contains("\"")
if single && double {
return token.raw
}
let use_single = if single {
false
} else if double {
true
} else {
style == SingleQuotes
}
let quote = if use_single { '\'' } else { '"' }
let out = StringBuilder()
out.write_char(quote)
for c in value.to_array() {
match c {
'\\' => out.write_string("\\\\")
'\n' => out.write_string("\\n")
'\r' => out.write_string("\\r")
'\t' => out.write_string("\\t")
'\u{8}' => out.write_string("\\b")
'\u{c}' => out.write_string("\\f")
_ => {
let code = c.to_int()
if c == quote {
out.write_char('\\')
}
if code < 32 || (code >= 127 && code <= 159) {
let hex = "0123456789abcdef"
out.write_string("\\u00")
out.write_char(hex[(code >> 4) & 15].to_char().unwrap())
out.write_char(hex[code & 15].to_char().unwrap())
} else {
out.write_char(c)
}
}
}
}
out.write_char(quote)
out.to_string()
}
///|
fn format_comment(
raw : String,
style : FormatCommentStyle,
first : Bool,
) -> String {
if style == HashComments && raw.has_prefix("//") {
"#" + raw[2:].to_owned()
} else if style == SlashComments &&
raw.has_prefix("#") &&
!(first && raw.has_prefix("#!")) {
"//" + raw[1:].to_owned()
} else {
raw
}
}