///|
fn step_quote(text : String) -> String {
let output = StringBuilder()
output.write_char('\'')
for character in text {
if character == '\'' {
output.write_char('\'')
output.write_char('\'')
} else {
output.write_char(character)
}
}
output.write_char('\'')
output.to_string()
}
///|
fn step_optional_string(value : String?) -> String {
match value {
Some(text) => step_quote(text)
None => "$".to_string()
}
}
///|
fn step_string_list(values : Array[String]) -> String {
"(" + values.map(step_quote).join(",") + ")"
}
///|
fn render_value(value : Value) -> String {
match value {
Null => "$".to_string()
Omitted => "*".to_string()
Integer(number) => number.to_string()
Real(number) => number.to_string()
String(text) => step_quote(text)
Enumeration(text) => "." + text + "."
Reference(id) => "#" + id.to_string()
Binary(text) => "\"" + text + "\""
Typed(name~, value~) => name + "(" + render_value(value) + ")"
List(values) => "(" + values.map(render_value).join(",") + ")"
}
}
///|
pub fn Value::to_step_lossless(self : Value) -> String {
render_value(self)
}
///|
fn render_entity(entity : Entity) -> String {
"#" +
entity.id.to_string() +
"=" +
entity.name +
"(" +
entity.arguments.map(render_value).join(",") +
");"
}
///|
fn render_header(header : Header) -> String {
let output = StringBuilder()
output <+ "HEADER;\n"
let description = "FILE_DESCRIPTION(" +
step_string_list(header.description) +
",'2;1');\n"
output <+ "\{description}"
let file_name = "FILE_NAME(" +
step_optional_string(header.file_name) +
"," +
step_optional_string(header.time_stamp) +
"," +
step_string_list(header.authors) +
"," +
step_string_list(header.organizations) +
"," +
step_optional_string(header.preprocessor_version) +
"," +
step_optional_string(header.originating_system) +
"," +
step_optional_string(header.authorization) +
");\n"
output <+ "\{file_name}"
let schema = "FILE_SCHEMA(" +
step_string_list(header.schema_identifiers) +
");\n"
output <+ "\{schema}"
output <+ "ENDSEC;\n"
output.to_string()
}
///|
/// Serialize the generic model back to a valid ISO 10303-21 document.
pub fn Model::to_step(self : Model) -> String {
let output = StringBuilder()
output <+ "ISO-10303-21;\n"
let header = render_header(self.header)
output <+ "\{header}"
output <+ "DATA;\n"
for entity in self.entities {
let rendered = render_entity(entity)
output <+ "\{rendered}\n"
}
output <+ "ENDSEC;\nEND-ISO-10303-21;\n"
output.to_string()
}
///|
pub fn serialize(model : Model) -> String {
model.to_step()
}
///|
pub fn round_trip(source : String) -> Model raise ParseError {
let model = parse(source)
parse(model.to_step())
}
///|
pub fn step_statistics(source : String) -> StepDocumentStats {
let mut line_count = 1
let mut string_count = 0
let mut comment_count = 0
let mut in_string = false
let mut in_comment = false
for character in source {
if character == '\n' {
line_count += 1
in_comment = false
}
if in_comment {
continue
}
if character == '/' && !in_string {
in_comment = true
comment_count += 1
} else if character == '\'' {
if !in_string {
in_string = true
string_count += 1
} else {
in_string = false
}
}
}
let model = try! parse(source)
let index = model.index()
{
byte_length: source.length(),
line_count,
entity_count: model.entity_count(),
reference_count: graph_stats(index).reference_count,
string_count,
comment_count,
}
}