///|
fn quote_sieve(text : String) -> String {
let out = StringBuilder()
out.write_char('"')
for c in text {
if c == '"' || c == '\\' {
out.write_char('\\')
}
out.write_char(c)
}
out.write_char('"')
out.to_string()
}
///|
fn format_argument(arg : Argument) -> String {
match arg {
Flag(name) => ":" + name
Literal(value) => quote_sieve(value)
Quantity(n) => n.to_string()
Strings(values) => {
let out = StringBuilder()
out.write_char('[')
for i = 0; i < values.length(); i = i + 1 {
if i > 0 {
out.write_string(", ")
}
out.write_string(quote_sieve(values[i]))
}
out.write_char(']')
out.to_string()
}
}
}
///|
fn write_arguments(out : StringBuilder, args : Array[Argument]) -> Unit {
for arg in args {
out.write_char(' ')
out.write_string(format_argument(arg))
}
}
///|
fn write_test(out : StringBuilder, expr : Test) -> Unit {
match expr {
Call(name, args, _) => {
out.write_string(name)
write_arguments(out, args)
}
Not(child, _) => {
out.write_string("not ")
write_test(out, child)
}
AnyOf(children, _) => write_test_list(out, "anyof", children)
AllOf(children, _) => write_test_list(out, "allof", children)
}
}
///|
fn write_test_list(
out : StringBuilder,
name : String,
children : Array[Test],
) -> Unit {
out.write_string(name)
out.write_char('(')
for i = 0; i < children.length(); i = i + 1 {
if i > 0 {
out.write_string(", ")
}
write_test(out, children[i])
}
out.write_char(')')
}
///|
fn indentation(out : StringBuilder, depth : Int) -> Unit {
for i = 0; i < depth; i = i + 1 {
out.write_string(" ")
}
}
///|
fn write_statements(
out : StringBuilder,
statements : Array[Statement],
depth : Int,
) -> Unit {
for statement in statements {
indentation(out, depth)
match statement {
Command(name, args, _) => {
out.write_string(name)
write_arguments(out, args)
out.write_string(";\n")
}
Branch(branches, otherwise, _) => {
for i = 0; i < branches.length(); i = i + 1 {
if i == 0 {
out.write_string("if ")
} else {
out.write_string(" elsif ")
}
write_test(out, branches[i].condition)
out.write_string(" {\n")
write_statements(out, branches[i].body, depth + 1)
indentation(out, depth)
out.write_char('}')
}
if !otherwise.is_empty() {
out.write_string(" else {\n")
write_statements(out, otherwise, depth + 1)
indentation(out, depth)
out.write_char('}')
}
out.write_char('\n')
}
}
}
}
///|
pub fn format_script(
source : String,
limits? : Limits = Limits::default(),
) -> String raise SieveError {
let syntax = parse(source, limits~)
let out = StringBuilder()
write_statements(out, syntax.statements, 0)
out.to_string()
}
///|
pub fn Program::canonical_source(self : Program) -> String {
let out = StringBuilder()
write_statements(out, self.syntax.statements, 0)
out.to_string()
}