2021-08-31 14:19:29 +00:00
|
|
|
#![feature(proc_macro_span)]
|
|
|
|
|
2021-08-13 03:58:23 +00:00
|
|
|
use syndicate::value::IOValue;
|
|
|
|
use syndicate::value::NestedValue;
|
|
|
|
use syndicate::value::Value;
|
|
|
|
use syndicate::value::text::iovalue_from_str;
|
|
|
|
|
2021-08-13 10:51:20 +00:00
|
|
|
use proc_macro2::Span;
|
|
|
|
use proc_macro2::TokenStream;
|
2021-08-13 03:58:23 +00:00
|
|
|
|
|
|
|
use quote::quote;
|
|
|
|
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
|
|
|
use syn::parse_macro_input;
|
|
|
|
use syn::ExprLit;
|
|
|
|
use syn::Ident;
|
|
|
|
use syn::Lit;
|
|
|
|
use syn::LitByteStr;
|
|
|
|
|
2021-09-19 14:53:37 +00:00
|
|
|
mod dur;
|
2021-08-31 14:19:29 +00:00
|
|
|
mod pat;
|
2021-09-19 14:53:37 +00:00
|
|
|
mod stx;
|
2021-08-31 14:19:29 +00:00
|
|
|
mod val;
|
|
|
|
|
|
|
|
use pat::lit;
|
|
|
|
|
2021-08-28 16:50:55 +00:00
|
|
|
enum SymbolVariant<'a> {
|
|
|
|
Normal(&'a str),
|
2024-02-03 14:24:28 +00:00
|
|
|
#[allow(dead_code)] // otherwise we get 'warning: field `0` is never read'
|
2021-08-28 16:50:55 +00:00
|
|
|
Binder(&'a str),
|
|
|
|
Substitution(&'a str),
|
|
|
|
Discard,
|
|
|
|
}
|
|
|
|
|
2021-08-13 10:51:20 +00:00
|
|
|
fn compile_sequence_members(vs: &[IOValue]) -> Vec<TokenStream> {
|
2021-08-31 14:19:29 +00:00
|
|
|
vs.iter().enumerate().map(|(i, f)| {
|
2021-08-13 10:51:20 +00:00
|
|
|
let p = compile_pattern(f);
|
2021-08-31 14:19:29 +00:00
|
|
|
quote!((#i .into(), #p))
|
2021-08-13 10:51:20 +00:00
|
|
|
}).collect::<Vec<_>>()
|
2021-08-13 03:58:23 +00:00
|
|
|
}
|
|
|
|
|
2021-08-28 16:50:55 +00:00
|
|
|
fn analyze_symbol(s: &str, allow_binding_and_substitution: bool) -> SymbolVariant {
|
|
|
|
if !allow_binding_and_substitution {
|
|
|
|
SymbolVariant::Normal(s)
|
|
|
|
} else if s.starts_with("$") {
|
|
|
|
SymbolVariant::Binder(&s[1..])
|
|
|
|
} else if s.starts_with("=") {
|
|
|
|
SymbolVariant::Substitution(&s[1..])
|
|
|
|
} else if s == "_" {
|
|
|
|
SymbolVariant::Discard
|
|
|
|
} else {
|
|
|
|
SymbolVariant::Normal(s)
|
|
|
|
}
|
|
|
|
}
|
2021-08-13 10:43:34 +00:00
|
|
|
|
2021-08-28 16:50:55 +00:00
|
|
|
struct ValueCompiler {
|
|
|
|
allow_binding_and_substitution: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ValueCompiler {
|
|
|
|
fn for_patterns() -> Self {
|
|
|
|
ValueCompiler {
|
|
|
|
allow_binding_and_substitution: false,
|
2021-08-13 11:11:37 +00:00
|
|
|
}
|
2021-08-28 16:50:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn for_templates() -> Self {
|
|
|
|
ValueCompiler {
|
|
|
|
allow_binding_and_substitution: true,
|
2021-08-13 11:11:37 +00:00
|
|
|
}
|
2021-08-28 16:50:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn compile(&self, v: &IOValue) -> TokenStream {
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
let V_: TokenStream = quote!(syndicate::value);
|
|
|
|
|
|
|
|
let walk = |w| self.compile(w);
|
|
|
|
|
|
|
|
match v.value() {
|
|
|
|
Value::Boolean(b) =>
|
|
|
|
quote!(#V_::Value::from(#b).wrap()),
|
|
|
|
Value::Double(d) => {
|
|
|
|
let d = d.0;
|
|
|
|
quote!(#V_::Value::from(#d).wrap())
|
|
|
|
}
|
|
|
|
Value::SignedInteger(i) => {
|
|
|
|
let i = i128::try_from(i).expect("Literal integer out-of-range");
|
|
|
|
quote!(#V_::Value::from(#i).wrap())
|
|
|
|
}
|
|
|
|
Value::String(s) =>
|
|
|
|
quote!(#V_::Value::from(#s).wrap()),
|
|
|
|
Value::ByteString(bs) => {
|
|
|
|
let bs = LitByteStr::new(bs, Span::call_site());
|
|
|
|
quote!(#V_::Value::from(#bs).wrap())
|
|
|
|
}
|
|
|
|
Value::Symbol(s) => match analyze_symbol(&s, self.allow_binding_and_substitution) {
|
|
|
|
SymbolVariant::Normal(s) =>
|
|
|
|
quote!(#V_::Value::symbol(#s).wrap()),
|
|
|
|
SymbolVariant::Binder(_) |
|
|
|
|
SymbolVariant::Discard =>
|
|
|
|
panic!("Binding/Discard not supported here"),
|
|
|
|
SymbolVariant::Substitution(s) => {
|
|
|
|
let i = Ident::new(s, Span::call_site());
|
|
|
|
quote!(#i)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Value::Record(r) => {
|
|
|
|
let arity = r.arity();
|
|
|
|
let label = walk(r.label());
|
|
|
|
let fs: Vec<_> = r.fields().iter().map(walk).collect();
|
|
|
|
quote!({
|
|
|
|
let mut ___r = #V_::Value::record(#label, #arity);
|
|
|
|
#(___r.fields_vec_mut().push(#fs);)*
|
|
|
|
___r.finish().wrap()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
Value::Sequence(vs) => {
|
|
|
|
let vs: Vec<_> = vs.iter().map(walk).collect();
|
|
|
|
quote!(#V_::Value::from(vec![#(#vs),*]).wrap())
|
|
|
|
}
|
|
|
|
Value::Set(vs) => {
|
|
|
|
let vs: Vec<_> = vs.iter().map(walk).collect();
|
|
|
|
quote!({
|
|
|
|
let mut ___s = #V_::Set::new();
|
|
|
|
#(___s.insert(#vs);)*
|
|
|
|
#V_::Value::from(___s).wrap()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
Value::Dictionary(d) => {
|
|
|
|
let members: Vec<_> = d.iter().map(|(k, v)| {
|
|
|
|
let k = walk(k);
|
|
|
|
let v = walk(v);
|
|
|
|
quote!(___d.insert(#k, #v))
|
|
|
|
}).collect();
|
|
|
|
quote!({
|
|
|
|
let mut ___d = #V_::Map::new();
|
|
|
|
#(#members;)*
|
|
|
|
#V_::Value::from(___d).wrap()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
Value::Embedded(_) =>
|
|
|
|
panic!("Embedded values in compile-time Preserves templates not (yet?) supported"),
|
2021-08-13 11:11:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn compile_pattern(v: &IOValue) -> TokenStream {
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
let P_: TokenStream = quote!(syndicate::schemas::dataspace_patterns);
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
let V_: TokenStream = quote!(syndicate::value);
|
2021-08-27 14:19:14 +00:00
|
|
|
#[allow(non_snake_case)]
|
|
|
|
let MapFromIterator_: TokenStream = quote!(<#V_::Map<_, _> as std::iter::FromIterator<_>>::from_iter);
|
2021-08-13 11:11:37 +00:00
|
|
|
|
|
|
|
match v.value() {
|
2021-08-28 16:50:55 +00:00
|
|
|
Value::Symbol(s) => match analyze_symbol(&s, true) {
|
|
|
|
SymbolVariant::Binder(_) =>
|
2021-08-13 11:11:37 +00:00
|
|
|
quote!(#P_::Pattern::DBind(Box::new(#P_::DBind {
|
|
|
|
pattern: #P_::Pattern::DDiscard(Box::new(#P_::DDiscard))
|
|
|
|
}))),
|
2021-08-28 16:50:55 +00:00
|
|
|
SymbolVariant::Discard =>
|
2021-08-13 11:11:37 +00:00
|
|
|
quote!(#P_::Pattern::DDiscard(Box::new(#P_::DDiscard))),
|
2021-08-28 16:50:55 +00:00
|
|
|
SymbolVariant::Substitution(s) =>
|
|
|
|
lit(Ident::new(s, Span::call_site())),
|
|
|
|
SymbolVariant::Normal(_) =>
|
|
|
|
lit(ValueCompiler::for_patterns().compile(v)),
|
2021-08-13 03:58:23 +00:00
|
|
|
}
|
|
|
|
Value::Record(r) => {
|
|
|
|
match r.label().value().as_symbol() {
|
|
|
|
None => panic!("Record labels in patterns must be symbols"),
|
2021-08-28 16:50:55 +00:00
|
|
|
Some(label) =>
|
2021-12-13 14:43:24 +00:00
|
|
|
if label.starts_with("$") && r.arity() == 1 {
|
2021-08-28 16:50:55 +00:00
|
|
|
let nested = compile_pattern(&r.fields()[0]);
|
|
|
|
quote!(#P_::Pattern::DBind(Box::new(#P_::DBind {
|
|
|
|
pattern: #nested
|
|
|
|
})))
|
2021-08-13 10:43:34 +00:00
|
|
|
} else {
|
2021-08-28 16:50:55 +00:00
|
|
|
let label_stx = if label.starts_with("=") {
|
|
|
|
let id = Ident::new(&label[1..], Span::call_site());
|
|
|
|
quote!(#id)
|
|
|
|
} else {
|
|
|
|
quote!(#V_::Value::symbol(#label).wrap())
|
|
|
|
};
|
|
|
|
let members = compile_sequence_members(r.fields());
|
|
|
|
quote!(#P_::Pattern::DCompound(Box::new(#P_::DCompound::Rec {
|
2021-12-13 14:43:24 +00:00
|
|
|
label: #label_stx,
|
|
|
|
fields: vec![#(#members),*],
|
2021-08-28 16:50:55 +00:00
|
|
|
})))
|
|
|
|
}
|
2021-08-13 03:58:23 +00:00
|
|
|
}
|
|
|
|
}
|
2021-08-13 11:11:37 +00:00
|
|
|
Value::Sequence(vs) => {
|
|
|
|
let members = compile_sequence_members(vs);
|
|
|
|
quote!(#P_::Pattern::DCompound(Box::new(#P_::DCompound::Arr {
|
2021-12-13 14:43:24 +00:00
|
|
|
items: vec![#(#members),*],
|
2021-08-13 11:11:37 +00:00
|
|
|
})))
|
|
|
|
}
|
|
|
|
Value::Set(_) =>
|
|
|
|
panic!("Cannot match sets in patterns"),
|
|
|
|
Value::Dictionary(d) => {
|
|
|
|
let members = d.iter().map(|(k, v)| {
|
2021-08-28 16:50:55 +00:00
|
|
|
let k = ValueCompiler::for_patterns().compile(k);
|
2021-08-13 11:11:37 +00:00
|
|
|
let v = compile_pattern(v);
|
|
|
|
quote!((#k, #v))
|
|
|
|
}).collect::<Vec<_>>();
|
|
|
|
quote!(#P_::Pattern::DCompound(Box::new(#P_::DCompound::Dict {
|
2021-12-13 14:43:24 +00:00
|
|
|
entries: #MapFromIterator_(vec![#(#members),*])
|
2021-08-13 11:11:37 +00:00
|
|
|
})))
|
|
|
|
}
|
2021-08-28 16:50:55 +00:00
|
|
|
_ => lit(ValueCompiler::for_patterns().compile(v)),
|
2021-08-13 03:58:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[proc_macro]
|
2021-08-31 14:19:29 +00:00
|
|
|
pub fn pattern_str(src: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
2021-08-13 03:58:23 +00:00
|
|
|
if let Lit::Str(s) = parse_macro_input!(src as ExprLit).lit {
|
|
|
|
match iovalue_from_str(&s.value()) {
|
|
|
|
Ok(v) => {
|
|
|
|
let e = compile_pattern(&v);
|
|
|
|
// println!("{:#}", &e);
|
2021-08-13 10:51:20 +00:00
|
|
|
return e.into();
|
2021-08-13 03:58:23 +00:00
|
|
|
}
|
|
|
|
Err(_) => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
panic!("Expected literal string containing the pattern and no more");
|
|
|
|
}
|
2021-08-28 16:50:55 +00:00
|
|
|
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn template(src: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
|
|
if let Lit::Str(s) = parse_macro_input!(src as ExprLit).lit {
|
|
|
|
match iovalue_from_str(&s.value()) {
|
|
|
|
Ok(v) => {
|
|
|
|
let e = ValueCompiler::for_templates().compile(&v);
|
|
|
|
// println!("{:#}", &e);
|
|
|
|
return e.into();
|
|
|
|
}
|
|
|
|
Err(_) => (),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
panic!("Expected literal string containing the template and no more");
|
|
|
|
}
|
2021-08-31 14:19:29 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn pattern(src: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
|
|
pat::pattern(src)
|
|
|
|
}
|
2021-09-19 14:53:37 +00:00
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn during(src: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
|
|
dur::during(src)
|
|
|
|
}
|
2022-01-07 16:15:03 +00:00
|
|
|
|
|
|
|
#[proc_macro]
|
|
|
|
pub fn on_message(src: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
|
|
|
dur::on_message(src)
|
|
|
|
}
|