Metaprogramming: Difference between revisions

m
→‎{{header|Wren}}: Changed to Wren S/H
(Added Wren)
m (→‎{{header|Wren}}: Changed to Wren S/H)
 
(28 intermediate revisions by 11 users not shown)
Line 10:
This sample adds a COBOL-like INSPECT "statement" by defining suitable operators.
 
<langsyntaxhighlight lang="algol68"># This example uses ALGOL 68 user defined operators to add a COBOL-style #
# "INSPECT statement" to ALGOL 68 #
# #
Line 140:
 
 
)</langsyntaxhighlight>
Output:
<pre>some text
Line 148:
kXXc some
</pre>
 
=={{header|Arturo}}==
 
Arturo has been designed with flexibility in mind (see: DSL creation) and as different languages of the same heritage (e.g. REBOL, Red, etc) has meta-programming capabilities as part of the language itself.
 
Let's see some examples:
 
===Infix Operators===
 
<syntaxhighlight lang="rebol">sumThemUp: function [x,y][
x+y
]
 
alias.infix '--> 'sumThemUp
 
do [
print 3 --> 4
]</syntaxhighlight>
 
{{out}}
 
<pre>7</pre>
 
===Runtime Code Evaluation===
 
<syntaxhighlight lang="rebol">code: "print 123"
do code</syntaxhighlight>
 
{{out}}
 
<pre>123</pre>
 
===Symbol Creation & Access at Runtime===
 
<syntaxhighlight lang="rebol">myvar: "iAmAVariable"
 
let myvar 2
 
print myvar ; print the name of the variable
 
print var myvar ; print the value of the variable
print iAmAVariable ; the same</syntaxhighlight>
 
{{out}}
 
<pre>iAmAVariable
2
2</pre>
 
===Data as Code & Code as Data===
 
<syntaxhighlight lang="rebol">block: [print]
block: block ++ to :integer "34"
 
print "Here is our code:"
print as.code block
 
print ""
print "And here's its result:"
do block</syntaxhighlight>
 
{{out}}
 
<pre>Here is our code:
[print 34]
 
And here's its result:
34</pre>
 
=={{header|C}}==
Line 155 ⟶ 223:
It's possible to create [http://stackoverflow.com/questions/3385515/static-assert-in-c static assertions]
 
<syntaxhighlight lang="c">
<lang c>
// http://stackoverflow.com/questions/3385515/static-assert-in-c
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(!!(COND))*2-1]
Line 168 ⟶ 236:
COMPILE_TIME_ASSERT(sizeof(int)==4);
}
</syntaxhighlight>
</lang>
 
Another common usage is to create custom loops
 
<syntaxhighlight lang="c">
<lang c>
//requires C99
#define ITERATE_LIST(n, list) \
Line 182 ⟶ 250:
printf("node value: %s\n", n->value);
}
</syntaxhighlight>
</lang>
 
