Try generating named functions via proc macros
This commit is contained in:
Generated
+3
-2
@@ -132,6 +132,7 @@ name = "peg_macro"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -217,9 +218,9 @@ checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.100"
|
||||
version = "2.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
||||
@@ -8,3 +8,4 @@ proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0.40"
|
||||
syn = "2.0.101"
|
||||
|
||||
+53
-1
@@ -1,8 +1,39 @@
|
||||
use proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
Ident, Token,
|
||||
parse::{Parse, ParseStream},
|
||||
parse_macro_input,
|
||||
punctuated::Punctuated,
|
||||
};
|
||||
|
||||
struct Grammar {
|
||||
rules: Punctuated<Rule, Token![;]>,
|
||||
}
|
||||
|
||||
struct Rule {
|
||||
name: Ident,
|
||||
}
|
||||
|
||||
impl Parse for Grammar {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
Ok(Grammar {
|
||||
rules: Punctuated::parse_terminated(input)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Parse for Rule {
|
||||
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||
let result = Self {
|
||||
name: input.parse()?,
|
||||
};
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn grammar(ts: TokenStream) -> TokenStream {
|
||||
pub fn grammar_old(ts: TokenStream) -> TokenStream {
|
||||
let token = ts.into_iter().next().expect("must have at least one token");
|
||||
let result = match token {
|
||||
proc_macro::TokenTree::Literal(literal) => {
|
||||
@@ -25,3 +56,24 @@ pub fn grammar(ts: TokenStream) -> TokenStream {
|
||||
|
||||
quote! { println!("Hello, world! {:?}", #result); }.into()
|
||||
}
|
||||
|
||||
#[proc_macro]
|
||||
pub fn grammar(ts: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(ts as Grammar);
|
||||
let fns: Vec<_> = input
|
||||
.rules
|
||||
.iter()
|
||||
.map(|r| {
|
||||
let fn_name = &r.name;
|
||||
quote! {
|
||||
fn #fn_name() -> String {
|
||||
"I'm a generated function!".into()
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
quote! {
|
||||
#(#fns)*
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
+3
-3
@@ -6,14 +6,14 @@ mod world;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use labels::labels::print_labels;
|
||||
use peg_macro::grammar;
|
||||
use peg_macro::grammar_old;
|
||||
use preprocess::eval::Context;
|
||||
use std::{env, error::Error, fs, path::PathBuf, process::exit};
|
||||
use world::World;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
grammar!(123);
|
||||
grammar!("abc");
|
||||
grammar_old!(123);
|
||||
grammar_old!("abc");
|
||||
|
||||
let args: Vec<String> = env::args().collect();
|
||||
if args.len() != 2 {
|
||||
|
||||
@@ -1,6 +1,91 @@
|
||||
use peg_macro::grammar;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Foo {
|
||||
Bar(usize),
|
||||
Baz(String),
|
||||
}
|
||||
|
||||
pub struct ParseState {
|
||||
pub input: String,
|
||||
pub offset: usize,
|
||||
}
|
||||
|
||||
pub struct Savepoint {
|
||||
offset: usize,
|
||||
}
|
||||
|
||||
impl ParseState {
|
||||
pub fn new(s: &str) -> Self {
|
||||
Self {
|
||||
input: s.into(),
|
||||
offset: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(&self) -> Savepoint {
|
||||
Savepoint {
|
||||
offset: self.offset,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn restore(&mut self, save: Savepoint) {
|
||||
self.offset = save.offset;
|
||||
}
|
||||
|
||||
pub fn literal(&mut self, s: &str) -> bool {
|
||||
if self.input[self.offset..].starts_with(s) {
|
||||
self.offset += s.len();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_foo(p: &mut ParseState) -> bool {
|
||||
let save = p.save();
|
||||
if !parse_f(p) {
|
||||
return false;
|
||||
}
|
||||
if !parse_oo(p) {
|
||||
p.restore(save);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn parse_f(p: &mut ParseState) -> bool {
|
||||
p.literal("f")
|
||||
}
|
||||
|
||||
fn parse_oo(p: &mut ParseState) -> bool {
|
||||
p.literal("oo")
|
||||
}
|
||||
|
||||
grammar! {
|
||||
generated_this;
|
||||
generated_that;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use insta::assert_snapshot;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_parser() {
|
||||
let mut p = ParseState::new("foo");
|
||||
assert!(parse_foo(&mut p));
|
||||
let mut p = ParseState::new("fee");
|
||||
assert!(!parse_foo(&mut p));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_generated() {
|
||||
assert_snapshot!(generated_this(), @"I'm a generated function!");
|
||||
assert_snapshot!(generated_that(), @"I'm a generated function!");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user