///|
fn codec_stage_to_json(stage : Stage) -> Json {
let object : Map[String, Json] = Map([
("name", Json::string(stage.name)),
("condition", codec_condition_to_json(stage.condition)),
("min", Json::number(stage.min.to_double())),
("max", Json::number(stage.max.to_double())),
(
"contiguity",
Json::string(
match stage.contiguity {
Strict => "strict"
SkipNext => "skip_next"
SkipAny => "skip_any"
},
),
),
])
if stage.forbidden is Some(condition) {
object.set("forbidden", codec_condition_to_json(condition))
}
Json::object(object)
}
///|
fn codec_stage_from_json(value : Json, path : String) -> Stage raise CepError {
let object = codec_object(value, path)
codec_keys(
object,
["name", "condition", "min", "max", "contiguity", "forbidden"],
path,
)
let name = codec_text_property(object, "name", path)
let condition = codec_condition_from_json(
codec_required(object, "condition", path),
"\{path}.condition",
)
let min = codec_int32(codec_required(object, "min", path), "\{path}.min")
let max = codec_int32(codec_required(object, "max", path), "\{path}.max")
let contiguity = match codec_text_property(object, "contiguity", path) {
"strict" => Strict
"skip_next" => SkipNext
"skip_any" => SkipAny
_ => raise Invalid(path="\{path}.contiguity", reason="unknown contiguity")
}
let forbidden = object
.get("forbidden")
.map(value => codec_condition_from_json(value, "\{path}.forbidden"))
Stage::new(name, condition, min~, max~, contiguity~, forbidden?)
}
///|
pub fn pattern_to_json(pattern : Pattern) -> Json {
let object : Map[String, Json] = Map([
("schema_version", Json::number(1.0)),
("id", Json::string(pattern.id)),
("within", Json::string(pattern.within.to_string())),
(
"after_match",
Json::string(
match pattern.after_match {
NoSkip => "no_skip"
SkipToNextStart => "skip_to_next_start"
SkipPastLast => "skip_past_last"
},
),
),
("stages", Json::array(pattern.stages.map(codec_stage_to_json))),
])
if pattern.absence is Some(condition) {
object.set("absence", codec_condition_to_json(condition))
}
Json::object(object)
}
///|
pub fn pattern_from_json(value : Json) -> Pattern raise CepError {
let path = "pattern"
let object = codec_object(value, path)
codec_keys(
object,
["schema_version", "id", "within", "after_match", "stages", "absence"],
path,
)
if codec_int32(
codec_required(object, "schema_version", path),
"pattern.schema_version",
) !=
1 {
raise Invalid(
path="pattern.schema_version",
reason="only version 1 is supported",
)
}
let id = codec_text_property(object, "id", path)
let within = codec_int64(
codec_required(object, "within", path),
"pattern.within",
)
let after_match = match codec_text_property(object, "after_match", path) {
"no_skip" => NoSkip
"skip_to_next_start" => SkipToNextStart
"skip_past_last" => SkipPastLast
_ =>
raise Invalid(
path="pattern.after_match",
reason="unknown match selection policy",
)
}
let items = codec_array(
codec_required(object, "stages", path),
"pattern.stages",
)
if items.length() > 32 {
raise Resource(resource="pattern stages", limit=32)
}
let stages = []
for index, item in items {
stages.push(codec_stage_from_json(item, "pattern.stages[\{index}]"))
}
let absence = object
.get("absence")
.map(value => codec_condition_from_json(value, "pattern.absence"))
Pattern::new(id, stages, within, after_match~, absence?)
}
///|
pub fn parse_pattern(text : String) -> Pattern raise CepError {
pattern_from_json(codec_parse(text, max_depth=128))
}
///|
pub fn format_pattern(pattern : Pattern) -> String raise CepError {
codec_bounded_format(pattern_to_json(pattern))
}