commit d712e4897a92db63d5737ae8500fc2e10100d390
parent 2748bee7863eec92d6fad7df5462766a3cde3560
Author: Demonstrandum <samuel@knutsen.co>
Date: Sat, 7 Dec 2024 22:35:24 +0000
Added %toml support.
Diffstat:
5 files changed, 235 insertions(+), 18 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -117,6 +117,12 @@ dependencies = [
]
[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
name = "formatx"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -138,12 +144,18 @@ dependencies = [
]
[[package]]
+name = "hashbrown"
+version = "0.15.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+
+[[package]]
name = "hashlink"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
dependencies = [
- "hashbrown",
+ "hashbrown 0.14.5",
]
[[package]]
@@ -170,6 +182,16 @@ dependencies = [
]
[[package]]
+name = "indexmap"
+version = "2.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.15.2",
+]
+
+[[package]]
name = "js-sys"
version = "0.3.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -285,6 +307,7 @@ dependencies = [
"markdown",
"regex",
"seam_argparse_proc_macro",
+ "toml",
"unicode-width",
"yaml-rust2",
]
@@ -299,6 +322,35 @@ dependencies = [
]
[[package]]
+name = "serde"
+version = "1.0.215"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.215"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -316,6 +368,40 @@ dependencies = [
]
[[package]]
+name = "toml"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
name = "unicode-id"
version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -534,6 +620,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
[[package]]
+name = "winnow"
+version = "0.6.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "yaml-rust2"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/crates/seam/Cargo.toml b/crates/seam/Cargo.toml
@@ -32,3 +32,4 @@ regex = "1.10.5"
glob = "0.3.1"
markdown = "1.0.0-alpha.21"
yaml-rust2 = "0.9.0"
+toml = "0.8.19"
diff --git a/crates/seam/src/parse/expander.rs b/crates/seam/src/parse/expander.rs
@@ -697,7 +697,7 @@ impl<'a> Expander<'a> {
extract_frontmatter()?;
Ok(Box::new([]))
},
- Only::Content => to_html(),
+ Only::Content => to_html(),
Only::Both => {
// Ignore any errors if no frontmatter exists.
let _ = extract_frontmatter();
@@ -1438,15 +1438,6 @@ fn expand_yaml<'a>(context: &Expander<'a>, text: &str, sep: &str, site: &Site<'a
impl<'a, 'b> yaml::parser::EventReceiver for EventSink<'a, 'b> {
fn on_event(&mut self, event: yaml::Event) {
- /*
- eprintln!("---");
- eprintln!("event: {:?}", event);
- eprintln!("mode: {:?}", self.mode);
- eprintln!("defn: {:?}", self.defining);
- eprintln!("prefix: {:?}", self.prefix);
- eprintln!("nodes: [{}]", self.nodes.iter().map(|node| node.to_string()).collect::<Vec<String>>().join("; "));
- eprintln!("parent: {:?}", self.parent);
- */
let the_dreaded_rparen = crate::parse::tokens::Token::new(
crate::parse::tokens::Kind::RParen,
")", "", self.site.clone()
@@ -1606,7 +1597,7 @@ fn expand_yaml<'a>(context: &Expander<'a>, text: &str, sep: &str, site: &Site<'a
yaml::parser::Parser::new_from_str(text)
.load(&mut sink, false)
.map_err(|err| ExpansionError(
- format!("Failed to parse yaml: {}", err),
+ format!("Failed to parse YAML: {}", err),
site.to_owned()
))?;
@@ -1615,5 +1606,135 @@ fn expand_yaml<'a>(context: &Expander<'a>, text: &str, sep: &str, site: &Site<'a
/// See [`expand_yaml`], but for the TOML configuration language instead.
fn expand_toml<'a>(context: &Expander<'a>, text: &str, sep: &str, site: &Site<'a>) -> Result<ParseTree<'a>, ExpansionError<'a>> {
- Ok(Box::new([]))
+ use toml;
+
+ let table: toml::Table = text.parse()
+ .map_err(|err| ExpansionError(
+ format!("Failed to parse TOML: {}", err),
+ site.to_owned()
+ ))?;
+
+ struct Traverser<'a, 'b> {
+ context: &'b Expander<'a>,
+ site: Site<'a>,
+ sep: String,
+ prefix: Vec<String>,
+ the_dreaded_rparen: crate::parse::tokens::Token<'a>,
+ }
+
+ fn whitespace(leading: bool) -> String {
+ if leading { String::new() } else { String::from(" ") }
+ }
+
+ impl<'a, 'b> Traverser<'a, 'b> {
+ fn qualified(&self, name: &str) -> String {
+ if self.prefix.is_empty() {
+ name.to_owned()
+ } else {
+ let prefix = self.prefix.join(&self.sep);
+ format!("{}{}{}", prefix, self.sep, name)
+ }
+ }
+
+ fn define(&self, name: String, node: ParseNode<'a>) {
+ let qualified = self.qualified(&name);
+ self.context.insert_variable(qualified, Rc::new(Macro {
+ name,
+ params: Box::new([]),
+ body: Box::new([node]),
+ }));
+ }
+
+ fn traverse_value(&mut self, value: toml::Value, leading: bool) -> ParseNode<'a> {
+ match value {
+ toml::Value::Array(array) => self.traverse_array(array, leading),
+ toml::Value::Table(table) => self.traverse_table(table, leading),
+ toml::Value::String(string) => ParseNode::String(Node {
+ value: string,
+ site: self.site,
+ leading_whitespace: whitespace(leading),
+ }),
+ toml::Value::Integer(int) => ParseNode::Number(Node {
+ value: format!("{}", int),
+ site: self.site,
+ leading_whitespace: whitespace(leading),
+ }),
+ toml::Value::Float(float) => ParseNode::Number(Node {
+ value: format!("{}", float),
+ site: self.site,
+ leading_whitespace: whitespace(leading),
+ }),
+ toml::Value::Datetime(date) => ParseNode::Number(Node {
+ value: format!("{}", date),
+ site: self.site,
+ leading_whitespace: whitespace(leading),
+ }),
+ toml::Value::Boolean(boolean) => ParseNode::Number(Node {
+ value: format!("{}", boolean),
+ site: self.site,
+ leading_whitespace: whitespace(leading),
+ }),
+ }
+ }
+
+ fn traverse_array(&mut self, array: Vec<toml::Value>, leading: bool) -> ParseNode<'a> {
+ let mut first = true;
+ let mut expanded = vec![];
+ let mut i = 0;
+ for value in array {
+ let name = format!("{}", i);
+ self.prefix.push(name.clone());
+ let node = self.traverse_value(value, first);
+ self.prefix.pop();
+ self.define(name, node.clone());
+ expanded.push(node);
+ first = false;
+ i += 1;
+ }
+ ParseNode::List {
+ nodes: expanded.into_boxed_slice(),
+ site: self.site,
+ end_token: self.the_dreaded_rparen,
+ leading_whitespace: whitespace(leading)
+ }
+ }
+
+ fn traverse_table(&mut self, table: toml::Table, leading: bool) -> ParseNode<'a> {
+ let mut nodes = vec![];
+ let mut first = true;
+ for (keyword, value) in table {
+ self.prefix.push(keyword.clone());
+ let node = self.traverse_value(value, false);
+ self.prefix.pop();
+ self.define(keyword.clone(), node.clone());
+ nodes.push(ParseNode::Attribute {
+ keyword,
+ node: Box::new(node),
+ site: self.site,
+ leading_whitespace: whitespace(first),
+ });
+ first = false;
+ }
+ let nodes = nodes.into_boxed_slice();
+ ParseNode::List {
+ nodes,
+ site: self.site,
+ end_token: self.the_dreaded_rparen,
+ leading_whitespace: whitespace(leading)
+ }
+ }
+ }
+
+ Ok(Box::new([
+ Traverser {
+ context,
+ site: *site,
+ prefix: Vec::new(),
+ sep: sep.to_owned(),
+ the_dreaded_rparen: crate::parse::tokens::Token::new(
+ crate::parse::tokens::Kind::RParen,
+ ")", "", *site
+ ),
+ }.traverse_table(table, true)
+ ]))
}
diff --git a/crates/seam/src/parse/parser.rs b/crates/seam/src/parse/parser.rs
@@ -223,9 +223,9 @@ impl<'a> ParseNode<'a> {
Self::Symbol(node)
| Self::Number(node)
| Self::String(node)
- | Self::Raw(node) => node.site.clone(),
- Self::List { site, .. } => site.clone(),
- Self::Attribute { site, .. } => site.clone(),
+ | Self::Raw(node) => node.site,
+ Self::List { site, .. } => *site,
+ Self::Attribute { site, .. } => *site,
}
}
diff --git a/crates/seam/src/parse/tokens.rs b/crates/seam/src/parse/tokens.rs
@@ -5,7 +5,7 @@ use unicode_width::UnicodeWidthStr;
/// Including references to the source-code and path, line number, bytes offsets
/// within the file, including from start of line, and the number of
/// bytes it occupies in the source.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Copy)]
pub struct Site<'a> {
pub source: &'a str,
pub source_code: &'a str,
@@ -128,7 +128,7 @@ pub enum Kind {
Keyword,
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, Copy)]
pub struct Token<'a> {
pub kind: Kind,
pub value: &'a str,