pub mod dump;
pub mod error;
pub mod types;
mod validate;
pub use error::HirError;
pub use types::{
Annotation, AnnotationArg, Declaration, DictEntry, DirectiveRecord, DirectiveValue, Event,
Expr, Generator, OptimizationState, Position, PreprocessingSnapshot, PreprocessingState,
Program, Protocol, Rule, RuleEntry, Settings, SettingsListElement, SettingsNode, SourceFile,
Span, Stmt, SwitchArm, TranslationState, default_var_index,
};
use serde_json::Value;
pub fn parse_str(input: &str) -> Result<Program, HirError> {
let value: Value = serde_json::from_str(input)?;
parse_value(value)
}
pub fn parse_value(value: Value) -> Result<Program, HirError> {
validate::check_envelope(&value)?;
validate::check_unknown_kinds(&value)?;
let program: Program = serde_json::from_value(value)?;
program.validate()?;
Ok(program)
}
impl Program {
pub fn validate(&self) -> Result<(), HirError> {
validate::validate_program(self)
}
pub fn dump(&self) -> String {
dump::dump(self)
}
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::parse_value;
use super::validate::check_envelope;
#[test]
fn v2_envelope_is_accepted_and_v1_is_rejected_before_body_inspection() {
let v2 = json!({
"protocol": { "name": "wright/opy-hir", "version": "2.0.0" }
});
assert!(check_envelope(&v2).is_ok());
let v1 = json!({
"protocol": { "name": "wright/opy-hir", "version": "1.1.0" },
"rules": [{ "kind": "malformed-v1-body" }]
});
let error = check_envelope(&v1).expect_err("v1 payload must not enter the v2 parser");
assert_eq!(error.code(), "incompatible-protocol");
}
#[test]
fn unknown_conditional_condition_kind_preserves_unsupported_node_span() {
let error = parse_value(json!({
"protocol": { "name": "wright/opy-hir", "version": "2.0.0" },
"rules": [{
"event": { "args": [] },
"conditions": [],
"actions": [{
"kind": "expr",
"expr": {
"kind": "conditional",
"thenValue": { "kind": "number", "value": 1 },
"condition": {
"kind": "future-expression",
"span": {
"file": 0,
"start": { "line": 4, "col": 12 },
"end": { "line": 4, "col": 20 }
}
},
"elseValue": { "kind": "number", "value": 0 }
}
}]
}]
}))
.expect_err("unknown kinds nested in conditional conditions must be rejected");
assert_eq!(error.code(), "unsupported-node");
assert_eq!(error.message(), "unsupported node kind 'future-expression'");
assert_eq!(error.span().unwrap().start.line, 4);
assert_eq!(error.span().unwrap().start.col, 12);
}
}