commit 68d7b73519898600f13be2692fe6917ecb0779c0
parent b72c4e29dc1db52d098155ebb2f86dc41de77bad
Author: Drew DeVault <sir@cmpwn.com>
Date: Sat, 10 Apr 2021 09:48:30 -0400
format::xml: implement XML comments
Diffstat:
M | format/xml/parser.ha | | | 156 | ++++++++++++++++++++++++++++++++++++++++++++++++++------------------------------ |
1 file changed, 98 insertions(+), 58 deletions(-)
diff --git a/format/xml/parser.ha b/format/xml/parser.ha
@@ -63,29 +63,30 @@ export fn scan(par: *parser) (token | void | error) = {
} else return void,
rn: rune => rn,
};
- // TODO:
- // - Comments
- // - Entities/references
- // - CDATA
- // - Processing Instructions
return switch (par.state) {
- state::ROOT => switch (rn) {
+ state::ROOT, state::ELEMENT => switch (rn) {
'<' => {
+ const next = match (bufio::scanrune(par.in)?) {
+ io::EOF => return syntaxerr,
+ rn: rune => {
+ bufio::unreadrune(par.in, rn);
+ rn;
+ },
+ };
bufio::unreadrune(par.in, rn);
+ switch (next) {
+ '!' => return scan_comment(par),
+ '?' => return scan_pi(par),
+ * => void,
+ };
let el = scan_element(par)?;
par.state = state::ATTRS;
el;
},
- * => return syntaxerr,
- },
- state::ELEMENT => switch (rn) {
- '<' => {
- bufio::unreadrune(par.in, rn);
- let el = scan_element(par);
- par.state = state::ATTRS;
- el;
- },
* => {
+ if (par.state == state::ROOT) {
+ return syntaxerr;
+ };
bufio::unreadrune(par.in, rn);
scan_content(par)?;
},
@@ -107,25 +108,6 @@ export fn scan(par: *parser) (token | void | error) = {
};
};
-fn scan_element(par: *parser) (token | error) = {
- want(par, '<')?;
- let close = false;
- match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => switch (rn) {
- '/' => close = true,
- * => bufio::unreadrune(par.in, rn),
- },
- };
- let name = scan_name(par)?;
- if (close) {
- free(name);
- return elementend;
- } else {
- return name: elementstart;
- };
-};
-
fn scan_attr(par: *parser) (token | error) = {
let name = scan_name(par)?;
want(par, OPTWS, '=', OPTWS);
@@ -135,8 +117,8 @@ fn scan_attr(par: *parser) (token | error) = {
io::EOF => return syntaxerr,
rn: rune => {
switch (rn) {
- '<' => abort(), // TODO
- '&' => abort(), // TODO
+ '<' => return syntaxerr,
+ '&' => abort(), // TODO: Entities
* => void,
};
if (rn == quot) break;
@@ -146,29 +128,39 @@ fn scan_attr(par: *parser) (token | error) = {
return (name, strio::finish(val)): attribute;
};
-fn scan_name(par: *parser) (str | error) = {
- let buf = strio::dynamic();
-
- const rn = match (bufio::scanrune(par.in)?) {
- io::EOF => return syntaxerr,
- rn: rune => rn,
- };
- if (!isnamestart(rn)) {
- return syntaxerr;
- };
- strio::appendrune(buf, rn);
-
- for (true) match (bufio::scanrune(par.in)?) {
+fn scan_comment(par: *parser) (token | void | error) = {
+ want(par, "<!")?;
+ match (bufio::scanrune(par.in)?) {
io::EOF => return syntaxerr,
- rn: rune => if (isname(rn)) {
- strio::appendrune(buf, rn);
- } else {
- bufio::unreadrune(par.in, rn);
- break;
+ rn: rune => switch (rn) {
+ '-' => { // Comments
+ want(par, '-')?;
+ },
+ '[' => { // CDATA
+ want(par, "CDATA[")?;
+ abort(); // TODO
+ },
+ * => return syntaxerr,
},
};
-
- return strio::finish(buf);
+ for (true) {
+ let rn = match (bufio::scanrune(par.in)?) {
+ io::EOF => return syntaxerr,
+ rn: rune => rn,
+ };
+ if (rn != '-') continue;
+ let rn = match (bufio::scanrune(par.in)?) {
+ io::EOF => return syntaxerr,
+ rn: rune => rn,
+ };
+ if (rn != '-') continue;
+ let rn = match (bufio::scanrune(par.in)?) {
+ io::EOF => return syntaxerr,
+ rn: rune => rn,
+ };
+ if (rn == '>') break;
+ };
+ return scan(par);
};
fn scan_content(par: *parser) (text | error) = {
@@ -183,11 +175,11 @@ fn scan_content(par: *parser) (text | error) = {
},
'&' => {
bufio::unreadrune(par.in, rn);
- abort(); // TODO
+ abort(); // TODO: Entities
},
'%' => {
bufio::unreadrune(par.in, rn);
- abort(); // TODO
+ abort(); // TODO: Parameter entities
},
};
strio::appendrune(content, rn);
@@ -196,6 +188,54 @@ fn scan_content(par: *parser) (text | error) = {
return strio::finish(content);
};
+fn scan_element(par: *parser) (token | error) = {
+ want(par, '<')?;
+ let close = false;
+ match (bufio::scanrune(par.in)?) {
+ io::EOF => return syntaxerr,
+ rn: rune => switch (rn) {
+ '/' => close = true,
+ * => bufio::unreadrune(par.in, rn),
+ },
+ };
+ let name = scan_name(par)?;
+ if (close) {
+ free(name);
+ return elementend;
+ } else {
+ return name: elementstart;
+ };
+};
+
+fn scan_name(par: *parser) (str | error) = {
+ let buf = strio::dynamic();
+
+ const rn = match (bufio::scanrune(par.in)?) {
+ io::EOF => return syntaxerr,
+ rn: rune => rn,
+ };
+ if (!isnamestart(rn)) {
+ return syntaxerr;
+ };
+ strio::appendrune(buf, rn);
+
+ for (true) match (bufio::scanrune(par.in)?) {
+ io::EOF => return syntaxerr,
+ rn: rune => if (isname(rn)) {
+ strio::appendrune(buf, rn);
+ } else {
+ bufio::unreadrune(par.in, rn);
+ break;
+ },
+ };
+
+ return strio::finish(buf);
+};
+
+fn scan_pi(par: *parser) (void | error) = {
+ abort(); // TODO: Processor instructions
+};
+
fn prolog(par: *parser) (void | error) = {
want(par, "<?xml", WS)?;