Skip to content

Commit

Permalink
Merge pull request #4 from metaborg/regex
Browse files Browse the repository at this point in the history
Regex
  • Loading branch information
jdonszelmann authored Nov 24, 2023
2 parents 5e7bed6 + bfb2c65 commit 9ff86e7
Show file tree
Hide file tree
Showing 18 changed files with 2,160 additions and 7 deletions.
1 change: 1 addition & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: test
args: --all-features

test-miri:
name: Test Miri
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ Cargo.lock
# MSVC Windows builds of rustc generate these, which store debugging information
*.pdb

.vscode/
.vscode/

*.dot
10 changes: 8 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ resolver = "2"
members = [
"scopegraphs-lib",
"scopegraphs",
"scopegraphs-macros"
"scopegraphs-macros",
"scopegraphs-regular-expressions",
]
default-members = [
"scopegraphs",
"scopegraphs-lib",
"scopegraphs-macros",
"scopegraphs-regular-expressions",
]
default-members = ["scopegraphs", "scopegraphs-lib", "scopegraphs-macros"]
4 changes: 2 additions & 2 deletions scopegraphs-lib/src/scopegraph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl<SCOPE, LABEL, DATA> ScopeGraph<SCOPE, LABEL, DATA> {
/// After this operation, all future calls to [`ScopeGraph::get_data`] on this scope will return the associated data.
///
/// Example:
/// ```no_run
/// ```ignore
/// # use scopegraphs::scopegraph::ScopeGraph;
/// let mut sg : ScopeGraph<i32, i32, i32> = ScopeGraph::new();
/// let data = 42;
Expand All @@ -60,7 +60,7 @@ impl<SCOPE, LABEL, DATA> ScopeGraph<SCOPE, LABEL, DATA> {
/// After this operation, all future calls to [`ScopeGraph::get_edges`] on the source will contain the destination.
///
/// Example:
/// ```no_run
/// ```ignore
/// # use scopegraphs::{scopegraph::ScopeGraph, Label};
///
/// #[derive(Label, Eq, PartialEq, Copy, Clone)]
Expand Down
11 changes: 9 additions & 2 deletions scopegraphs-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,12 @@ proc-macro = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
syn = { version = "2.0.29", features = ["derive"] }
quote = "1.0.33"
syn = { version = "2.0.29", features = ["full"] }
quote = "1.0.33"
scopegraphs-regular-expressions = {path = "../scopegraphs-regular-expressions", features = ["rust-code-emitting", "dot"]}

[dev-dependencies]
scopegraphs = {path="../scopegraphs"}

[features]
dot = ["scopegraphs-regular-expressions/dot"]
29 changes: 29 additions & 0 deletions scopegraphs-macros/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,40 @@
use crate::label::impl_label;
use crate::regex::RegexInput;

use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput};

mod label;
mod regex;

#[proc_macro_derive(Label)]
pub fn label_derive(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
impl_label(input)
}

/// Syntax: `$attrs type $type<$alphabet_type> = regex`.
/// For example:
///
/// ```rust
/// # use std::borrow;
/// use scopegraphs::*;
///
/// pub enum Alphabet {
/// A,
/// B,
/// C,
/// }
/// use Alphabet::*;
///
/// compile_regex!(type Machine<Alphabet> = A* B);
/// assert!(Machine::new().accepts([A, B]));
/// ```
///
/// # Attributes
/// * `#[graph="$path"]` location to put a graphviz dot file representing the generated finite state machine. (only with the `dot` feature)
#[proc_macro]
pub fn compile_regex(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as RegexInput);
input.compile()
}
92 changes: 92 additions & 0 deletions scopegraphs-macros/src/regex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
use std::rc::Rc;

use proc_macro::TokenStream;
use scopegraphs_regular_expressions::Regex;
use syn::parse::{Parse, ParseStream};
use syn::{Attribute, Ident, Meta, Token, Type};

#[cfg(feature = "dot")]
use std::fs::File;
#[cfg(feature = "dot")]
use syn::{Expr, ExprLit, Lit, MetaNameValue};

pub(crate) struct RegexInput {
attrs: Vec<Attribute>,
_type: Token![type],
name: Ident,
_open: Token![<],
alphabet_type: Type,
_close: Token![>],
_equals: Token![=],
regex: Regex,
errors: Vec<syn::Error>,
}

impl Parse for RegexInput {
fn parse(input: ParseStream) -> syn::Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let _type = input.parse()?;
let name = input.parse()?;
let _open = input.parse()?;
let alphabet_type = input.parse()?;
let _close = input.parse()?;
let _equals = input.parse()?;
let (regex, errors) = match input.parse() {
Ok(re) => (re, vec![]),
Err(err) => (Regex::Complement(Rc::new(Regex::EmptySet)), vec![err]),
};
Ok(Self {
attrs,
_type,
name,
_open,
alphabet_type,
_close,
_equals,
regex,
errors,
})
}
}

impl RegexInput {
pub fn compile(self) -> TokenStream {
let mut errors = self.errors;
#[cfg(feature = "dot")]
let mut graph = None;

for i in self.attrs {
let attr = i.meta.clone();
match attr {
#[cfg(feature = "dot")]
Meta::NameValue(MetaNameValue {
path,
value:
Expr::Lit(ExprLit {
lit: Lit::Str(s), ..
}),
..
}) if path.is_ident("graph") => {
graph = Some(s);
}
i => errors.push(syn::Error::new_spanned(i, "unexpected attribute")),
}
}

let compiled = self.regex.compile();

#[cfg(feature = "dot")]
if let Some(path) = graph {
let path = path.value();
let mut f = File::create(&path)
.unwrap_or_else(|e| panic!("can't open dot file for graphing at {path}: {e}"));
compiled
.output_dot(&mut f)
.unwrap_or_else(|e| panic!("failed while graphing at {path}: {e}"));
}

compiled
.emit(&self.name, &self.alphabet_type, errors)
.into()
}
}
17 changes: 17 additions & 0 deletions scopegraphs-regular-expressions/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "scopegraphs-regular-expressions"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
syn = { version = "2.0.29", features = ["full", "extra-traits"] }
quote = { version = "1.0.33" , optional = true}
proc-macro2 = "1.0.69"
thiserror = "1.0.50"

[features]
rust-code-emitting = ["quote"]
pretty-print = ["quote"]
dot = ["pretty-print"]
dynamic = ["quote"]
Loading

0 comments on commit 9ff86e7

Please sign in to comment.