From: Huck Boles Date: Wed, 3 May 2023 19:13:51 +0000 (-0500) Subject: parser core X-Git-Url: https://git.huck.website/?a=commitdiff_plain;h=59589f044ae27a154bdb43d3d8de1dc92453bee6;p=metaforge.git parser core --- diff --git a/src/lib.rs b/src/lib.rs index e69de29..7b33542 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -0,0 +1,12 @@ +extern crate pest; +#[macro_use] +extern crate pest_derive; + +mod metafile; +mod parser; + +pub use metafile::*; +pub use parser::*; + +#[cfg(test)] +mod tests; diff --git a/src/main.rs b/src/main.rs index e7a11a9..b648bd2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,7 @@ +extern crate pest; +#[macro_use] +extern crate pest_derive; + fn main() { println!("Hello, world!"); } diff --git a/src/metafile.rs b/src/metafile.rs new file mode 100644 index 0000000..f1f3114 --- /dev/null +++ b/src/metafile.rs @@ -0,0 +1,30 @@ +use std::collections::HashMap; + +pub struct MetaFile<'a> { + pub variables: HashMap<&'a str, &'a str>, + pub arrays: HashMap<&'a str, Vec<&'a str>>, + pub patterns: HashMap<&'a str, &'a str>, + pub source: Vec>, +} + +impl<'a> MetaFile<'a> { + pub fn new() -> MetaFile<'a> { + MetaFile { + variables: HashMap::new(), + arrays: HashMap::new(), + patterns: HashMap::new(), + source: Vec::new(), + } + } +} + +pub enum Source<'a> { + Str(&'a str), + Sub(Substitution<'a>), +} + +pub enum Substitution<'a> { + Variable(&'a str), + Array(&'a str), + Pattern(&'a str), +} diff --git a/src/parser.rs b/src/parser.rs index e69de29..4f42021 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -0,0 +1,3 @@ +mod parse; + +pub use parse::*; diff --git a/src/parser/meta.pest b/src/parser/meta.pest index f673b18..59ae711 100644 --- a/src/parser/meta.pest +++ b/src/parser/meta.pest @@ -22,7 +22,7 @@ key_chars = @{ (ASCII_ALPHANUMERIC | "_" | ".")* } key = @{ key_chars } value = ${ string | array | "BLANK" | "DEFAULT" } -assign = _{ key ~ "=" ~ value } +assign = { key ~ "=" ~ value } def_block = _{ sigil ~ assign* ~ "}" } var_def = { &("$") ~ def_block } diff --git a/src/parser/parse.rs b/src/parser/parse.rs new file mode 100644 index 0000000..f87e9df --- /dev/null +++ b/src/parser/parse.rs @@ -0,0 +1,115 @@ +use crate::{MetaFile, Source, Substitution}; +use color_eyre::Result; +use pest::{ + iterators::{Pair, Pairs}, + Parser, +}; +use std::collections::HashMap; + +#[derive(Parser)] +#[grammar = "parser/meta.pest"] +pub struct MetaParser; + +pub fn parse_file(file: &str) -> Result { + let meta_source = MetaParser::parse(Rule::file, file)?.next().unwrap(); + + Ok(parse_pair(meta_source)) +} + +pub fn parse_pair(pair: Pair) -> MetaFile { + let mut meta_file = MetaFile::new(); + + if Rule::file == pair.as_rule() { + match pair.as_rule() { + Rule::source => meta_file.source = parse_source(pair.into_inner()), + Rule::var_def => meta_file.variables = parse_defs(pair.into_inner()), + Rule::arr_def => meta_file.arrays = parse_array_defs(pair.into_inner()), + Rule::pat_def => meta_file.patterns = parse_defs(pair.into_inner()), + // anything else is either hidden or children of previous nodes and will be dealt with + // in respective parse functions + _ => unreachable!(), + } + } + + meta_file +} + +fn parse_defs<'a>(pairs: Pairs<'a, Rule>) -> HashMap<&'a str, &'a str> { + let mut map = HashMap::new(); + for pair in pairs { + if Rule::assign == pair.as_rule() { + let (key, val) = parse_assign(pair); + map.insert(key, val); + } + } + map +} + +fn parse_array_defs<'a>(pairs: Pairs<'a, Rule>) -> HashMap<&'a str, Vec<&'a str>> { + let mut map = HashMap::new(); + for pair in pairs { + if Rule::assign == pair.as_rule() { + let (key, val) = parse_assign_array(pair); + map.insert(key, val); + } + } + map +} + +fn parse_source<'a>(pairs: Pairs) -> Vec { + let mut vec: Vec = Vec::new(); + + for pair in pairs { + match pair.as_rule() { + Rule::var_sub => vec.push(Source::Sub(Substitution::Variable(pair.as_str()))), + Rule::arr_sub => vec.push(Source::Sub(Substitution::Array(pair.as_str()))), + Rule::pat_sub => vec.push(Source::Sub(Substitution::Pattern(pair.as_str()))), + Rule::char_seq => vec.push(Source::Str(pair.as_str())), + // anything that isn't a substitution is a char_seq inside source + _ => unreachable!(), + } + } + + vec +} + +fn parse_assign<'a>(pair: Pair<'a, Rule>) -> (&'a str, &'a str) { + let mut key = ""; + let mut val = ""; + for pair in pair.into_inner() { + if Rule::key == pair.as_rule() { + key = pair.as_str(); + } + if Rule::value == pair.as_rule() { + val = pair.as_str(); + } + } + + (key, val) +} + +fn parse_assign_array<'a>(pair: Pair<'a, Rule>) -> (&'a str, Vec<&'a str>) { + let mut key = ""; + let mut val: Vec<&str> = Vec::default(); + for pair in pair.into_inner() { + if Rule::key == pair.as_rule() { + key = pair.as_str(); + } + if Rule::value == pair.as_rule() { + val = parse_array(pair.into_inner()); + } + } + + (key, val) +} + +fn parse_array<'a>(pairs: Pairs<'a, Rule>) -> Vec<&'a str> { + let mut vec: Vec<&str> = Vec::default(); + + for pair in pairs { + if Rule::string == pair.as_rule() { + vec.push(pair.as_str()); + } + } + vec +}