///|
pub fn program_to_json(program : Program) -> Json {
{
"schema_version": 1,
"patterns": Json::array(program.patterns.map(pattern_to_json)),
"limits": limits_to_json(program.limits),
"projections": Json::array(program.projections.map(projection_to_json)),
}
}
///|
pub fn program_from_json(value : Json) -> Program raise CepError {
let object = codec_object(value, "program")
codec_keys(
object,
["schema_version", "patterns", "limits", "projections"],
"program",
)
if codec_int32(
codec_required(object, "schema_version", "program"),
"program.schema_version",
) !=
1 {
raise Invalid(
path="program.schema_version",
reason="only version 1 is supported",
)
}
let entries = codec_array(
codec_required(object, "patterns", "program"),
"program.patterns",
)
if entries.length() > 64 {
raise Resource(resource="patterns", limit=64)
}
let patterns = entries.map(pattern_from_json)
let limits = limits_from_json(codec_required(object, "limits", "program"))
let projection_json = codec_array(
codec_required(object, "projections", "program"),
"program.projections",
)
if projection_json.length() > 64 {
raise Resource(resource="projections", limit=64)
}
let plans : Array[ProjectionPlan] = []
for item in projection_json {
let target = codec_text_property(
codec_object(item, "projection"),
"pattern",
"projection",
)
let mut pattern : Pattern? = None
for candidate in patterns {
if candidate.id == target {
pattern = Some(candidate)
}
}
match pattern {
Some(pattern) => plans.push(projection_from_json(pattern, item))
None =>
raise Invalid(
path="projection.pattern",
reason="unknown pattern \{target}",
)
}
}
Program::new(patterns, limits~, projections=plans)
}
///|
pub fn parse_program(text : String) -> Program raise CepError {
program_from_json(codec_parse(text, max_depth=128))
}
///|
pub fn format_program(program : Program) -> String raise CepError {
codec_bounded_format(program_to_json(program))
}
///|
pub fn Program::describe(self : Program) -> Json {
{
"limits": limits_to_json(self.limits),
"patterns": Json::array(
self.patterns.map(pattern => {
let analysis = pattern.analysis()
{
"id": Json::string(pattern.id),
"within": Json::string(pattern.within.to_string()),
"stages": Json::number(pattern.stages.length().to_double()),
"minimum_captures": Json::number(
analysis.minimum_captures.to_double(),
),
"maximum_captures": Json::number(
analysis.maximum_captures.to_double(),
),
"nullable_stages": Json::number(analysis.nullable_stages.to_double()),
"has_absence": Json::boolean(analysis.has_absence),
"branching": Json::string(
match analysis.branching_risk {
FixedSequence => "fixed_sequence"
BoundedRepetition => "bounded_repetition"
CombinatorialSelection => "combinatorial_selection"
},
),
}
}),
),
"projection_count": Json::number(self.projections.length().to_double()),
}
}