use std::fmt::Write;
use crate::constants::{CARRIAGE_RETURN, NEWLINE, SPACE};
use crate::xdoc::error::Result;
use crate::Pi;
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DocTypeDecl {
pub(crate) space_before_name: Whitespace,
pub(crate) name: DocTypeName,
pub(crate) external_id: Option<(Whitespace, ExternalID)>,
pub(crate) space_before_int_subset: Option<Whitespace>,
pub(crate) int_subsets: Option<(IntSubsets, Option<Whitespace>)>,
}
pub(crate) const STR_DOCTYPE: &str = "DOCTYPE";
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DocTypeName {
pub(crate) name: String,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Whitespace {
pub(crate) inner: Vec<Space>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Space {
Space,
Tab,
CarriageReturn,
Newline,
}
pub(crate) const STR_SYSTEM: &str = "SYSTEM";
pub(crate) const STR_PUBLIC: &str = "PUBLIC";
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ExternalID {
System(SystemExternalID),
Public(PublicExternalID),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SystemExternalID {
pub(crate) space_before_literal: Whitespace,
pub(crate) system_literal: SystemLiteral,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PublicExternalID {
pub(crate) space_before_pub_id: Whitespace,
pub(crate) pub_id_literal: PubIDLiteral,
pub(crate) space_after_pub_id: Whitespace,
pub(crate) system_literal: SystemLiteral,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Quote {
Single,
Double,
}
impl Quote {
pub(crate) fn new(c: char) -> Result<Self> {
match c {
'\'' => Ok(Quote::Single),
'"' => Ok(Quote::Double),
_ => raise!("expected either single or double quote character"),
}
}
pub(crate) fn char(&self) -> char {
match self {
Quote::Single => '\'',
Quote::Double => '"',
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SystemLiteral {
pub(crate) quote: Quote,
pub(crate) value: String,
}
impl SystemLiteral {
pub(crate) fn forbidden(c: char, q: Quote) -> bool {
q.char() == c
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PubIDLiteral {
pub(crate) quote: Quote,
pub(crate) value: String,
}
impl PubIDLiteral {
pub(crate) fn forbidden(c: char, q: Quote) -> bool {
match q {
Quote::Single if c == '\'' => return true,
Quote::Double if c == '"' => return true,
_ => {}
}
matches!(c,
SPACE |
CARRIAGE_RETURN |
NEWLINE |
'a'..='z' |
'A'..='Z' |
'0'..='9' |
'-' |
'\'' |
'(' |
')' |
'+' |
',' |
'.' |
'/' |
':' |
'?' |
';' |
'*' |
'#' |
'@' |
'$' |
'_' |
'%'
)
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct IntSubsets(Vec<IntSubset>);
impl IntSubsets {
pub(crate) fn new(items: Vec<IntSubset>) -> Self {
Self(items)
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum IntSubset {
MarkupDecl(MarkupDeclValue),
DeclSep(DeclSep), }
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum DeclSep {
PEReference(PEReferenceValue),
Space(Whitespace),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ReferenceValue {
pub(crate) value: DocTypeName,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PEReferenceValue {
pub(crate) value: DocTypeName,
}
pub(crate) const STR_ELEMENT: &str = "ELEMENT";
pub(crate) const STR_ATTLIST: &str = "ATTLIST";
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum MarkupDeclValue {
ElementDecl(ElementDeclValue),
AttlistDecl(AttlistDeclValue),
EntityDecl(EntityDeclValue),
NotationDecl(NotationDeclValue),
PI(Pi),
Comment(String),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ElementDeclValue {
pub(crate) space_before_name: Whitespace,
pub(crate) name: DocTypeName,
pub(crate) space_after_name: Whitespace,
pub(crate) content_spec: ContentSpec,
pub(crate) space_after_content_spec: Option<Whitespace>,
}
pub(crate) const STR_EMPTY: &str = "EMPTY";
pub(crate) const STR_ANY: &str = "ANY";
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ContentSpec {
Empty,
Any,
Mixed(MixedValue),
Children(ChildrenValue),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NmToken {
pub(crate) value: String,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DelimitedListItem<T> {
pub(crate) space_before_delimiter: Option<Whitespace>,
pub(crate) space_after_delimiter: Option<Whitespace>,
pub(crate) item: T,
}
pub(crate) const STR_PCDATA: &str = "#PCDATA";
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct MixedValue {
pub(crate) space_after_open_parenthesis: Option<Whitespace>,
pub(crate) element_names: Vec<DelimitedListItem<DocTypeName>>,
pub(crate) space_before_close_parenthesis: Option<Whitespace>,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Repetitions {
Optional,
Once,
ZeroOrMore,
OneOrMore,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ChildrenType {
Choice(ChoiceValue),
Seq(SeqValue),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ChildrenValue {
pub(crate) children_type: ChildrenType,
pub(crate) repetitions: Repetitions,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum CpItem {
Name(DocTypeName),
Choice(ChoiceValue),
Seq(SeqValue),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct CpValue {
pub(crate) cp_item: CpItem,
pub(crate) repetitions: Repetitions,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct ChoiceValue {
pub(crate) cps: Vec<DelimitedListItem<CpValue>>,
pub(crate) space_before_close: Option<Whitespace>,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SeqValue {
pub(crate) cps: Vec<DelimitedListItem<CpValue>>,
pub(crate) space_before_close: Option<Whitespace>,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AttlistDeclValue {
pub(crate) space_before_name: Whitespace,
pub(crate) name: DocTypeName,
pub(crate) att_defs: Vec<AttDef>,
pub(crate) space_before_close: Option<Whitespace>,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AttDef {
pub(crate) space_before_name: Whitespace,
pub(crate) name: DocTypeName,
pub(crate) space_before_att_type: Whitespace,
pub(crate) att_type: AttType,
pub(crate) space_before_default_decl: Whitespace,
pub(crate) default_decl: DefaultDecl,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum AttType {
CData,
ID,
IDRef,
IDRefs,
Entity,
Entities,
NMToken,
NMTokens,
EnumeratedTypes(EnumeratedType),
}
pub(crate) const STR_CDATA: &str = "CDATA";
pub(crate) const STR_ID: &str = "ID";
pub(crate) const STR_IDREF: &str = "IDREF";
pub(crate) const STR_IDREFS: &str = "IDREFS";
pub(crate) const STR_ENTITY: &str = "ENTITY";
pub(crate) const STR_ENTITIES: &str = "ENTITIES";
pub(crate) const STR_NMTOKEN: &str = "NMTOKEN";
pub(crate) const STR_NMTOKENS: &str = "NMTOKENS";
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum EnumeratedType {
NotationType(NotationTypeValue),
Enumeration(EnumerationValue),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NotationTypeValue {
pub(crate) space_before_open: Whitespace,
pub(crate) names: Vec<DelimitedListItem<DocTypeName>>,
pub(crate) space_before_close: Option<Whitespace>,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct EnumerationValue {
pub(crate) names: Vec<DelimitedListItem<NmToken>>,
pub(crate) space_before_close: Option<Whitespace>,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum EntityDeclValue {
GEDecl(GEDeclValue),
PEDecl(PEDeclValue),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct GEDeclValue {
pub(crate) space_before_name: Whitespace,
pub(crate) name: DocTypeName,
pub(crate) space_before_entity_def: Whitespace,
pub(crate) entity_def: EntityDef,
pub(crate) space_before_close: Option<Whitespace>,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PEDeclValue {
pub(crate) space_before_percent: Whitespace,
pub(crate) space_before_name: Whitespace,
pub(crate) name: DocTypeName,
pub(crate) space_before_pe_def: Whitespace,
pub(crate) pe_def: PEDef,
pub(crate) space_before_close: Option<Whitespace>,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum EntityDef {
Entity(EntityValue),
External(EntityDefExternal),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct EntityDefExternal {
pub(crate) external_id: ExternalID,
pub(crate) ndata_decl: Option<NDataDecl>,
}
pub(crate) const STR_NDATA: &str = "NDATA";
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NDataDecl {
pub(crate) space_before_ndata: Whitespace,
pub(crate) space_before_name: Whitespace,
pub(crate) name: DocTypeName,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum PEDef {
Entity(EntityValue),
External(ExternalID),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct EntityValue {
pub(crate) quote: Quote,
pub(crate) data: Vec<EntityValueData>,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum EntityValueData {
String(String),
PEReference(PEReferenceValue),
Reference(ReferenceValue),
}
impl EntityValueData {
pub(crate) fn forbidden(c: char, q: Quote) -> bool {
match c {
'\'' if q == Quote::Single => true,
'"' if q == Quote::Double => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Reference {
EntityRef(ReferenceValue),
CharRef(CharRefValue),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct CharRefValue {
pub(crate) char_ref_type: CharRefValueType,
pub(crate) value: u64,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum CharRefValueType {
Decimal,
Hex,
}
pub(crate) const STR_NOTATION: &str = "NOTATION";
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NotationDeclValue {
pub(crate) space_before_name: Whitespace,
pub(crate) name: DocTypeName,
pub(crate) space_before_id: Whitespace,
pub(crate) id: ExternalOrPublicID,
pub(crate) space_before_close: Option<Whitespace>,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum ExternalOrPublicID {
External(ExternalID),
Public(PublicID),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct PublicID {
pub(crate) space_before_name: Whitespace,
pub(crate) public_id_literal: PubIDLiteral,
}
pub(crate) const STR_REQUIRED: &str = "#REQUIRED";
pub(crate) const STR_IMPLIED: &str = "#IMPLIED";
pub(crate) const STR_FIXED: &str = "#FIXED";
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum DefaultDecl {
Required,
Implied,
Value(DefaultDeclAttValue),
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct DefaultDeclAttValue {
pub(crate) fixed: Option<Whitespace>,
pub(crate) att_value: AttValue,
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct AttValue {
pub(crate) quote: Quote,
pub(crate) data: AttValueData,
}
impl AttValue {
fn write_opts<W: Write>(&self, _w: W, _o: Wst) -> Result<()> {
unimplemented!();
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum AttValueData {
Text(String),
Reference(ReferenceValue),
}
impl AttValueData {
pub(crate) fn forbidden(c: char, q: Quote) -> bool {
match c {
'\'' if q == Quote::Single => true,
'"' if q == Quote::Double => true,
'&' => true,
'<' => true,
_ => false,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct Wst {}