[fpc-pascal] Proper preprocessor?

denisgolovan denisgolovan at yandex.ru
Fri Jun 22 12:09:57 CEST 2018


See below the function to convert dynamic value into string value inside interpreter project I am working at, something similar to *ToStr family in FPC.

It's generated by the macro which expands to corresponding branches for each value type. "$" prefixes are for passing macro arguments. "ident!" is "calling" other macros, but it's quite obvious I guess.

Last syntax expression is "application" of this macro resulting in actual function creating and immediate compilation by Rust compiler. 

macro_rules! to_string {
    ($($scalar:tt),*) => {
        pub fn to_string(ast: &AST, interpreter: &Interpreter) -> AST {
            match base_tp(ast.tp()) {
                $(
                    $scalar => {
                        let aco=aco!($scalar, ast, Some(interpreter.alloc()));
                        let s=ato_str!(aco, aget!(aco, ast), interpreter);
                        new_string(&s, interpreter.alloc())
                    },
                )*
                $(
                    to_vec!($scalar) => {
                        let aco=aco!($scalar, ast, Some(interpreter.alloc()));
                        let v=ast.array::<atype!($scalar)>();
                        v.iter().map(|x| {
                            let s=ato_str!(aco, *x, interpreter);
                            new_string(&s, interpreter.alloc())
                        }).enlist(v.len(), interpreter.alloc())
                    }
                )*
                $(
                    to_deq!($scalar) => {
                        let aco=aco!($scalar, ast, Some(interpreter.alloc()));
                        let v=ast.vecdeq().head::<atype!($scalar)>();
                        v.iter().map(|x| {
                            let s=ato_str!(aco, *x, interpreter);
                            new_string(&s, interpreter.alloc())
                        }).enlist(v.len(), interpreter.alloc())
                    }
                )*
                x if is_nested(x) => atomic(ast, to_string, "to_string", interpreter),
                VEC_CHAR => (*ast).clone(),

                _ => except!(eval_err!("cast: nyi.")),
            }
        }
    }
}
to_string!(
    SC_BOOL,
    SC_BYTE,
    SC_SHORT,
    SC_INT,
    SC_MONTH,
    SC_DATE,
    SC_MINUTE,
    SC_SECOND,
    SC_TIME,
    SC_LONG,
    SC_TIMESTAMP,
    SC_DATETIME,
    SC_TIMESPAN,
    SC_SINGLE,
    SC_DOUBLE,
    SC_ENUM,
    SC_SYMBOL,
    SC_GUID
);

All in all my rough estimate for macro efficiency ratio is something like 12x currently. That's about 12 times less code to type and support. YMMV, of course.

See https://danielkeep.github.io/tlborm/book/mbe-min-captures-and-expansion-redux.html for boring details on Rust macros.

BR,
Denis



More information about the fpc-pascal mailing list