-
-
Save rust-play/a050229041bd8924c1891ab4756827d7 to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
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
use std::borrow::Cow; | |
use std::ops::Deref; | |
pub enum Value<'a> { | |
Int(i32), | |
Str(Cow<'a, str>), | |
} | |
pub struct ExecutionContext<'e> { | |
value: Option<Value<'e>>, | |
} | |
trait HasExecutionContext<'a> { | |
type ExecutionContext: Deref<Target = ExecutionContext<'a>> + 'a; | |
} | |
type ExecutionContextOf<'a, T> = <T as HasExecutionContext<'a>>::ExecutionContext; | |
trait BooleanOperationWithGat: for<'a> HasExecutionContext<'a> { | |
fn execute<'e>(&self, ctx: ExecutionContextOf<'e, Self>) -> bool; | |
} | |
trait ValueOperationWithGat: for<'a> HasExecutionContext<'a> { | |
fn execute<'e: 'e>(&self, ctx: ExecutionContextOf<'e, Self>) -> Value<'e>; | |
} | |
enum ValueExpr { | |
Value, | |
FunctionCall(FunctionCallExpr), | |
} | |
enum ComparisonExpr { | |
StrEq { lhs: ValueExpr, rhs: String }, | |
} | |
enum FunctionCallExpr { | |
Lowercase, | |
} | |
trait Compiler: for<'a> HasExecutionContext<'a> { | |
type BooleanOperation: BooleanOperationWithGat | |
+ for<'a> HasExecutionContext<'a, ExecutionContext = ExecutionContextOf<'a, Self>>; | |
type ValueOperation: ValueOperationWithGat | |
+ for<'a> HasExecutionContext<'a, ExecutionContext = ExecutionContextOf<'a, Self>>; | |
fn compile_comparison_expr( | |
&mut self, | |
comparison_expr: ComparisonExpr, | |
) -> Self::BooleanOperation; | |
fn compile_function_call_expr( | |
&mut self, | |
function_call_expr: FunctionCallExpr, | |
) -> Self::ValueOperation; | |
} | |
impl<'a> HasExecutionContext<'a> for Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> bool> { | |
type ExecutionContext = &'a ExecutionContext<'a>; | |
} | |
impl BooleanOperationWithGat for Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> bool> { | |
#[inline] | |
fn execute<'e>(&self, ctx: ExecutionContextOf<'e, Self>) -> bool { | |
(self)(ctx) | |
} | |
} | |
impl<'a> HasExecutionContext<'a> for Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> Value<'e>> { | |
type ExecutionContext = &'a ExecutionContext<'a>; | |
} | |
impl ValueOperationWithGat for Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> Value<'e>> { | |
#[inline] | |
// the 'e: 'e works around a compiler bug | |
fn execute<'e: 'e>(&self, ctx: ExecutionContextOf<'e, Self>) -> Value<'e> { | |
(self)(ctx) | |
} | |
} | |
struct DefaultCompiler; | |
impl<'a> HasExecutionContext<'a> for DefaultCompiler { | |
type ExecutionContext = &'a ExecutionContext<'a>; | |
} | |
impl Compiler for DefaultCompiler { | |
type BooleanOperation = Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> bool>; | |
type ValueOperation = Box<dyn for<'e> Fn(&'e ExecutionContext<'e>) -> Value<'e>>; | |
fn compile_comparison_expr( | |
&mut self, | |
comparison_expr: ComparisonExpr, | |
) -> Self::BooleanOperation { | |
match comparison_expr { | |
ComparisonExpr::StrEq { lhs, rhs } => { | |
match lhs { | |
ValueExpr::Value => Box::new(move |ctx: &ExecutionContext<'_>| { | |
match ctx.value.as_ref().unwrap() { | |
Value::Str(left) => &rhs == left, | |
Value::Int(_) => unreachable!(), | |
} | |
}), | |
ValueExpr::FunctionCall(function_call_expr) => { | |
let call = self.compile_function_call_expr(function_call_expr); | |
Box::new(move |ctx: &ExecutionContext<'_>| match call.execute(ctx) { | |
Value::Str(left) => &rhs == &left, | |
Value::Int(_) => unreachable!(), | |
}) | |
} | |
} | |
} | |
} | |
} | |
fn compile_function_call_expr( | |
&mut self, | |
function_call_expr: FunctionCallExpr, | |
) -> Self::ValueOperation { | |
match function_call_expr { | |
FunctionCallExpr::Lowercase => { | |
Box::new( | |
move |ctx: &ExecutionContext<'_>| match ctx.value.as_ref().unwrap() { | |
Value::Str(left) => Value::Str(left.to_ascii_lowercase().into()), | |
Value::Int(_) => unreachable!(), | |
}, | |
) | |
} | |
} | |
} | |
} | |
fn main() { | |
let comp = ComparisonExpr::StrEq { | |
lhs: ValueExpr::FunctionCall(FunctionCallExpr::Lowercase), | |
rhs: String::from("test"), | |
}; | |
let mut compiler = DefaultCompiler; | |
let pred = compiler.compile_comparison_expr(comp); | |
let ctx = ExecutionContext { | |
value: Some(Value::Str("Test".into())), | |
}; | |
println!("{}", pred.execute(&ctx)); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment