Skip to content

Commit

Permalink
Merge pull request #216 from gosub-browser/doctype-fixes
Browse files Browse the repository at this point in the history
Implemented doctype nodes
  • Loading branch information
jaytaph authored Nov 2, 2023
2 parents fd2fe96 + 0142d60 commit 161f1c1
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 12 deletions.
14 changes: 11 additions & 3 deletions src/bin/parser-test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fn main() -> Result<()> {
tests_failed: Vec::new(),
};

let filenames = Some(&["tests19.dat"][..]);
let filenames = Some(&["doctype01.dat"][..]);
let fixtures = testing::tree_construction::fixtures(filenames).expect("fixtures");

for fixture_file in fixtures {
Expand Down Expand Up @@ -207,8 +207,10 @@ fn print_node_result(result: &SubtreeResult) {
println!("❌ {expected}, Found unexpected attribute: {name}");
}

Some(NodeResult::ElementMatchFailure { name, expected, .. }) => {
println!("❌ {expected}, Found unexpected element node: {name}");
Some(NodeResult::ElementMatchFailure {
actual, expected, ..
}) => {
println!("❌ {expected}, Found unexpected element node: {actual}");
}

Some(NodeResult::TextMatchSuccess { expected }) => {
Expand All @@ -219,6 +221,12 @@ fn print_node_result(result: &SubtreeResult) {
println!("❌ {expected}, Found unexpected text node: {text}");
}

Some(NodeResult::DocTypeMatchFailure {
actual, expected, ..
}) => {
println!("❌ {actual}, Found unexpected doctype node: {expected}");
}

Some(NodeResult::CommentMatchFailure {
expected, comment, ..
}) => {
Expand Down
23 changes: 23 additions & 0 deletions src/html5/node.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::parser::document::{Document, DocumentHandle};
use crate::html5::node::data::comment::CommentData;
use crate::html5::node::data::doctype::DocTypeData;
use crate::html5::node::data::document::DocumentData;
use crate::html5::node::data::element::ElementData;
use crate::html5::node::data::text::TextData;
Expand All @@ -21,6 +22,7 @@ pub mod data;
#[derive(Debug, PartialEq)]
pub enum NodeType {
Document,
DocType,
Text,
Comment,
Element,
Expand All @@ -31,6 +33,8 @@ pub enum NodeType {
pub enum NodeData {
/// Represents a document
Document(DocumentData),
// Represents a doctype
DocType(DocTypeData),
/// Represents a text
Text(TextData),
/// Represents a comment
Expand Down Expand Up @@ -244,6 +248,24 @@ impl Node {
}
}

pub fn new_doctype(
document: &DocumentHandle,
name: &str,
pub_identifier: &str,
sys_identifier: &str,
) -> Self {
Node {
id: Default::default(),
parent: None,
children: vec![],
data: NodeData::DocType(DocTypeData::new(name, pub_identifier, sys_identifier)),
name: "".to_string(),
namespace: None,
document: Document::clone(document),
is_registered: false,
}
}

/// Create a new element node with the given name and attributes and namespace
pub fn new_element(
document: &DocumentHandle,
Expand Down Expand Up @@ -340,6 +362,7 @@ impl NodeTrait for Node {
fn type_of(&self) -> NodeType {
match self.data {
NodeData::Document { .. } => NodeType::Document,
NodeData::DocType { .. } => NodeType::DocType,
NodeData::Text { .. } => NodeType::Text,
NodeData::Comment { .. } => NodeType::Comment,
NodeData::Element { .. } => NodeType::Element,
Expand Down
1 change: 1 addition & 0 deletions src/html5/node/data.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub mod comment;
pub mod doctype;
pub mod document;
pub mod element;
pub mod text;
33 changes: 33 additions & 0 deletions src/html5/node/data/doctype.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use core::fmt::{Debug, Formatter};
use std::fmt;

#[derive(PartialEq, Clone)]
/// Data structure for document nodes
pub struct DocTypeData {
pub name: String,
pub pub_identifier: String,
pub sys_identifier: String,
}

impl Default for DocTypeData {
fn default() -> Self {
Self::new("", "", "")
}
}

impl Debug for DocTypeData {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut debug = f.debug_struct("DocTypeData");
debug.finish()
}
}

impl DocTypeData {
pub(crate) fn new(name: &str, pub_identifier: &str, sys_identifier: &str) -> Self {
DocTypeData {
name: name.to_string(),
pub_identifier: pub_identifier.to_string(),
sys_identifier: sys_identifier.to_string(),
}
}
}
16 changes: 11 additions & 5 deletions src/html5/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1751,11 +1751,17 @@ impl<'stream> Html5Parser<'stream> {
/// Create a new node that is not connected or attached to the document arena
fn create_node(&self, token: &Token, namespace: &str) -> Node {
match token {
Token::DocType { name, .. } => {
let val = format!("!DOCTYPE {}", name.as_deref().unwrap_or(""),);

return Node::new_element(&self.document, val.as_str(), HashMap::new(), namespace);
}
Token::DocType {
name,
pub_identifier,
sys_identifier,
..
} => Node::new_doctype(
&self.document,
&name.clone().unwrap_or_default(),
&pub_identifier.clone().unwrap_or_default(),
&sys_identifier.clone().unwrap_or_default(),
),
Token::StartTag {
name, attributes, ..
} => Node::new_element(&self.document, name, attributes.clone(), namespace),
Expand Down
11 changes: 11 additions & 0 deletions src/html5/parser/document.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::html5::node::arena::NodeArena;
use crate::html5::node::data::doctype::DocTypeData;
use crate::html5::node::data::{comment::CommentData, text::TextData};
use crate::html5::node::HTML_NAMESPACE;
use crate::html5::node::{Node, NodeData, NodeId};
Expand Down Expand Up @@ -494,6 +495,16 @@ impl Document {
NodeData::Document(_) => {
_ = writeln!(f, "{}Document", buffer);
}
NodeData::DocType(DocTypeData {
name,
pub_identifier,
sys_identifier,
}) => {
_ = writeln!(
f,
r#"{buffer}<!DOCTYPE {name} "{pub_identifier}" "{sys_identifier}">"#,
);
}
NodeData::Text(TextData { value, .. }) => {
_ = writeln!(f, "{}\"{}\"", buffer, value);
}
Expand Down
60 changes: 56 additions & 4 deletions src/testing/tree_construction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod parser;

use self::parser::{ErrorSpec, ScriptMode, TestSpec, QUOTED_DOUBLE_NEWLINE};
use super::FIXTURE_ROOT;
use crate::html5::node::data::doctype::DocTypeData;
use crate::html5::node::{HTML_NAMESPACE, MATHML_NAMESPACE, SVG_NAMESPACE};
use crate::html5::parser::document::DocumentBuilder;
use crate::html5::parser::tree_builder::TreeBuilder;
Expand Down Expand Up @@ -70,7 +71,9 @@ pub enum NodeResult {
},

/// The element matches the expected element
ElementMatchSuccess { actual: String },
ElementMatchSuccess {
actual: String,
},

/// A text node did not match
TextMatchFailure {
Expand All @@ -79,6 +82,12 @@ pub enum NodeResult {
text: String,
},

// A doctype node did not match
DocTypeMatchFailure {
actual: String,
expected: String,
},

/// A comment node did not match
CommentMatchFailure {
actual: String,
Expand All @@ -87,7 +96,9 @@ pub enum NodeResult {
},

/// A text node matches
TextMatchSuccess { expected: String },
TextMatchSuccess {
expected: String,
},
}

pub struct SubtreeResult {
Expand Down Expand Up @@ -172,6 +183,12 @@ impl Test {
panic!("text match failed, wanted: [{expected}], got: [{actual}]");
}

Some(NodeResult::DocTypeMatchFailure {
actual, expected, ..
}) => {
panic!("doctype match failed, wanted: [{expected}], got: [{actual}]");
}

Some(NodeResult::ElementMatchFailure {
actual,
expected,
Expand Down Expand Up @@ -283,6 +300,43 @@ impl Test {
let node = document.get_node_by_id(node_idx).unwrap();

let node_result = match &node.data {
NodeData::DocType(DocTypeData {
name,
pub_identifier,
sys_identifier,
}) => {
let doctype_text = if pub_identifier.is_empty() && sys_identifier.is_empty() {
// <!DOCTYPE html>
name.to_string()
} else {
// <!DOCTYPE html "pubid" "sysid">
format!(r#"{name} "{pub_identifier}" "{sys_identifier}""#,)
};

let actual = format!(
"|{}<!DOCTYPE {}>",
" ".repeat(indent as usize * 2 + 1),
doctype_text.trim(),
);

let expected = self.document[next_expected_idx as usize].to_owned();
next_expected_idx += 1;

if actual != expected {
let node = Some(NodeResult::DocTypeMatchFailure {
actual,
expected: "".to_string(),
});

return SubtreeResult {
node,
children: vec![],
next_expected_idx: None,
};
}

Some(NodeResult::TextMatchSuccess { expected })
}
NodeData::Element(element) => {
let prefix: String = match &node.namespace {
Some(namespace) => match namespace.as_str() {
Expand Down Expand Up @@ -357,7 +411,6 @@ impl Test {

Some(NodeResult::ElementMatchSuccess { actual })
}

NodeData::Text(text) => {
let actual = format!(
"|{}\"{}\"",
Expand Down Expand Up @@ -398,7 +451,6 @@ impl Test {

Some(NodeResult::TextMatchSuccess { expected })
}

NodeData::Comment(comment) => {
let actual = format!(
"|{}<!-- {} -->",
Expand Down

0 comments on commit 161f1c1

Please sign in to comment.