For examples in real world, look [http://svn.gna.org/viewcvs/freeciv/trunk/common/city.h?view=markup FreeCiv], and [http://mz.openttdcoop.org/is2/openttd-is2-h1f270887-docs/engine__base_8h-source.html OpenTTD] macros(city_map_iterate for FreeCiv, FOR_ALL_ENGINES for OpenTTD).
 
Also, C does not support functions overloading, but becausbecause macro calls do not require type it's possible to emulate overloading to some extent
 
<syntaxhighlight lang="c">
<lang c>
#define my_min(x, y) ((x) < (y) ? (x) : (y))
...
printf("%f %d %ll\n", my_min(0.0f, 1.0f), my_min(1,2), my_min(1ll, 2ll));
</syntaxhighlight>
</lang>
 
The [[Order|Order programming language]] is implemented entirely using the C preprocessor, providing a portable, high-level, functional programming language that can be used to metaprogram any C99 project, in a fashion loosely similar to Lisp's macro system.
 
[https://github.com/Hirrolot/metalang99 Metalang99] is also a functional language aimed at full-blown preprocessor metaprogramming in pure C99. With the aid of Metalang99, such things as [https://github.com/Hirrolot/datatype99 Datatype99] and [https://github.com/Hirrolot/interface99 Interface99] became possible.
 
==={{libheader|Gadget}}===
<p>Gadget is a basic library that combines the use of macros and functions to facilitate programming in pure C.</p>
<p>Some useful macros that you can find in this library are the following:</p>
 
<syntaxhighlight lang="c">
 
#define Str_init(_V_) char * _V_=NULL;
 
#define Free_secure(_X_) if(_X_) { free(_X_); _X_=NULL; }
 
#define Let(_X_,_Y_) \
do{\
if(_X_) free(_X_);\
int len = strlen(_Y_);\
_X_ = (char*)calloc( len + 1, 1);\
if(_X_) { memcpy(_X_, _Y_, len); }\
else { perror("\033[38;5;196mLet: No hay memoria para <"#_X_">(CALLOC)\n\033[0m"); }\
}while(0);
 
/* inicia el trabajo con el stack */
#define Stack if( (PILA_GADGET = 1) )
 
/* finaliza el trabajo con el stack. La pila debe quedar en "0" */
#define Stack_off \
PILA_GADGET = 0; \
if(CONTADOR_PILA>=0){ Msg_red("Proceso termina con stack ocupado: borro sobrante\n");\
CONTADOR_PILA=-1; }
 
/*
STORE almacena el valor en la variable indicada, obtenido desde el
stack. */
#define Store(_X_,_Y_) \
do{\
_Y_;\
if(PILA_GADGET){\
if( CONTADOR_PILA>=0 ){\
Let(_X_, pila_de_trabajo[CONTADOR_PILA]);CONTADOR_PILA--;\
}\
}else{ Msg_amber("Store: No hay datos en la pila");}\
}while(0);
...
#define Main \
int main(int argc, char* argv[]){\
__TOKEN__=NULL;\
Init_token();\
Init_stack;
 
/* SALIDA NORMAL */
#define End End_token(); \
Free_stack_str;\
return(0); }
</syntaxhighlight>
<p>With these macros it is possible to write programs like this:</p>
<syntaxhighlight lang="c">
#include <gadget/gadget.h>
LIB_GADGET_START
 
Main
String w, v="María tenía un corderito";
 
Stack{
Store( v, Substr(v, Str_at("tenía",v),Str_len( Upper(v) )) );
Store( v, Trim(Left( Upper(v), Str_at("CORDERITO",Upper(v))-1)));
}Stack_off;
 
Print "msg stack : [%s]\n\n", v;
Let( v, "María tenía un corderito");
 
/* Str_len() sirve sin stack, pero en este caso es mejor usar strlen() de C. */
w = Substr(v, Str_at("tenía",v),Str_len(v));
Print "msg normal: %s\n", w;
 
Free secure w,v;
End
</syntaxhighlight>
<p>Note: the "Free_secure()" and "Str_init()" macros are preprocessed before entering the compile cycle.</p>
 
<p>Other interesting macros that can extend the C language are the "Assert" and "Exception" macros, which use the "hated GOTO":</p>
 
<syntaxhighlight lang="c">
#define Throw(_X_) if( !Is_ok ) { goto _X_; }
#define Exception(_H_) _H_: if( !Is_ok++ )
#define Assert(_X_,_Y_) if( !(_X_) ) { Is_ok=0; goto _Y_; }
</syntaxhighlight>
<p>Example:</p>
<syntaxhighlight lang="c">
#include <gadget/gadget.h>
LIB_GADGET_START
 
Main
int retVal=0;
Assert( Arg_count == 2, fail_input );
Get_arg_str( filename, 0 );
Get_arg_float( number, 1 );
 
Print "First argument (filename) = %s\n", filename;
Print "Second argument (a number) = %f\n", number;
 
Free secure filename;
 
Exception( fail_input ){
Msg_yellow("Use:\n ./prog <number>\n");
retVal=1;
}
Return( retVal );
</syntaxhighlight>
<p>There are also macros that, in combination with functions, allow you to extend the C language and simplify its programming:</p>
<syntaxhighlight lang="c">
/* declara un array vacío */
#define New_mt_array(_X_) \
MT_CELL *_X_ = NULL;\
Define_New_Array(_X_)\
_X_##_data.type = MULTI_TYPE;
....
/* acceso a celdas string */
#define sCell(_X_,...) CONCAT2(Cell_mtstr, COUNT_ARGUMENTS(__VA_ARGS__))(_X_, ##__VA_ARGS__)
 
#define Cell_mtstr1(_X_,ARG1) (_X_[ ARG1 ].value)
#define Cell_mtstr2(_X_,ARG1,ARG2) (_X_[ ( ARG1 ) * ( _X_##_data.cols ) + ( ARG2 ) ].value)
#define Cell_mtstr3(_X_,ARG1,ARG2,ARG3) (_X_[ ( ( ARG1 ) * ( _X_##_data.cols ) + ( ARG2 ) ) + \
( ARG3 ) * ( _X_##_data.cols * _X_##_data.rows ) ].value)
...
/* acceso a celdas long */
#define lCell(_X_,...) CONCAT2(Cell_mtlng, COUNT_ARGUMENTS(__VA_ARGS__))(_X_, ##__VA_ARGS__)
 
#define Cell_mtlng1(_X_,ARG1) *((long *)(_X_[ ARG1 ].value))
#define Cell_mtlng2(_X_,ARG1,ARG2) *((long *)(_X_[ ( ARG1 ) * ( _X_##_data.cols ) + ( ARG2 ) ].value))
#define Cell_mtlng3(_X_,ARG1,ARG2,ARG3) *((long *)(_X_[ ( ( ARG1 ) * ( _X_##_data.cols ) + ( ARG2 ) ) + \
( ARG3 ) * ( _X_##_data.cols * _X_##_data.rows ) ].value))
 
...
/* RANGOS para acceso iterado */
#define Range_for(_X_, ...) CONCAT2(Range_for, COUNT_ARGUMENTS(__VA_ARGS__))(_X_, ##__VA_ARGS__)
 
/* para un array 1D */
#define Range_for3(_X_,A1,A2,A3) \
_X_##_data.rowi=A1;_X_##_data.rowinc=A2;_X_##_data.rowe=A3;
 
/* para un array 2D */
#define Range_for6(_X_,A1,A2,A3,B1,B2,B3) \
_X_##_data.rowi=A1;_X_##_data.rowinc=A2;_X_##_data.rowe=A3; \
_X_##_data.coli=B1;_X_##_data.colinc=B2;_X_##_data.cole=B3;
....
</syntaxhighlight>
<p>Example:</p>
<syntaxhighlight lang="c">
#include <gadget/gadget.h>
 
LIB_GADGET_START
 
void Muestra_archivo_original();
 
Main
Assert (Exist_file("load_matrix.txt"), file_not_found);
 
/* recupero informacion del archivo para su apertura segura */
F_STAT dataFile = Stat_file("load_matrix.txt");
Assert (dataFile.is_matrix, file_not_matrixable) // tiene forma de matriz???
New multitype test;
/* The data range to be read is established.
It is possible to read only part of the file using these ranges. */
Range for test [0:1:dataFile.total_lines-1, 0:1:dataFile.max_tokens_per_line-1];
/* cargamos el array detectando números enteros como long */
test = Load_matrix_mt( pSDS(test), "load_matrix.txt", dataFile, DET_LONG);
/* modifica algunas cosas del archivo */
Let( $s-test[0,1], "Columna 1");
$l-test[2,1] = 1000;
$l-test[2,2] = 2000;
/* inserto filas */
/* preparo la fila a insertar */
New multitype nueva_fila;
sAppend_mt(nueva_fila,"fila 3.1"); /* sAppend_mt() and Append_mt() are macros */
Append_mt(nueva_fila,float,0.0);
Append_mt(nueva_fila,int,0);
Append_mt(nueva_fila,double,0.0);
Append_mt(nueva_fila,long, 0L);
/* insertamos la misma fila en el array, 3 veces */
test = Insert_row_mt(pSDS(test),pSDS(nueva_fila), 4);
test = Insert_row_mt(pSDS(test),pSDS(nueva_fila), 4);
test = Insert_row_mt(pSDS(test),pSDS(nueva_fila), 4);
Free multitype nueva_fila;
Print "\nGuardando archivo en \"save_matrix.txt\"...\n";
DEC_PREC = 20; /* establece precision decimal */
All range for test;
Save_matrix_mt(SDS(test), "save_matrix.txt" );
 
Free multitype test;
Print "\nArchivo original:\n";
Muestra_archivo_original();
Exception( file_not_found ){
Msg_red("File not found\n");
}
Exception( file_not_matrixable ){
Msg_red("File is not matrixable\n");
}
 
End
 
void Muestra_archivo_original(){
String csys;
csys = `cat load_matrix.txt`;
Print "\n%s\n", csys;
Free secure csys;
}
</syntaxhighlight>
<p>Note: "Range_for()", "sCell()", "lCell()", "v=`...`", and "New_mt_array()" macros are preprocessed before entering the compile cycle.</p>
<pre>GADGET has been designed to encapsulate the complicated (and basically utilitarian, that is, what will always be programmed in the same way) without losing the spirit of the C language (the possibility of working at a low level).
 
From Chile with love,
 
Mr Dalien.</pre>
 
=={{header|C sharp|C#}}==
Line 201 ⟶ 494:
 
=={{header|Clojure}}==
See [httphttps://clojure-doc.org/articles/languagereference/macros.html Clojure Macros and MetaprogrammingReference] article.
 
=={{header|Common Lisp}}==
Line 212 ⟶ 505:
Calculate mean, and sample variance and sample standard deviation of some numbers:
 
<langsyntaxhighlight lang="lisp">
(loop for count from 1
for x in '(1 2 3 4 5)
Line 222 ⟶ 515:
(spl-var (- (* count sum-of-squares) (* sum sum)))
(spl-dev (sqrt (/ spl-var (1- count)))))
(values mean spl-var spl-dev)))) </langsyntaxhighlight>
 
=> <pre>5/2 ;
Line 233 ⟶ 526:
Here is what CLISP makes of the above, by investigating the macro expansion using the ANSI standard <code>macroexpand</code> function:
 
<langsyntaxhighlight lang="lisp">
[5]>
(macroexpand'
Line 268 ⟶ 561:
(SPL-VAR (- (* COUNT SUM-OF-SQUARES) (* SUM SUM)))
(SPL-DEV (SQRT (/ SPL-VAR (1- COUNT)))))
(VALUES MEAN SPL-VAR SPL-DEV)))))))))))))) ; T</langsyntaxhighlight>
 
