aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml3
-rw-r--r--src/bin.rs5
-rw-r--r--src/parser/mod.rs3
-rw-r--r--src/parser/serialize.rs36
-rw-r--r--src/rst.pest10
5 files changed, 48 insertions, 9 deletions
diff --git a/Cargo.toml b/Cargo.toml
index 4c7b8aa..07bb072 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -26,8 +26,9 @@ bitflags = '1.0.4'
unicode_categories = '0.1.1'
pest = '2.0.2'
pest_derive = '2.0.1'
+serde = '1.0.80'
+serde_json = '1.0.32'
quicli = '0.3.1'
structopt = '0.2.12'
-structopt-derive = '0.2.12'
clap = '2.32.0'
diff --git a/src/bin.rs b/src/bin.rs
index 5eeb768..f8ee45b 100644
--- a/src/bin.rs
+++ b/src/bin.rs
@@ -6,7 +6,7 @@ use structopt::StructOpt;
use clap::{_clap_count_exprs, arg_enum};
use quicli::{main, fs::read_file, prelude::Verbosity};
-use self::parser::{RstParser, Rule};
+use self::parser::{RstParser, Rule, serialize::PairsWrap};
arg_enum! {
@@ -30,7 +30,8 @@ struct Cli {
main!(|args: Cli, log_level: verbosity| {
let content = read_file(args.file)?;
let parsed = RstParser::parse(Rule::doc, &content)?;
+ let stdout = std::io::stdout();
match args.format {
- Format::json => println!("{}", parsed.to_string())
+ Format::json => serde_json::to_writer(stdout, &PairsWrap(parsed))?,
}
});
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 2ae47cb..26470e8 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -1,10 +1,11 @@
pub mod token;
+pub mod serialize;
#[allow(unused_imports)]
use pest::consumes_to;
#[allow(unused_imports)]
use pest::parses_to;
-use pest_derive::*;
+use pest_derive::Parser;
#[derive(Parser)]
#[grammar = "rst.pest"]
diff --git a/src/parser/serialize.rs b/src/parser/serialize.rs
new file mode 100644
index 0000000..260084f
--- /dev/null
+++ b/src/parser/serialize.rs
@@ -0,0 +1,36 @@
+use pest::{RuleType, iterators::{Pair, Pairs}};
+use serde::{
+ Serialize,
+ Serializer,
+ ser::{
+ SerializeSeq,
+ SerializeStruct,
+ },
+};
+
+pub struct PairsWrap<'i, R>(pub Pairs<'i, R>);
+pub struct PairWrap <'i, R>(pub Pair <'i, R>);
+
+impl<'i, R> Serialize for PairsWrap<'i, R> where R: RuleType {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
+ let mut seq = serializer.serialize_seq(None)?;
+ for pair in self.0.clone() {
+ seq.serialize_element(&PairWrap(pair))?;
+ }
+ seq.end()
+ }
+}
+
+impl<'i, R> Serialize for PairWrap<'i, R> where R: RuleType {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
+ let mut state = serializer.serialize_struct("Pair", 3)?;
+ state.serialize_field("rule", &format!("{:?}", self.0.as_rule()))?;
+ let tokens: Vec<_> = self.0.clone().tokens().collect();
+ if tokens.len() > 2 {
+ state.serialize_field("inner", &PairsWrap(self.0.clone().into_inner()))?;
+ } else {
+ state.serialize_field("content", self.0.as_str())?;
+ }
+ state.end()
+ }
+}
diff --git a/src/rst.pest b/src/rst.pest
index f087c2e..9f92ef7 100644
--- a/src/rst.pest
+++ b/src/rst.pest
@@ -444,7 +444,7 @@ code = { ticks_2 ~ ( (!"`" ~ nonspacechar)+ | "_" | !ticks_2 ~ "`" | !(sp ~ tick
raw_html = { (html_comment | html_block_script | html_tag) }
-blank_line = { sp ~ NEWLINE }
+blank_line = _{ sp ~ NEWLINE }
quoted = {
"\"" ~ (!"\"" ~ ANY)* ~ "\"" |
@@ -483,16 +483,16 @@ hex_entity = { "&#" ~ ("X"|"x") ~ ('0'..'9' | 'a'..'f' | 'A'..'F')+ ~ ";" }
dec_entity = { "&#" ~ ASCII_DIGIT+ ~ ";" }
char_entity = { "&" ~ ASCII_ALPHANUMERIC+ ~ ";" }
-nonindent_space = { " " | " " | "" }
-indent = { "\t" | " " }
+nonindent_space = _{ " " | " " | "" }
+indent = _{ "\t" | " " }
indented_line = { indent ~ line }
optionally_indented_line = { indent? ~ line }
doctest_line = { ">>> " ~ raw_line }
-line = { raw_line }
+line = _{ raw_line }
-raw_line = { (!NEWLINE ~ ANY)* ~ NEWLINE | (!EOI ~ ANY)+ ~ EOI }
+raw_line = _{ (!NEWLINE ~ ANY)* ~ NEWLINE | (!EOI ~ ANY)+ ~ EOI }
skip_block = {
html_block |