Macro call syntax in ABNF:
arg-name = 1*ALPHA
arg = [ arg-name ":" ] ( expr | statement )
arg-list = [ arg [ "," ] ]
arg-list /= arg "," arg-list
macro-name = 1*ALPHA
macro-call = name "!" [ "(" arg-list ")" ]
Example:
foo!;
bar!();
baz!(true, limit 1);
Importing user-defined macros differs from loading function declarations in PHP due to it's nature.
How to import user-defined macros if they're compile time and include*
family functions operate in runtime?
If I got it right: One solution is to compile all macro declarations on compilation time before processing the ast.
First there are two kinds of macros. One which substitute to proper ast replaced in place of macro invocation and second which don't resolve cause they emit opcodes or influence compiler.
Below is an example of macro declaration. First the eval!
actually is the unresolvable one but the second resolves into
ast substitution in place of it's call.
macro!(assert, {
($assertion, $msg, $throw) => {
if (!assert_enabled()) return;
$msg = $msg ?? 'Default error: ' . stringify!($assertion);
$throw = $throw ?? new!(AssertionException, %$msg);
rerturn if!(
%$assertion,
throw!(%$throw)
);
}
});
Note! Old, macros should return ast nodes like above.
macro!(eval, {
($e:expr) => { eval((string) $e); }
});
macro!(foo, {
($f:expr) => { if ($f) echo "Foo!\n"; };
($($args:expr,*)* $l:literal) => {
foreach ($args as $arg) {
var_dump(eval!($arg));
}
echo "Literal: {$l}";
};
});
Use of foo!
macro:
foo!; // ERROR
foo!(true); // echo "Foo!\n"
foo!("Hello", upper('w') . 'orld', SOME_Lit3ral);
declare!(strict_types: 1);
assert!(false, throw: new FalseAssertionException());
assert!(false, msg: 'Assertion failed');
$level = error_reporting!(level: E_ALL);
$error = error_get_last!;
error_clear_last!;
$vars = compact!('_ENV');
extract!($argv);
$vars = get_defined_vars!;
$empty = empty!($foo);
$isset = isset!($foo);
unset!($_ENV);
$argc = argc!;
$argv = argv!;
$arg = argv!('arg_name');
$trace = trace!(limit: 1); // debug_backtrace()
print_trace!(limit: 1); // debug_print_backtrace()
$callee = callee!; // equivalent of trace!(DEBUG_BACKTRACE_IGNORE_ARGS, limit: 1)[0];
dump!($foo); // debug_zval_dump()
exit!
exit!(1);
die!;
die!("The end.\n");
set_time_limit!(60);
trigger_error!("Cannot divide by zero", E_USER_ERROR);
halt!;
register!(autoload: 'myLoader', exception: 'exceptionHandler', error: 'errorHandler');
autoload_unregister!('myLoader');
autoload_call!();
restore_error_handler!();
restore_exception_handler!();
restore_include_path!;
$path = get_include_path!;
$path = set_include_path!('/usr/lib/pear');
ini_set!('memory_limit', '1G');
ast!(2 + 2);
header!('Content-Type', 'application/json');
$headers = headers_list!;
$headers = headers_sent!;
setcookie!('my_cookie', date('Y-m-d'));
setrawcookie!('my_cookie', date('Y-m-d'));
getcookie!('my_cookie'); // ??
$cookies = cookies_list!; // ??
$cookies = cookies_sent!; // ??