Posted to tcl by aspect at Wed Oct 08 09:49:08 GMT 2014view pretty

** Macros in Tcl **

The invocation [proc $name $arglist $body] creates a command procedure named $name, whose invocation (according to DDL#2) results in the following

  1.1) a local scope will be created for the local vars
  1.2) some local vars (the formal arguments) will be initialized with values coming from the actual arguments;
  1.3) the body will be run as a script in that local scope, returning it's last result;
  1.4) the local scope will be destroyed


The invocation [defmacro $name $arglist $body] creates a command procedure named $name, whose expansion and invocation are according to the following:

  2.1) a local scope will be created for the local vars
  2.2) some local vars (the formal arguments) will be initialized with values coming from the actual arguments;
  2.3) the body will be run as a script in that local scope, returning it's last result;
  2.4) the local scope will be destroyed
  2.5) the result of step #3 will be evaluated in the calling context as though it were passwd to [eval];

A macro differs from a proc in that steps 1-4 may occur *at any time*.  The interpreter is free to pre-evaluate macros, or to cache the results of a
macro call to be re-used next time a compatible call-site is evaluated.

This places limits on the sort of things that can be done in a macro body with defined results.  Those limits can be summarised as:

  3.1) evaluation of a macro body can have no observable side effects
  3.2) evaluation of a macro body cannot depend on time-varying elements of the execution environment

Breaching either of these may make demons fly out your nose.


*** Proof-of concept implementation in pure Tcl ****

======
namespace eval ::macros {}

proc defmacro {name arglist body} {
    proc ::macros::$name $arglist $body
    uplevel 1 [
        list interp alias {} $name {} expand-macro $name
    ]
}

proc expand-macro {name args} {
    tailcall eval [::macros::$name {*}$args]
}

# not-very-motivating example usage:
defmacro let {varName args} {
    return "set [list $varName] \[expr $args\]"
}
let x 23*42
======


*** Proof-of-concept implementation inside the interpreter ***

See http://sourceforge.net/p/tcl/patches/535/ - spjuth, 2008; via http://wiki.tcl.tk/11159