///|
/// 名字段门:按文档版本与版本面选表的 XML 名字产生式校验。
/// 数据面 = `name_tables_gen.mbt`(生成器直发区间表 + 谓词);本件只写拼装语义
/// (1.0 Letter = BaseChar|Ideographic、Name/NameChar 组合)与树面行走。
/// 规则:
/// - version="1.1" 文档恒走 1.1 紧凑表(产生式 [4]/[5]),版本面选择无关;
/// - version="1.0"/无声明文档按 [XmlEdition] 选表:Editions1to4 = 4e 全表
/// (BaseChar/Ideographic/CombiningChar/Digit/Extender,产生式 [85]-[89],
/// 套件 EDITION="1 2 3 4" 面判词所据);Edition5 = 5e 紧凑表(与 1.1 同形,
/// 套件 EDITION="5" 面判词所据;亦即 parse 缺省面 = 现行底座行为)。
/// 门位:树建后全量行走(DOCTYPE 名 / PI 目标 / 元素名 / 属性名)——内部子集的
/// PI 事件落在 prologue/epilogue,树面可见,漏拒都出在这里。
/// 施工账:ctx.md §6(役E1,R-E1b/R-E1c)。
///|
/// XML 1.0 版本面(套件 EDITION 语义:测试按适用版次标注,处理器按面选子集)。
pub(all) enum XmlEdition {
Editions1to4
Edition5
} derive(Eq)
///|
pub extend XmlEdition with Eq::{equal, not_equal}
///|
/// 1.0 Letter(4e 产生式 [84])= BaseChar | Ideographic。
fn is_letter_10(code_point : Int32) -> Bool {
is_base_char_10(code_point) || is_ideographic_10(code_point)
}
///|
/// 1.0 NameStartChar(4e [5] 字符面)= ':' | '_' | Letter。
fn is_name_start_10(code_point : Int32) -> Bool {
code_point == 0x3A || code_point == 0x5F || is_letter_10(code_point)
}
///|
/// 1.0 NameChar(4e [4])= NameStartChar | Digit | '.' | '-' | CombiningChar |
/// Extender。
fn is_name_char_10(code_point : Int32) -> Bool {
is_name_start_10(code_point) ||
is_digit_10(code_point) ||
code_point == 0x2D ||
code_point == 0x2E ||
is_combining_char_10(code_point) ||
is_extender_10(code_point)
}
///|
/// 5e/1.1 NameStartChar(紧凑表,gen 直发)。
fn is_name_start_5(code_point : Int32) -> Bool {
is_name_start_char_11(code_point)
}
///|
/// 5e/1.1 NameChar(紧凑表 + 对 NameStartChar 的引用,gen 已展开)。
fn is_name_char_5(code_point : Int32) -> Bool {
is_name_char_11(code_point)
}
///|
/// 版本面 → 谓词对(version="1.1" 恒走 1.1;否则按版本面选)。
fn name_predicates(
edition : XmlEdition,
version_11 : Bool,
) -> ((Int32) -> Bool, (Int32) -> Bool) {
match (edition, version_11) {
(_, true) => (is_name_start_5, is_name_char_5)
(Editions1to4, false) => (is_name_start_10, is_name_char_10)
(Edition5, false) => (is_name_start_5, is_name_char_5)
}
}
///|
/// 名字串按谓词对校验;返回违规注记(合法 = None)。
fn name_violation_of(
name : String,
edition : XmlEdition,
version_11 : Bool,
) -> String? {
let (start_ok, char_ok) = name_predicates(edition, version_11)
let chars = name.to_array()
if chars.length() == 0 {
return Some("empty name")
}
let first = chars[0].to_int()
if start_ok(first) == false {
return Some(
"illegal name start character #x\{first.to_string(radix=16)} in \"\{name}\"",
)
}
for index in 1.. XmlError {
XmlError::At(error=XmlErrorKind::IllegalName(message), span={
start: { offset: 0, line: 1, column: 1, },
end: { offset: 0, line: 1, column: 1, },
})
}
///|
fn check_name(
name : String,
edition : XmlEdition,
version_11 : Bool,
) -> Unit raise XmlError {
match name_violation_of(name, edition, version_11) {
Some(message) => raise name_error(message)
None => ()
}
}
///|
/// 树节点行走:PI 目标 + 元素名 + 属性名,递归子树。
fn check_node(
node : Node,
edition : XmlEdition,
version_11 : Bool,
) -> Unit raise XmlError {
match node {
PI(target~, ..) => check_name(target, edition, version_11)
Element(element) => {
check_name(element.name.qualified_name, edition, version_11)
for attribute in element.attributes {
check_name(attribute.name.qualified_name, edition, version_11)
}
for child in element.children {
check_node(child, edition, version_11)
}
}
_ => ()
}
}
///|
/// 文档名字面全查:DOCTYPE 名 + 根前 + 根 + 根后(声明定版本;无声明 = 1.0)。
fn validate_document_names(
document : Document,
edition : XmlEdition,
) -> Unit raise XmlError {
let version_11 = match document.decl {
Some(declaration) => declaration.version == "1.1"
None => false
}
match document.doctype {
Some(name) => check_name(name, edition, version_11)
None => ()
}
for node in document.prologue {
check_node(node, edition, version_11)
}
check_name(document.root.name.qualified_name, edition, version_11)
for attribute in document.root.attributes {
check_name(attribute.name.qualified_name, edition, version_11)
}
for child in document.root.children {
check_node(child, edition, version_11)
}
for node in document.epilogue {
check_node(node, edition, version_11)
}
}