Next, we can leave ANSI behind and call CLISP's internal code walker to expand the entire form, removing all traces of the definitions of local macros, leaving behind only pure code based on special forms and function calls:
 
<langsyntaxhighlight lang="lisp">(system::expand-form
'(loop for count from 1
for x in '(1 2 3 4 5)
Line 300 ⟶ 593:
(SPL-VAR (- (* COUNT SUM-OF-SQUARES) (* SUM SUM)))
(SPL-DEV (SQRT (/ SPL-VAR (1- COUNT)))))
(VALUES MEAN SPL-VAR SPL-DEV)))))))))</langsyntaxhighlight>
 
===Implement monadic comprehensions===
Line 306 ⟶ 599:
We can use Lisp macros, and other features, to add support to Lisp for monads, which come from functional languages. The following module of code provides a new macro form called COMPREHEND which works with monads. If we use the LIST monad, we get list comprehensions. For instance:
 
<langsyntaxhighlight lang="lisp">
;; The -> notation is not part of Lisp, it is used in examples indicate the output of a form.
;;
Line 314 ⟶ 607:
-> ((1 . A) (1 . B) (1 . C)
(2 . A) (2 . B) (2 . C)
(3 . A) (3 . B) (3 . C))</langsyntaxhighlight>
 
As you can see, the comprehension processes all combinations of X and Y from both sets, and collects the application of (CONS X Y) to these elements.
Line 329 ⟶ 622:
 
Another example, using the identity monad. With the identity monad, the comprehension becomes a sequence of successive variable bindings, and a form evaluated in the scope of those bindings. It is basically like a "Lispified" Haskell DO syntax:
<langsyntaxhighlight lang="lisp">(identity-comp (list x y z) (x 1) (y (* 3 x)) (z (+ x y)))
-> (1 3 4)
</syntaxhighlight>
</lang>
I.e. combine the values X, Y and Z into a triplet list, were X is 1, Y is 3X, and Z is X + Y.
 
To see the original version of this code with lengthy comments, have a look in the Lisp Pastebin. http://paste.lisp.org/display/71196
 
<langsyntaxhighlight lang="lisp">(defgeneric monadic-map (monad-class function))
 
(defgeneric monadic-join (monad-class container-of-containers &rest additional))
Line 434 ⟶ 727:
((x new-state)
(funcall embedded-xformer intermediate-state)))))
:unit ((x) (lambda (s) (values x s))))</langsyntaxhighlight>
===Python in Lisp===
The CLPython project (http://common-lisp.net/project/clpython) provides a Python implementation embedded in Common Lisp. Python modules can be included in Lisp programs and interoperate with Lisp code. There is even a mixed-mode interactive loop ("REPL") where one can use a dialect which mixes Python and Lisp:
Line 469 ⟶ 762:
[http://dlang.org/mixin.html Mixins] enable string constants to be compiled as regular D code and inserted into the program. Combining this with compile time manipulation of strings enables the creation of domain-specific languages.
 
<langsyntaxhighlight lang="d">enum GenStruct(string name, string fieldName) =
"struct " ~ name ~ "{ int " ~ fieldName ~ "; }";
 
Line 478 ⟶ 771:
Foo f;
f.bar = 10;
}</langsyntaxhighlight>
 
=={{header|E}}==
Line 495 ⟶ 788:
Perhaps the most obvious use of Metaprogramming in Forth is Forth itself. The Forth virtual machine traditionally has a primitive operation called BRANCH, which as you could guess, does an unconditional branch to somewhere in the program. There is also ?BRANCH (sometimes called 0BRANCH) which branches only if the top of the Forth DATA stack is zero. There are typically also primitive "DO" and "LOOP" operators. All of these primitives cannot be used on their own and must be compiled into program code by the Forth compiler which needs to compute where to branch or loop to in the context of the code. The compiler itself is implemented in Forth and defines the syntax for conditional branches and loops. Understanding this code is not "needed" for application programming but exists inside the Forth system. The application programmer is free to use these same tools to create new branching and looping syntax if there is a need to do so. (FOR/NEXT, CASE ENDCASE etc.)
 
<LANGsyntaxhighlight lang="forth">\ BRANCH and LOOP COMPILERS
 
\ branch offset computation operators
Line 529 ⟶ 822:
: UNTIL ( ? -- ) 1 ?PAIRS POSTPONE ?BRANCH BACK ; IMMEDIATE
: WHILE ( ? -- ) POSTPONE IF 2+ ; IMMEDIATE
: REPEAT ( -- ) 2>R POSTPONE AGAIN 2R> 2- POSTPONE THEN ; IMMEDIATE</LANGsyntaxhighlight>
 
Simple Usage Examples
 
<LANGsyntaxhighlight lang="forth"> : CHARSET [CHAR] ~ [CHAR] ! DO I EMIT LOOP ;
 
: >DIGIT ( n -- c) DUP 9 > IF 7 + THEN [CHAR] 0 + ;
Line 542 ⟶ 835:
WHILE
1- \ dec. length
REPEAT ;</LANGsyntaxhighlight>
 
=={{header|FreeBASIC}}==
Line 549 ⟶ 842:
For example, we can create a 'forall' loop to iterate through the characters of a string rather than use a traditional 'for' loop:
 
<langsyntaxhighlight lang="freebasic">' FB 1.05.0 Win64
 
#Macro ForAll(C, S)
Line 564 ⟶ 857:
Print
Sleep</langsyntaxhighlight>
 
{{out}}
Line 585 ⟶ 878:
 
In the following example the 'copy' function, which is normally used to copy slices, is redeclared to copy a 'person' struct instead:
<langsyntaxhighlight lang="go">package main
 
import "fmt"
Line 608 ⟶ 901:
copy(it, is)
*/
}</langsyntaxhighlight>
 
{{out}}
Line 644 ⟶ 937:
 
Using metaprogramming, the do/while can be somewhat emulated:
<langsyntaxhighlight lang="julia">macro dowhile(condition, block)
quote
while true
Line 681 ⟶ 974:
end
println("Done.")
</langsyntaxhighlight>{{output}}<pre>
[7, 31]
[8, 32]
Line 697 ⟶ 990:
It is also possible to define infix functions which look like user defined operators:
 
<langsyntaxhighlight lang="scala">// version 1.0.6
 
infix fun Double.pwr(exp: Double) = Math.pow(this, exp)
Line 704 ⟶ 997:
val d = 2.0 pwr 8.0
println(d)
}</langsyntaxhighlight>
 
{{out}}
Line 714 ⟶ 1,007:
Lingo allows to create (and pre-compile) arbitrary code at runtime. You can't really change the language's syntax, but you can overwrite (or extend) built-in commands. Here as example some code that overwrite's Lingo's halt command, which would normally exit the current program:
 
<langsyntaxhighlight lang="lingo">r = RETURN
str = "on halt"&r&"--do nothing"&r&"end"
new(#script).scripttext = str</langsyntaxhighlight>
 
=={{header|Lua}}==
Line 723 ⟶ 1,016:
 
For example:
<langsyntaxhighlight lang="lua">
class "foo" : inherits "bar"
{
}
</syntaxhighlight>
</lang>
 
is perfectly valid syntax. (Lua does not having a built in concept of classes or inheritance.)
 
=={{header|M2000 Interpreter}}==
<syntaxhighlight lang="m2000 interpreter">
<lang M2000 Interpreter>
Module Meta {
FunName$="Alfa"
Line 748 ⟶ 1,041:
}
Meta
</syntaxhighlight>
</lang>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
Mathematica can overload all symbols, though sometimes Unprotect has to be invoked. You can also introduce your own infix operators:
<langsyntaxhighlight Mathematicalang="mathematica">CircleTimes[x_, y_] := Mod[x, 10] Mod[y, 10]
14\[CircleTimes]13</langsyntaxhighlight>
{{out}}
<pre>12</pre>
Line 766 ⟶ 1,059:
===Infix Operators===
You can define your own infix operators:
<langsyntaxhighlight lang="nim">proc `^`*[T: SomeInteger](base, exp: T): T =
var (base, exp) = (base, exp)
result = 1
Line 776 ⟶ 1,069:
base *= base
echo 2 ^ 10 # 1024</langsyntaxhighlight>
 
===Compile Time evaluation===
<code>when</code> is a compile time <code>if</code> and can be used to prevent code from even being parsed at compile time, for example to write platform specific code:
<langsyntaxhighlight lang="nim">when defined windows:
echo "Call some Windows specific functions here"
elif defined linux:
echo "Call some Linux specific functions here"
else:
echo "Code for the other platforms"</langsyntaxhighlight>
Normal code can be executed at compile time if it is in a <code>static</code> block:
<langsyntaxhighlight lang="nim">static:
echo "Hello Compile time world: ", 2 ^ 10</langsyntaxhighlight>
As well as stored in compile time constants:
<langsyntaxhighlight lang="nim">const x = 2 ^ 10</langsyntaxhighlight>
===Templates===
The <code>expensive</code> procedure has to be evaluated even when <code>debug</code> is <code>false</code>:
<langsyntaxhighlight lang="nim">import os
 
const debug = false
Line 807 ⟶ 1,100:
for i in 1..10:
log expensive()
</syntaxhighlight>
</lang>
This can be prevented using templates, as template calls are replaced with the template body at compile time:
<syntaxhighlight lang="text">template log(msg: string) =
if debug:
echo msg
 
for i in 1..10:
log expensive()</langsyntaxhighlight>
Templates can use block syntax with statement parameters:
<langsyntaxhighlight lang="nim">template times(x, y: untyped): untyped =
for i in 1..x:
y
Line 822 ⟶ 1,115:
10.times: # or times 10: or times(10):
echo "hi"
echo "bye"</langsyntaxhighlight>
 
===Term Rewriting Templates===
Term Rewriting Templates can be used to write your own optimizations:
<syntaxhighlight lang="text">template optLog1{a and a}(a): auto = a
template optLog2{a and (b or (not b))}(a,b): auto = a
template optLog3{a and not a}(a: int): auto = 0
Line 840 ⟶ 1,133:
 
q = (s and not x) and not (s and not x)
# Hint: optLog3(s and not x) --> ’0’ [Pattern]</langsyntaxhighlight>
===Macros===
The most powerful metaprogramming capabilities are offered by macros. They can generate source code or even an AST directly.
 
<code>dumpTree</code> can be useful when creating an AST, as it show you the AST of any code:
<langsyntaxhighlight lang="nim">import macros
 
dumpTree:
Line 857 ⟶ 1,150:
p2
else:
p3</langsyntaxhighlight>
This prints:
<pre>StmtList
Line 889 ⟶ 1,182:
For example the "define" macro implementation based on 'setq' (assigns value to variable) and 'lambda' (creates function) keywords and provides uniform way to define variables and functions.
 
<langsyntaxhighlight lang="scheme">
(define-syntax define
(syntax-rules (lambda) ;λ
Line 902 ⟶ 1,195:
((define name a b . c)
(define name (begin a b . c)))))
</syntaxhighlight>
</lang>
 
Now we can use
 
<langsyntaxhighlight lang="scheme">
(define (sum a b) (+ a b))
; instead of
(setq sum (lambda (a b) (+ a b)))
</syntaxhighlight>
</lang>
 
=={{header|OxygenBasic}}==
 
OxygenBasic supports metalanguage useable with various macro formats.
 
Unlike the C preprocessor, OxygenBasic metalanguage is resolved inline.
 
<syntaxhighlight lang="text">
 
'EQUATES
 
% half 0.5
$ title "My Metaprogram"
 
'CONDITIONAL BLOCKS
 
#ifdef ...
...
#elseif ...
...
#else
...
#endif
 
'MACROS
 
'msdos-like
def sum
%1 + %2
end def
 
'C-like
#define sum(a,b) a + b
 
'native
macro sum(a,b)
a + b
end macro
 
'native macro functions
macro sum int(r,a,b)
r = a + b
end macro
 
</syntaxhighlight>
 
=={{header|PARI/GP}}==
Line 927 ⟶ 1,265:
 
In (e.g.) basemath/somefile.c:
<langsyntaxhighlight Clang="c">long
smin0ss(long a, long b)
{
Line 940 ⟶ 1,278:
GEN c = gcmp(a, b) < 1 ? a : b; /* copy pointer */
return signe(c) > 0 ? gcopy(c) : gen_0;
}</langsyntaxhighlight>
 
=={{header|Perl}}==
Line 946 ⟶ 1,284:
You can textually transform code with a [http://perldoc.perl.org/perlfilter.html source filter], a module that when <code>use</code>d modifies the following lines of source. [http://perldoc.perl.org/Filter/Util/Call.html Filter::Util::Call] provides a general means of writing source filters. [http://perldoc.perl.org/Filter/Simple.html Filter::Simple] is an interface to <code>Filter::Util::Call</code> that lets you elide a lot of boilerplate code. More important, <code>Filter::Simple</code> can hide the contents of quoting constructs from your filter, obviating the biggest dangers of textual metaprogramming. For example, given the following module:
 
<langsyntaxhighlight lang="perl">package UnicodeEllipsis;
 
use Filter::Simple;
 
FILTER_ONLY code => sub { s/…/../g };</langsyntaxhighlight>
 
this program:
 
<langsyntaxhighlight lang="perl">use UnicodeEllipsis;
 
print join(' … ', 1 … 5), "\n";</langsyntaxhighlight>
 
prints:
Line 973 ⟶ 1,311:
Primarily for compiler development use, rather than end user applications. No code is generated, but compilation will abort if they fail.
Some static assertions can be performed with #isginfo{}, eg:
<langsyntaxhighlight Phixlang="phix">object x
#isginfo{x,0b0101,5,7,integer,3}
-- {var,type,min,max,etype,len}
Line 979 ⟶ 1,317:
x = {1,2,3} -- sequence of integer, length 3
x = 5 -- integer 5 (becomes min)
x = 7 -- integer 7 (becomes max)</langsyntaxhighlight>
A compile-time error occurs if say either 7 is changed to 6 (but not both).<br>
Note that you only get that error for "p -c test", not "p test".
Line 999 ⟶ 1,337:
PostScript allows the reification of stack, scoping (dynamic scoping is default, but lexical scoping can be implemented using immediate loading), bindings using dictionaries, and even control flow. Here is an example of implementation of if statement
{{libheader|initlib}}
<langsyntaxhighlight lang="postscript">
 
/ift {
Line 1,012 ⟶ 1,350:
} ifelse
end}.
</syntaxhighlight>
</lang>
The standard if expression in PostScript does not take a predicate. Instead it acts on the boolean value on top of the stack. This newly created word allows us to do
<langsyntaxhighlight lang="postscript">
>| 2 {1 gt} {=} ift
2
</syntaxhighlight>
</lang>
Instead of
 
<langsyntaxhighlight lang="postscript">
>| 2 dup 1 gt {=} ift
2
</syntaxhighlight>
</lang>
 
Note that even the let expression was implemented using meta programming
<langsyntaxhighlight lang="postscript">
/let* {reverse {exch def} forall}.
</syntaxhighlight>
</lang>
 
=={{header|Prolog}}==
Line 1,034 ⟶ 1,372:
This example expands and prints a goal using [http://www.swi-prolog.org/pldoc/man?predicate=clause/2 clause/2]:
 
<langsyntaxhighlight lang="prolog">
:- initialization(main).
main :- clause(less_than(1,2),B),writeln(B).
less_than(A,B) :- A<B.
 
</syntaxhighlight>
</lang>
New goals can be created at runtime using [http://www.swi-prolog.org/pldoc/man?predicate=assertz/1 assertz/1]:
<langsyntaxhighlight lang="prolog">
assertz((mother(Child, Mother) :-
parent(Child, Mother),
female(Mother))).
</syntaxhighlight>
</lang>
 
=={{header|Python}}==
Line 1,057 ⟶ 1,395:
This is example is taken from MacroPy's [https://github.com/lihaoyi/macropy/blob/2885df8ca73fa0f6c17168a98d218dc4a3f088c2/docs/examples/first_macro/full/macro_module.py GitHub page]. It creates a macro called <tt>expand</tt> that, when invoked, generates the AST for a function in place of the original expression.
 
<langsyntaxhighlight lang="python">
from macropy.core.macros import *
from macropy.core.quotes import macros, q, ast, u
Line 1,067 ⟶ 1,405:
addition = 10
return q[lambda x: x * ast[tree] + u[addition]]
</syntaxhighlight>
</lang>
 
It is then invoked like this:
<langsyntaxhighlight lang="python">
func = expand[1 + 2]
print func(5)
</syntaxhighlight>
</lang>
 
=={{header|Quackery}}==
 
The various forms of metaprogramming available in Quackery are discussed in [https://github.com/GordonCharlton/Quackery The Book of Quackery]. Here, two types are illustrated.
 
1: Extending the Quackery compiler by adding a compiler directive to skip over inline comments indicated by a semicolon. (Quackery has block comments delimited by "(" and ")" but not "comment to end of line".)
 
2: Adding a new control-flow structure (a switch statement) by using meta-control-flow words. (The ones with ]reverse-nested[ names, indicating they convey properties to the nest that invoked them.)
 
<syntaxhighlight lang="quackery">
( +---------------------------------------------------+ )
( | add inline comments ";" to Quackery with "builds" | )
( +---------------------------------------------------+ )
 
[ dup $ "" = not while
behead carriage =
until ] builds ; ( [ $ --> [ $ )
 
 
; +---------------------------------------------------+
; | add switch to Quackery with ]else[ ]'[ & ]done[ |
; +---------------------------------------------------+
 
[ stack ] is switch.arg ( --> s )
protect switch.arg
 
[ switch.arg put ] is switch ( x --> )
 
[ switch.arg release ] is otherwise
 
[ switch.arg share
!= iff ]else[ done
otherwise
]'[ do ]done[ ] is case ( x --> )
 
 
[ switch
1 case [ say "The number 1." cr ]
$ "two" case [ say 'The string "two".' cr ]
otherwise [ say "Something else." cr ] ] is test
( x --> )
 
 
' tally test ; output should be: Something else.
$ "two" test ; output should be: The string "two".
1 test ; output should be: The number 1.
 
</syntaxhighlight>
 
{{Out}}
 
<pre>Something else.
The string "two".
The number 1.
</pre>
=={{header|R}}==
R does not have much to offer in this regard. It has generic functions, but they're little more than the forbidden option of operator overloading. We equally cannot use any eval tricks, because the task has also forbidden those. As for macros, although R is inspired by Scheme, it has nothing of the sort. For example, see the admitted cheating in [[Extend your language#R]].
 
As for the permitted things that R does have, it makes it very easy to define new infix operators. We have shown one such example at [[Matrix-exponentiation operator#Infix operator]]. To my knowledge, this is only documented in 'An Introduction to R', [https://cran.r-project.org/doc/manuals/r-release/R-intro.html#Defining-new-binary-operators section 10.2]. As for doing this ourselves, we will implement a version of the "nCk" syntax that some calculators use for "n choose k", i.e. the binomial coefficient:
<syntaxhighlight lang="rsplus">'%C%' <- function(n, k) choose(n, k)
5 %C% 2 #Outputs 10.</syntaxhighlight>
 
=={{header|Racket}}==
Line 1,084 ⟶ 1,483:
 
For a simple example, this is the definition and a use of the macro list-when:
<langsyntaxhighlight lang="racket">#lang racket
 
(define-syntax-rule (list-when test body)
Line 1,093 ⟶ 1,492:
(let ([not-a-string 42])
(list-when (string? not-a-string)
(string->list not-a-string)))</langsyntaxhighlight>
 
Unlike a plain function, which would eagerly evaluate its arguments, list-when only evaluates its body expression when its test expression passes: otherwise, it evaluates to the empty list. Therefore, the example above does not produce an error.
Line 1,099 ⟶ 1,498:
Alternatively, list-when could be defined using syntax-parse, which provides better error messages for syntax errors:
 
<langsyntaxhighlight lang="racket">(require (for-syntax syntax/parse))
 
(define-syntax list-when
Line 1,106 ⟶ 1,505:
#'(if test
body
null)]))</langsyntaxhighlight>
 
=={{header|Raku}}==
Line 1,117 ⟶ 1,516:
There is no a built in factorial operator Raku. It was purposely left out to use as a demonstration of how easy it is to add it. <tt>:-)</tt>
 
<syntaxhighlight lang="raku" perl6line>sub postfix:<!> { [*] 1..$^n }
say 5!; # prints 120</langsyntaxhighlight>
 
You may augment a base class with a new method, as long as you declare that you are going to cheat.
Line 1,124 ⟶ 1,523:
Here we add a new method to do natural sorting to the base class <tt>Any</tt>. (<tt>List</tt> and <tt>Array</tt> are both subclasses of Any)
 
<syntaxhighlight lang="raku" perl6line>use MONKEY-TYPING; # Needed to do runtime augmentation of a base class.
 
augment class List {
Line 1,131 ⟶ 1,530:
 
say ~<a201st a32nd a3rd a144th a17th a2 a95>.nsort;
say ~<a201st a32nd a3rd a144th a17th a2 a95>.sort;</langsyntaxhighlight>
 
Prints
Line 1,138 ⟶ 1,537:
a144th a17th a2 a201st a32nd a3rd a95</pre>
Grammar mixins work in Raku because grammar rules are just methods in grammar classes, and Raku automatically writes a JIT lexer for you whenever you derive a new language. This functionality already works internally in the standard parser—what is not yet implemented is the <tt>augment slang</tt> hook to allow user code to do this mixin. Raku itself is already parsed using such grammar mixins to provide extensible quoting and regex syntax. For example, every time you pick your own quote characters, you're actually deriving a new Raku dialect that supports those start and stop characters. Likewise any switches to impose single or double-quote semantics, or heredoc semantics, is merely a grammar mixin on the basic <tt>Q</tt> language.
<syntaxhighlight lang="raku" perl6line>say "Foo = $foo\n"; # normal double quotes
say Q:qq 【Foo = $foo\n】; # a more explicit derivation, new quotes</langsyntaxhighlight>
 
=={{header|Rascal}}==
Line 1,148 ⟶ 1,547:
In Rascal, grammars can be easily defined. The example below shows the syntax definition for the easy languages C and E1. ViewParseTree visualises the parse tree and lets the user interactively check whether sentences belong to the grammar. The greater than symbol in language E1 means that multiplication has a higher priority than addition.
 
<langsyntaxhighlight lang="rascal">extend ViewParseTree;
 
layout Whitespace = [\ \t\n]*;
Line 1,161 ⟶ 1,560:
> E "+" E
| "(" E ")"
;</langsyntaxhighlight>
 
An example of the parse viewer for E1
Line 1,169 ⟶ 1,568:
===Syntax Tree Traversal===
Furthermore, Rascal has built-in functions to traverse trees. This can be used to visit all the nodes in the abstract syntax trees that are automatically generated by Rascal. This provides a powerful tool to analyse code. The following example counts for each operator how many of these the programme contains.
<langsyntaxhighlight lang="rascal">map[str, int] operatorUsage(PROGRAM P) {
m = ();
visit(P){
Line 1,177 ⟶ 1,576:
}
return m;
}</langsyntaxhighlight>
Where the abstract syntax is defined as follows
<langsyntaxhighlight lang="rascal">public data TYPE =
natural() | string();
Line 1,206 ⟶ 1,605:
| doUntilStat(EXP exp, list[STATEMENT] body)
| unlessStat(EXP exp, list[STATEMENT] body)
;</langsyntaxhighlight>
 
===Pico in Rascal===
Line 1,212 ⟶ 1,611:
This is part of the Pico syntax expressed in Rascal.
 
<langsyntaxhighlight lang="rascal">module lang::pico::Syntax
 
import Prelude;
Line 1,267 ⟶ 1,666:
public start[Program] program(str s, loc l) {
return parse(#start[Program], s, l);
} </langsyntaxhighlight>
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/*┌───────────────────────────────────────────────────────────────────┐
│ The REXX language doesn't allow for the changing or overriding of │
│ syntax per se, but any of the built-in-functions (BIFs) can be │
Line 1,322 ⟶ 1,721:
│ the (below) statement as an error. │
└───────────────────────────────────────────────────────────────────┘ */
options strict_white_space_comparisons /*can be in lower/upper/mixed.*/</langsyntaxhighlight>
 
=={{header|Ring}}==
The next program add new method to the object class during the runtime
<langsyntaxhighlight lang="ring">
o1 = new point { x=10 y=20 z=30 }
addmethod(o1,"print", func { see x + nl + y + nl + z + nl } )
Line 1,332 ⟶ 1,731:
Class point
x y z
</syntaxhighlight>
</lang>
 
The next example presents how to create a class that defines two instructions
Line 1,339 ⟶ 1,738:
Also keywords that can be ignored like the ‘the’ keyword
 
<langsyntaxhighlight lang="ring">
New App
{
Line 1,384 ⟶ 1,783:
# Keywords to ignore, just give them any value
the=0
</syntaxhighlight>
</lang>
 
=={{header|Ruby}}==
An rudimentary example of metaprogramming is presented in this simple identification system template:
<langsyntaxhighlight lang="ruby">class IDVictim
# Create elements of this man, woman, or child's identification.
Line 1,399 ⟶ 1,798:
end
end</langsyntaxhighlight>
 
The "self.new_element" class method allows one to (later) specify a new attribute to be added to the defaults of "name", "birthday", "gender", and "hometown".
Line 1,406 ⟶ 1,805:
(This is not really metaprogramming, at least not under any useful meaning...)
 
<langsyntaxhighlight lang="runbasic">' ---------------------------------------------------
' create a file to be run
' RB can run the entire program
Line 1,437 ⟶ 1,836:
RUN "runned.bas",#handle ' setup run command to execute runned.bas and give it a handle
#handle displayText("Welcome!") ' only execute the function withing the runned program
render #handle ' render the handle will execute the program</langsyntaxhighlight>
 
=={{header|Rust}}==
Rust supports extensive metaprogramming via macros. Note that rust macros differ from, say, C preprocessor macros in that they are not mere text substitution (so operator precedence is preserved and name shadowing is not an issue). Here is an example from rustbyexample.com that implements and tests the <code>+=</code>, <code>-=</code>, and <code>*=</code> operators for Vectors.
 
<langsyntaxhighlight lang="rust">// dry.rs
use std::ops::{Add, Mul, Sub};
 
Line 1,499 ⟶ 1,898:
test!(mul_assign, 2u32, 3u32, 6u32);
test!(sub_assign, 3u32, 2u32, 1u32);
}</langsyntaxhighlight>
 
{{out}}
Line 1,511 ⟶ 1,910:
 
=={{header|Scala}}==
<langsyntaxhighlight Scalalang="scala">import scala.language.experimental.macros
import scala.reflect.macros.Context
 
Line 1,521 ⟶ 1,920:
 
def hello: Unit = macro impl
}</langsyntaxhighlight>
 
=={{header|Shen}}==
Being a Lisp, metaprogramming is easily achievable in Shen through macros. However, defining macros is only possible when the typechecker is off.
<langsyntaxhighlight lang="shen">(define make-list
[A|D] -> [cons (make-list A) (make-list D)]
X -> X)
Line 1,532 ⟶ 1,931:
[info Exp] -> [output "~A: ~A~%" (make-list Exp) Exp])
 
(info (* 5 6)) \\ outputs [* 5 6]: 30</langsyntaxhighlight>
Like most macro systems, defmacro looks like a function that takes a sexp and returns one. However, Shen's defmacro is special in that it allows arbitrary activation of sexps.
<langsyntaxhighlight lang="shen">(0-) (defmacro +-macro
[A + B] -> [+ A B])
macro
Line 1,540 ⟶ 1,939:
 
(1-) (1 + (* 2 3))
7</langsyntaxhighlight>
It's important to be careful when using macros like this; this example would be bad because + is sometimes used as an argument to a function (e.g. (fold-left + 0) would compile to (+ fold-left 0)). However, the fact that a symbol can at once match a macro and denote a function can give the illusion of optional arguments or polyadicity. This is how many mathematical operators and functions like append work while retaining their type signature:
<langsyntaxhighlight lang="shen">(2-) (tc +)
true
 
Line 1,555 ⟶ 1,954:
 
(6-) (macroexpand [+ 1 2 3])
[+ 1 [+ 2 3]]</langsyntaxhighlight>
 
=={{header|Sidef}}==
Sidef recognizes all mathematical operators in Unicode and allows the user to define methods that behave like infix operators, even for built-in types.
<langsyntaxhighlight lang="ruby">class Number {
method ⊕(arg) {
self + arg
Line 1,565 ⟶ 1,964:
}
 
say (21 ⊕ 42)</langsyntaxhighlight>
 
Another example of metaprogramming, is the definition of methods at run-time:
 
<langsyntaxhighlight lang="ruby">var colors = Hash(
'black' => "000",
'red' => "f00",
Line 1,588 ⟶ 1,987:
say "blue".in_blue
say "red".in_red
say "white".in_white</langsyntaxhighlight>
{{out}}
<pre>
Line 1,595 ⟶ 1,994:
<span style="color: #fff">white</span>
</pre>
 
=={{header|Smalltalk}}==
In Smalltalk, a class can redefine which compiler class is to be used when methods are compiled (aka "accepted in the class browser"). That compiler may be as simple as a subclass of the standard compiler with additional language features (such as additional literal types, extended string syntax etc.) or a completely different language build using one of the available compiler-compiler packages (tgen, petite - a peg parser, and others), or a hand written parser. There exists number of such packages to implement Scheme, Prolog, JavaScript, O-Meta, a number of domain specific language and data description languages (eg. for C data structures or ASN1 types).
 
As a simple example, here is how external library functions are handled by a pragma detector, to generate a callout to eg. C-functions:
<syntaxhighlight lang="smalltalk">apiSyslog:priority format:format message:message
<cdecl: int 'syslog' (int char* char*) >
^ self primitiveFailed.
</syntaxhighlight>
 
=={{header|SNOBOL4}}==
There are several features of SNOBOL4 which could be considered meta-programming. The first of these is the ability to define synonyms for existing operators or functions, a feature which can help in creating DSLs of sorts in SNOBOL4 programs. For example the following code will alias the built-in function <code>IDENT</code> to <code>SAME</code> and the unary operator <code>*</code> to <code>$</code>:
<langsyntaxhighlight lang="snobol4">
OPSYN('SAME','IDENT')
OPSYN('$','*',1)
</syntaxhighlight>
</lang>
 
This is a simplistic use of <code>OPSYN</code>, however. More interesting is the aliasing of a function to an operator:
<langsyntaxhighlight lang="snobol4">
OPSYN('F','*',1)
</syntaxhighlight>
</lang>
 
In this setup, calling <code>F(X)</code> is the same as using the sequence <code>*X</code> which, in more complicated expressions, could result in better readability.
 
Other metaprogramming features supported would include the use of unevaluated expressions. If, in code, <code>E</code> is an expression it has a value as soon as it is defined and/or assigned to. <code>*E</code>, on the other hand, has a value only when it is evaluated either in the context of a pattern or in the context of an <code>EVAL</code>. The following example shows the motivation for unevaluated expressions in pattern matching contexts:
<langsyntaxhighlight lang="snobol4">
&ANCHOR = 0 ; &TRIM = 1
WORD = BREAK(' .,') . W SPAN(' .,')
Line 1,621 ⟶ 2,029:
OUTPUT OUTPUT = LIST
END
</syntaxhighlight>
</lang>
 
In this code, two strings are input and a list of words appearing in both strings is generated. The problem with this code is that the pattern structure <code>' ' W ANY(' .,')</code> is built on each iteration. Since pattern building is expensive, putting it in a loop like this is bad form. It cannot be moved outside of the loop, however, since the value of W changes for each iteration. The solution to this is to defer the evaluation of the variable <code>W</code> until it is needed while keeping the rest of the pattern intact:
<langsyntaxhighlight lang="snobol4">
&ANCHOR = 0 ; &TRIM = 1
WORD = BREAK(' .,') . W SPAN(' .,')
Line 1,635 ⟶ 2,043:
OUTPUT OUTPUT = LIST
END
</syntaxhighlight>
</lang>
In this code, the pattern is constructed only once in the line <code>FINDW = ' ' *W ANY(' .,')</code>. The value of the variable <code>W</code>, however, is only provided when FINDW is used in a pattern match. In this case it is given its value from the line before when <code>STRING1</code> is matched against the pattern <code>WORD</code>. In this way the expense of building the pattern is paid only once, but the flexibility of matching a sequence of values is retained.
 
Line 1,641 ⟶ 2,049:
 
Consider this hand-waving example for the motivation:
<langsyntaxhighlight lang="snobol4">
* This example provides a bizarrely-expensive addition operation.
* It assumes the existence of an expensive procedure—say a database
Line 1,650 ⟶ 2,058:
XADD XADD = X + ADDVALUE :(RETURN)
XADD.END
</syntaxhighlight>
</lang>
 
In normal operation the interpreter will execute the <code>DEFINE</code> function and then execute the <code>ADDVALUE = ...</code> line, branching *past* the actual body of the function to the label <code>XADD.END</code>. If, however, there are many such functions, and especially if there's the possibility that these functions are never actually called, this could render program startup very slow. For purposes of amortizing initialization time, or for purposes of saving unnecessary initialization, the following code is better:
<langsyntaxhighlight lang="snobol4">
DEFINE('XADD(X)','XADD.INIT') :(XADD.END)
XADD.INIT ADDVALUE = CALL_SOME_EXPENSIVE_OPERATION()
Line 1,659 ⟶ 2,067:
XADD XADD = X + ADDVALUE :(RETURN)
XADD.END
</syntaxhighlight>
</lang>
 
The code now defines the <code>XADD</code> function and immediately, without doing initialization, jumps to the <code>XADD.END</code> label, bypassing both initialization and the function body. The trick here is that it defines the entry point of the function to be the <code>XADD.INIT</code> label. Now the first time <code>XADD</code> is called, control is transferred to <code>XADD.INIT</code>, the expensive initialization is performed, then the <code>XADD</code> function is *redefined* to point to the <code>XADD</code> label as the entry point. From this point onward all calls to <code>XADD</code> only perform the calculation, not the expensive initialization while the expensive initialization isn't paid at all unless the function is used at least once.
Line 1,666 ⟶ 2,074:
 
=={{header|Standard ML}}==
<syntaxhighlight lang="standard ml">
<lang Standard ML>
fun to (a, b) = List.tabulate (b-a,fn i => a+i ) ;
infix 5 to ;
</syntaxhighlight>
</lang>
example
<syntaxhighlight lang="standard ml">
<lang Standard ML>
- 2 to 9 ;
val it = [2,3,4,5,6,7,8] : int list
</syntaxhighlight>
</lang>
 
=={{header|Tcl}}==
Metaprogramming is considered to be normal in Tcl; the whole language was designed to support new operations that work with a similar level of integration to existing commands (and indeed, the standard commands are not syntactically special in any way), and the <code>upvar</code> and <code>uplevel</code> commands are ''specifically'' for this sort of use. Moreover, there are no language keywords that need to be worked around; words/tokens can be used to mean anything necessary. For example:
<langsyntaxhighlight lang="tcl">proc loopVar {var from lower to upper script} {
if {$from ne "from" || $to ne "to"} {error "syntax error"}
upvar 1 $var v
Line 1,691 ⟶ 2,099:
}
}
}</langsyntaxhighlight>
The above creates a new <code>loopVar</code> command that might be used like this:
<langsyntaxhighlight lang="tcl">loopVar x from 1 to 4 {
loopVar y from $x to 6 {
puts "pair is ($x,$y)"
if {$y >= 4} break
}
}</langsyntaxhighlight>
Which prints this:
<pre>
Line 1,718 ⟶ 2,126:
 
Finally, the total lack of keywords is exemplified by this classic fragment of Tcl:
<syntaxhighlight lang ="tcl">set set set</langsyntaxhighlight>
In this, the first <code>set</code> is a command (that updates a variable), the second is the name of a variable in the current namespace, and the third is a string that will be placed in a variable.
 
Line 1,734 ⟶ 2,142:
Example define a while loop which supports break and continue. Two forms of break are supported <code>break</code> which causes the loop to terminate with the return value <code>nil</code> and <code>(break &lt;form&gt;)</code> which returns the specified value.
 
<langsyntaxhighlight lang="txrlisp">(defmacro whil ((condition : result) . body)
(let ((cblk (gensym "cnt-blk-"))
(bblk (gensym "brk-blk-")))
Line 1,759 ⟶ 2,167:
(if (> i 30)
break)
(prinl i))))</langsyntaxhighlight>
 
{{out}}
Line 1,787 ⟶ 2,195:
=={{header|Wren}}==
Analogous to D's mixins, Wren has an optional Meta module which enables strings to be compiled to regular Wren code or expressions and inserted into the script. The D example looks like this in Wren.
<langsyntaxhighlight ecmascriptlang="wren">import "meta" for Meta
 
var genericClass = Fn.new { |cname, fname|
Line 1,799 ⟶ 2,207:
var CFoo = genericClass.call("Foo", "bar")
var foo = CFoo.new(10)
System.print([foo.bar, foo.type])</langsyntaxhighlight>
 
{{out}}
Line 1,805 ⟶ 2,213:
[10, Foo]
</pre>
 
=={{header|Z80 Assembly}}==
Meta-programming is very limited, but macros can make parameter passing much more straightforward.
 
<syntaxhighlight lang="z80">macro xchg,regpair1,regpair2
;swaps the contents of two registers.
push regpair1
push regpair2
pop regpair1
pop regpair2
endm</syntaxhighlight>
 
Then in your code you can do the following:
<syntaxhighlight lang="z80">xchg bc,de ;exchanges BC with DE</syntaxhighlight>
 
 
=={{header|zkl}}==
Meta programming is quite limited unless you hack the compiler (which is written in zkl) or you write a DSL. Otherwise, there is a "kinda like" C pre-processor support.
<langsyntaxhighlight lang="zkl">#define name [0|1]
#if [0|1|name]
#else, #endif</langsyntaxhighlight>
 
<langsyntaxhighlight lang="zkl">//Full zkl functionality but limited access to the parse stream; only #defines
#ifdef name
#fcn name {code}</langsyntaxhighlight>
 
<langsyntaxhighlight lang="zkl">// Shove text into the parse stream
#text name text
#tokenize name, #tokenize f, #tokenize f(a)</langsyntaxhighlight>
 
<langsyntaxhighlight lang="zkl">#<<<#
text, any text, inside #<<<# pairs is ignored
#<<<#</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">string:=
#<<<
"here docs:
Line 1,830 ⟶ 2,253:
can not span lines.";
#<<<
println(string); // contains newlines</langsyntaxhighlight>
In addition, there is a concept of "parse space/time" - it is after parsing and before compiling where the full power of the language can be used to "so stuff". For example, enums can be implemented like so:
<langsyntaxhighlight lang="zkl">const{ var _n=-1; var [proxy] N=fcn{ _n+=1 } }
const X=N; // → 0
println(_n); // → 2 code time is after const time
const Y=N,Z=N; // → 1,2</langsyntaxhighlight>
 
{{omit from|Ada}}
9,485

edits