use super::{AbendId, CondId, ConstId, Count, IntExpr, MovePlan, Odo, Operand, PlaceId, RangeId, StorePlan, SymId};
use crate::storage::Kind;
use crate::vocab::Figurative;
use crate::{codec_enum, codec_struct};
use zarch::hfp::Precision;
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Markup {
JsonGenerate(JsonGenerate),
XmlGenerate(XmlGenerate),
XmlParse(XmlParse),
JsonParse(JsonParse),
}
impl Markup {
pub fn phrases(&self) -> (bool, bool) {
match self {
Markup::JsonGenerate(g) => (g.on_exception, g.not_on_exception),
Markup::XmlGenerate(g) => (g.on_exception, g.not_on_exception),
Markup::XmlParse(p) => (p.on_exception, p.not_on_exception),
Markup::JsonParse(p) => (p.on_exception, p.not_on_exception),
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Ccsid {
Unnamed,
CodePage,
Operand(Operand),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Convert {
Chars { justified: bool },
National,
Float(Precision),
Fixed { integers: u32 },
Refused(AbendId),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Marker {
Byte(Option<u8>),
Condition(CondId),
Refused(AbendId),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct JsonGenerate {
pub from: PlaceId,
pub subscripts: Vec<IntExpr>,
pub nodes: Vec<JsonNode>,
pub name: Option<SymId>,
pub receiver: PlaceId,
pub encoding: Ccsid,
pub count: Option<(PlaceId, StorePlan)>,
pub code: (PlaceId, StorePlan),
pub on_exception: bool,
pub not_on_exception: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct JsonNode {
pub offset: u32,
pub moved: Vec<Odo>,
pub len: u32,
pub kind: Kind,
pub name: SymId,
pub occurs: Option<Count>,
pub indicator: Option<(Result<PlaceId, AbendId>, Marker)>,
pub null: Option<Figurative>,
pub value: JsonValue,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum JsonValue {
Object { members: Vec<u32>, eligible: bool },
Leaf(JsonLeaf),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct JsonLeaf {
pub suppress: Vec<Figurative>,
pub boolean: Option<Marker>,
pub convert: Convert,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct XmlGenerate {
pub receiver: PlaceId,
pub encoding: Ccsid,
pub namespace: Option<Operand>,
pub prefix: Option<Operand>,
pub declaration: bool,
pub from: PlaceId,
pub subscripts: Vec<IntExpr>,
pub nodes: Vec<XmlNode>,
pub suppressing: bool,
pub count: Option<(PlaceId, StorePlan)>,
pub code: (PlaceId, StorePlan),
pub on_exception: bool,
pub not_on_exception: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct XmlNode {
pub offset: u32,
pub moved: Vec<Odo>,
pub len: u32,
pub kind: Kind,
pub name: SymId,
pub occurs: Option<Count>,
pub value: XmlValue,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum XmlValue {
Element { members: Vec<u32> },
Members { members: Vec<u32> },
Leaf { form: XmlForm, suppress: Vec<Figurative>, convert: Convert },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum XmlForm {
Attribute,
Element,
Content,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct XmlParse {
pub document: PlaceId,
pub encoding: Option<Operand>,
pub national: bool,
pub procedure: RangeId,
pub event: PlaceId,
pub code: (PlaceId, StorePlan),
pub information: (PlaceId, StorePlan),
pub code_value: IntExpr,
pub on_exception: bool,
pub not_on_exception: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct JsonParse {
pub source: PlaceId,
pub encoding: Ccsid,
pub into: PlaceId,
pub subscripts: Vec<IntExpr>,
pub nodes: Vec<ParseNode>,
pub ignore_all: bool,
pub code: (PlaceId, StorePlan),
pub status: (PlaceId, StorePlan),
pub on_exception: bool,
pub not_on_exception: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParseNode {
pub offset: u32,
pub moved: Vec<Odo>,
pub len: u32,
pub kind: Kind,
pub name: Named,
pub occurs: Option<Count>,
pub ignored: bool,
pub indicator: Option<Indicator>,
pub null: Option<(Figurative, MovePlan)>,
pub value: ParseValue,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Named {
Exactly(SymId),
Folded(SymId),
Omitted,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ParseValue {
Object { members: Vec<u32> },
Leaf(ParseLeaf),
Suppressed,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ParseLeaf {
pub boolean: Option<Flag>,
pub text: Option<MovePlan>,
pub number: NumberInto,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberInto {
Float(MovePlan),
Store(StorePlan),
Edited(MovePlan),
Digits,
Incompatible,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Indicator {
pub place: Option<Result<PlaceId, AbendId>>,
pub flag: Flag,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Flag {
Set { on: SetTo, off: SetTo },
Literals { on: (ConstId, MovePlan), off: (ConstId, MovePlan) },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SetTo {
Nothing,
Move { place: PlaceId, value: ConstId, plan: MovePlan },
Refused(AbendId),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum XmlRegister {
Text,
NText,
Namespace,
NNamespace,
Prefix,
NPrefix,
}
impl XmlRegister {
pub fn national(self) -> bool {
matches!(self, XmlRegister::NText | XmlRegister::NNamespace | XmlRegister::NPrefix)
}
}
codec_enum!(Markup { JsonGenerate(g) = 0, XmlGenerate(g) = 1, XmlParse(p) = 2, JsonParse(p) = 3 });
codec_enum!(Ccsid { Unnamed = 0, CodePage = 1, Operand(o) = 2 });
codec_enum!(Convert { Chars { justified } = 0, National = 1, Float(precision) = 2, Fixed { integers } = 3, Refused(abend) = 4 });
codec_enum!(Marker { Byte(b) = 0, Condition(c) = 1, Refused(abend) = 2 });
codec_struct!(JsonGenerate { from, subscripts, nodes, name, receiver, encoding, count, code, on_exception, not_on_exception } check json_valid);
codec_struct!(JsonNode { offset, moved, len, kind, name, occurs, indicator, null, value });
codec_enum!(JsonValue { Object { members, eligible } = 0, Leaf(leaf) = 1 });
codec_struct!(JsonLeaf { suppress, boolean, convert });
codec_struct!(XmlGenerate {
receiver, encoding, namespace, prefix, declaration, from, subscripts, nodes, suppressing, count, code, on_exception, not_on_exception,
} check xml_valid);
codec_struct!(XmlNode { offset, moved, len, kind, name, occurs, value });
codec_enum!(XmlValue { Element { members } = 0, Members { members } = 1, Leaf { form, suppress, convert } = 2 });
codec_enum!(XmlForm { Attribute = 0, Element = 1, Content = 2 });
codec_struct!(XmlParse { document, encoding, national, procedure, event, code, information, code_value, on_exception, not_on_exception });
codec_struct!(JsonParse { source, encoding, into, subscripts, nodes, ignore_all, code, status, on_exception, not_on_exception } check parse_valid);
codec_struct!(ParseNode { offset, moved, len, kind, name, occurs, ignored, indicator, null, value });
codec_enum!(Named { Exactly(name) = 0, Folded(name) = 1, Omitted = 2 });
codec_enum!(ParseValue { Object { members } = 0, Leaf(leaf) = 1, Suppressed = 2 });
codec_struct!(ParseLeaf { boolean, text, number });
codec_enum!(NumberInto { Float(plan) = 0, Store(store) = 1, Edited(plan) = 2, Digits = 3, Incompatible = 4 });
codec_struct!(Indicator { place, flag });
codec_enum!(Flag { Set { on, off } = 0, Literals { on, off } = 1 });
codec_enum!(SetTo { Nothing = 0, Move { place, value, plan } = 1, Refused(abend) = 2 });
codec_enum!(XmlRegister { Text = 0, NText = 1, Namespace = 2, NNamespace = 3, Prefix = 4, NPrefix = 5 });
fn tree_valid<'n>(nodes: usize, members: impl Iterator<Item = (usize, &'n [u32])>) -> Result<(), String> {
if nodes == 0 {
return Err("a markup tree with no root".into());
}
for (k, list) in members {
if let Some(&m) = list.iter().find(|&&m| m as usize <= k || m as usize >= nodes) {
return Err(format!("markup node {k} holds node {m} of {nodes}"));
}
}
Ok(())
}
fn json_valid(g: &JsonGenerate) -> Result<(), String> {
tree_valid(g.nodes.len(), g.nodes.iter().enumerate().filter_map(|(k, n)| match &n.value {
JsonValue::Object { members, .. } => Some((k, &members[..])),
JsonValue::Leaf(_) => None,
}))
}
fn xml_valid(g: &XmlGenerate) -> Result<(), String> {
tree_valid(g.nodes.len(), g.nodes.iter().enumerate().filter_map(|(k, n)| match &n.value {
XmlValue::Element { members } | XmlValue::Members { members } => Some((k, &members[..])),
XmlValue::Leaf { .. } => None,
}))
}
fn parse_valid(p: &JsonParse) -> Result<(), String> {
tree_valid(p.nodes.len(), p.nodes.iter().enumerate().filter_map(|(k, n)| match &n.value {
ParseValue::Object { members } => Some((k, &members[..])),
_ => None,
}))
}