Skip to content

TokenStream Backend ​

Generate proc_macro2::TokenStream from dew expressions for use in Rust proc-macros.

Enable ​

toml
dew-scalar = { version = "0.1", features = ["tokenstream"] }
dew-linalg = { version = "0.1", features = ["tokenstream"] }

dew-scalar ​

Generate TokenStream ​

rust
use dew_core::Expr;
use dew_scalar::tokenstream::emit_tokenstream;

let expr = Expr::parse("sin(x) + cos(y)").unwrap();
let tokens = emit_tokenstream(expr.ast()).unwrap();

// tokens is a proc_macro2::TokenStream
// Output equivalent: (x.sin() + y.cos())

dew-linalg ​

Generate with Types (glam-compatible) ​

rust
use dew_core::Expr;
use dew_linalg::tokenstream::emit_tokenstream;
use dew_linalg::Type;
use std::collections::HashMap;

let expr = Expr::parse("normalize(v) * 2.0").unwrap();

let mut var_types: HashMap<String, Type> = HashMap::new();
var_types.insert("v".to_string(), Type::Vec3);

let result = emit_tokenstream(expr.ast(), &var_types).unwrap();

// result.code is a TokenStream
// result.typ is Type::Vec3
// Output equivalent: (v.normalize() * 2.0)

glam Compatibility ​

The linalg backend emits code compatible with the glam math library:

dew Typeglam Type
Scalarf32
Vec2Vec2
Vec3Vec3
Vec4Vec4
Mat2Mat2
Mat3Mat3
Mat4Mat4

Vector Constructors ​

rust
// dew: vec2(x, y)
// Output: Vec2::new(x, y)

// dew: vec3(x, y, z)
// Output: Vec3::new(x, y, z)

Method Syntax ​

TokenStream output uses Rust method syntax:

rust
// dew: dot(a, b)
// Output: a.dot(b)

// dew: normalize(v)
// Output: v.normalize()

// dew: lerp(a, b, t)
// Output: a.lerp(b, t)

Function Mapping ​

dewTokenStream Output
sin(x)x.sin()
cos(x)x.cos()
sqrt(x)x.sqrt()
abs(x)x.abs()
floor(x)x.floor()
x ^ yx.powf(y)
min(a, b)a.min(b)
max(a, b)a.max(b)
clamp(x, lo, hi)x.clamp(lo, hi)
pi()::std::f32::consts::PI
e()::std::f32::consts::E
tau()::std::f32::consts::TAU

Use Case: Proc-Macro Derive ​

The primary use case is generating code at compile time in procedural macros:

rust
use proc_macro::TokenStream;
use quote::quote;
use dew_core::Expr;
use dew_scalar::tokenstream::emit_tokenstream;

#[proc_macro]
pub fn dew(input: TokenStream) -> TokenStream {
    let expr_str = input.to_string();
    let expr = Expr::parse(&expr_str).expect("invalid dew expression");
    let tokens = emit_tokenstream(expr.ast()).expect("codegen failed");

    quote! {
        fn generated(x: f32, y: f32) -> f32 {
            #tokens
        }
    }.into()
}

Comparison with Rust Text Backend ​

FeatureTokenStreamRust text
Outputproc_macro2::TokenStreamString
Use caseProc-macros, compile-timeDebug, docs, runtime codegen
ParsingDirect use in macrosRequires re-parse with syn
Dependenciesproc_macro2, quoteNone

Type Inference ​

The linalg backend performs full type inference:

rust
// Matrix-vector multiplication infers result type
let result = emit_tokenstream(
    Expr::parse("m * v").unwrap().ast(),
    &[("m", Type::Mat3), ("v", Type::Vec3)].into_iter().collect()
).unwrap();

assert_eq!(result.typ, Type::Vec3);

See Also ​