remove command_system_macros

This commit is contained in:
libglfw 2024-11-02 14:55:06 -07:00
parent 737d6d3216
commit b6eec3784d
5 changed files with 93 additions and 176 deletions

View file

@ -1,12 +0,0 @@
[package]
name = "command_system_macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
quote = "1.0"
proc-macro2 = "1.0"
syn = "2.0"

View file

@ -1,151 +0,0 @@
use proc_macro2::{Delimiter, TokenStream, TokenTree, Literal, Span};
use syn::parse::{Parse, ParseStream, Result as ParseResult};
use syn::{parse_macro_input, Token, Ident};
use quote::{quote, quote_spanned};
enum CommandToken {
/// "typed argument" being a member of the `Token` enum in the
/// command parser crate.
///
/// prefixed with `@` in the command macro.
TypedArgument(Ident, Span),
/// interpreted as a literal string in the command input.
///
/// no prefix in the command macro.
Literal(Literal, Span),
}
impl Parse for CommandToken {
fn parse(input: ParseStream) -> ParseResult<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Token![@]) {
// typed argument
input.parse::<Token![@]>()?;
let ident = input.parse::<Ident>()?;
Ok(Self::TypedArgument(ident.clone(), ident.span()))
} else if lookahead.peek(Ident) {
// literal string
let ident = input.parse::<Ident>()?;
let lit = Literal::string(&format!("{ident}"));
Ok(Self::Literal(lit, ident.span()))
} else {
Err(input.error("expected a command token"))
}
}
}
impl Into<TokenStream> for CommandToken {
fn into(self) -> TokenStream {
match self {
Self::TypedArgument(ident, span) => quote_spanned! {span=>
Token::#ident
},
Self::Literal(lit, span) => quote_spanned! {span=>
Token::Value(vec![ #lit.to_string(), ])
},
}.into()
}
}
struct Command {
tokens: Vec<CommandToken>,
help: Literal,
cb: Literal,
}
impl Parse for Command {
fn parse(input: ParseStream) -> ParseResult<Self> {
let mut tokens = Vec::<CommandToken>::new();
loop {
if input.peek(Token![,]) {
break;
}
tokens.push(input.parse::<CommandToken>()?);
}
input.parse::<Token![,]>()?;
let cb_ident = input.parse::<Ident>()?;
let cb = Literal::string(&format!("{cb_ident}"));
input.parse::<Token![,]>()?;
let help = input.parse::<Literal>()?;
Ok(Self {
tokens,
cb,
help,
})
}
}
impl Into<TokenStream> for Command {
fn into(self) -> TokenStream {
let Self { tokens, help, cb } = self;
let tokens = tokens.into_iter().map(Into::into).collect::<Vec<TokenStream>>();
quote! {
Command { tokens: vec![#(#tokens),*], help: #help.to_string(), cb: #cb.to_string() }
}
}
}
#[proc_macro]
pub fn commands(stream: proc_macro::TokenStream) -> proc_macro::TokenStream {
let stream: TokenStream = stream.into();
let mut commands: Vec<TokenStream> = Vec::new();
let mut top_level_tokens = stream.into_iter();
'a: loop {
// "command"
match top_level_tokens.next() {
Some(TokenTree::Ident(ident)) if format!("{ident}") == "command" => {}
None => break 'a,
_ => panic!("contents of commands! macro is invalid"),
}
//
match top_level_tokens.next() {
Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Parenthesis => {
let group_stream: proc_macro::TokenStream = group.stream().into();
commands.push(parse_macro_input!(group_stream as Command).into());
}
_ => panic!("contents of commands! macro is invalid"),
}
// ;
match top_level_tokens.next() {
Some(TokenTree::Punct(punct)) if format!("{punct}") == ";" => {}
_ => panic!("contents of commands! macro is invalid"),
}
}
let command_registrations = commands
.iter()
.map(|v| -> TokenStream { quote! { tree.register_command(#v); }.into() })
.collect::<TokenStream>();
let res = quote! {
lazy_static::lazy_static! {
static ref COMMAND_TREE: TreeBranch = {
let mut tree = TreeBranch {
current_command_key: None,
possible_tokens: vec![],
branches: HashMap::new(),
};
#command_registrations
tree.sort_tokens();
// println!("{{tree:#?}}");
tree
};
}
};
// panic!("{res}");
res.into()
}

View file

@ -8,7 +8,6 @@ crate-type = ["cdylib"]
[dependencies]
lazy_static = { workspace = true }
command_system_macros = { path = "../command_system_macros" }
uniffi = { version = "0.25" }

View file

@ -9,8 +9,6 @@ mod string;
mod token;
use token::*;
use command_system_macros::commands;
// todo!: move all this stuff into a different file
// lib.rs should just have exported symbols and command definitions
@ -69,23 +67,105 @@ impl TreeBranch {
}
}
#[derive(Clone)]
struct Command {
tokens: Vec<Token>,
help: String,
cb: String,
}
// todo: aliases
// todo: categories
commands! {
command(help, help, "Shows the help command");
fn command(tokens: &[&Token], help: &str, cb: &str) -> Command {
Command {
tokens: tokens.iter().map(|&x| x.clone()).collect(),
help: help.to_string(),
cb: cb.to_string(),
}
}
command(member new, member_new, "Creates a new system member");
command(member @MemberRef, member_show, "Shows information about a member");
command(member @MemberRef description, member_desc_show, "Shows a member's description");
command(member @MemberRef description @FullString, member_desc_update, "Changes a member's description");
command(member @MemberRef privacy, member_privacy_show, "Displays a member's current privacy settings");
command(member @MemberRef privacy @MemberPrivacyTarget @PrivacyLevel, member_privacy_update, "Changes a member's privacy settings");
mod commands {
use super::Token;
use super::command;
use super::Token::*;
fn cmd(value: &str) -> Token {
Token::Value(vec![value.to_string()])
}
pub fn cmd_with_alias(value: &[&str]) -> Token {
Token::Value(value.iter().map(|x| x.to_string()).collect())
}
// todo: this needs to have less ampersands -alyssa
pub fn happy() -> Vec<super::Command> {
let system = &cmd_with_alias(&["system", "s"]);
let member = &cmd_with_alias(&["member", "m"]);
let description = &cmd_with_alias(&["description", "desc"]);
let privacy = &cmd_with_alias(&["privacy", "priv"]);
vec![
command(&[&cmd("help")], "help", "Shows the help command"),
command(
&[system],
"system_show",
"Shows information about your system",
),
command(&[system, &cmd("new")], "system_new", "Creates a new system"),
command(
&[member, &cmd_with_alias(&["new", "n"])],
"member_new",
"Creates a new system member",
),
command(
&[member, &MemberRef],
"member_show",
"Shows information about a member",
),
command(
&[member, &MemberRef, description],
"member_desc_show",
"Shows a member's description",
),
command(
&[member, &MemberRef, description, &FullString],
"member_desc_update",
"Changes a member's description",
),
command(
&[member, &MemberRef, privacy],
"member_privacy_show",
"Displays a member's current privacy settings",
),
command(
&[
member,
&MemberRef,
privacy,
&MemberPrivacyTarget,
&PrivacyLevel,
],
"member_privacy_update",
"Changes a member's privacy settings",
),
]
}
}
lazy_static::lazy_static! {
static ref COMMAND_TREE: TreeBranch = {
let mut tree = TreeBranch {
current_command_key: None,
possible_tokens: vec![],
branches: HashMap::new(),
};
commands::happy().iter().for_each(|x| tree.register_command(x.clone()));
tree.sort_tokens();
// println!("{{tree:#?}}");
tree
};
}
pub enum CommandResult {

View file

@ -3,6 +3,7 @@ use std::collections::HashMap;
lazy_static::lazy_static! {
// Dictionary of (left, right) quote pairs
// Each char in the string is an individual quote, multi-char strings imply "one of the following chars"
// Certain languages can have quote patterns that have a different character for open and close
pub static ref QUOTE_PAIRS: HashMap<String, String> = {
let mut pairs = HashMap::new();