-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds an option to apply functions over regular arguments. For now only upper() and lower() functions are available.
- Loading branch information
1 parent
acdf1b5
commit 05ba64c
Showing
10 changed files
with
184 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
use quote::ToTokens; | ||
use syn::parse::discouraged::Speculative; | ||
use syn::parse::{Parse, ParseStream}; | ||
|
||
/// Argument in form of an identifier, underscore or a string literal. | ||
#[derive(Debug)] | ||
pub struct Arg { | ||
pub(super) value: String, | ||
} | ||
|
||
impl Parse for Arg { | ||
fn parse(input: ParseStream) -> syn::Result<Self> { | ||
let value: String; | ||
if input.peek(syn::Ident) && !input.peek2(syn::token::Paren) { | ||
let ident = input.parse::<syn::Ident>()?; | ||
value = ident.to_string(); | ||
} else if input.parse::<syn::Token![_]>().is_ok() { | ||
value = "_".to_string(); | ||
} else if let Ok(lit_str) = input.parse::<syn::LitStr>() { | ||
value = lit_str.value(); | ||
} else { | ||
return Err(input.error("Expected identifier or _")); | ||
} | ||
Ok(Arg { value }) | ||
} | ||
} | ||
|
||
/// Function call in form of `upper(arg)` or `lower(arg)`. | ||
#[derive(Debug)] | ||
pub enum Func { | ||
Upper(Box<Expr>), | ||
Lower(Box<Expr>), | ||
} | ||
|
||
impl Parse for Func { | ||
fn parse(input: ParseStream) -> syn::Result<Self> { | ||
let call = input.parse::<syn::ExprCall>()?; | ||
let func_name = call.func.to_token_stream().to_string(); | ||
match func_name.as_str() { | ||
"upper" | "lower" => { | ||
let args = call.args; | ||
if args.len() != 1 { | ||
return Err(input.error("Expected 1 argument")); | ||
} | ||
let arg = syn::parse2::<Expr>(args.into_token_stream())?; | ||
match func_name.as_str() { | ||
"upper" => Ok(Func::Upper(Box::new(arg))), | ||
"lower" => Ok(Func::Lower(Box::new(arg))), | ||
_ => unreachable!(), | ||
} | ||
} | ||
_ => Err(input.error(r#"Expected "upper()" or "lower()""#)), | ||
} | ||
} | ||
} | ||
|
||
/// Expression in form of an argument or a function call. | ||
#[derive(Debug)] | ||
pub(super) enum Expr { | ||
ArgExpr { value: Box<Arg> }, | ||
FuncCallExpr { value: Box<Func> }, | ||
} | ||
|
||
impl Parse for Expr { | ||
fn parse(input: ParseStream) -> syn::Result<Self> { | ||
let fork = input.fork(); | ||
if let Ok(func) = fork.parse::<Func>() { | ||
input.advance_to(&fork); | ||
Ok(Expr::FuncCallExpr { | ||
value: Box::new(func), | ||
}) | ||
} else if let Ok(arg) = input.parse::<Arg>() { | ||
Ok(Expr::ArgExpr { | ||
value: Box::new(arg), | ||
}) | ||
} else { | ||
Err(input.error("Expected argument or function call")) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use crate::core::{Arg, Expr, Func}; | ||
|
||
/// A syntactic structure that can be evaluated. | ||
pub trait Eval { | ||
fn eval(&self) -> String; | ||
} | ||
|
||
impl Eval for Arg { | ||
fn eval(&self) -> String { | ||
self.value.clone() | ||
} | ||
} | ||
|
||
impl Eval for Func { | ||
fn eval(&self) -> String { | ||
match self { | ||
Func::Upper(expr) => expr.eval().to_uppercase(), | ||
Func::Lower(expr) => expr.eval().to_lowercase(), | ||
} | ||
} | ||
} | ||
|
||
impl Eval for Expr { | ||
fn eval(&self) -> String { | ||
match self { | ||
Expr::ArgExpr { value } => value.eval(), | ||
Expr::FuncCallExpr { value } => value.eval(), | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
use compose_idents::compose_idents; | ||
|
||
compose_idents!(my_var = [upper("foo"), lower(_), upper(bar)]; { | ||
const my_var: u32 = 42; | ||
}); | ||
|
||
fn main() { | ||
assert_eq!(FOO_BAR, 42); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
use compose_idents::compose_idents; | ||
|
||
compose_idents!(my_var = [lower(FOO), _, lower(BAR)]; { | ||
const my_var: u32 = 42; | ||
}); | ||
|
||
fn main() { | ||
assert_eq!(foo_bar, 42); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
use compose_idents::compose_idents; | ||
|
||
compose_idents!(my_var = [lower(upper(FOO))]; { | ||
const my_var: u32 = 42; | ||
}); | ||
|
||
fn main() { | ||
assert_eq!(foo, 42); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
use compose_idents::compose_idents; | ||
|
||
compose_idents!(my_var = [upper(foo), _, upper(bar)]; { | ||
const my_var: u32 = 42; | ||
}); | ||
|
||
fn main() { | ||
assert_eq!(FOO_BAR, 42); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters