Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/Sugar+command+macros?V=23
QUERY_STRINGV=23
CONTENT_TYPE
DOCUMENT_URI/revision/Sugar+command+macros
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.69.58.127
REMOTE_PORT51312
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR18.191.234.191
HTTP_CF_RAY87723b06ee4d112b-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_CF_CONNECTING_IP18.191.234.191
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit {Sugar command macros} ***\ NOTE\ ***\n\ The\ API\ changed\ in\ two\ ways,\ you\ should\ be\ aware\ of\ this\ if\ you\ want\ to\ try\ with\ the\ current\ release\ of\n\ sugar\ what\ is\ shown\ in\ this\ tutorial.\n\n\ First\ Change\ -\ Now\ macros\ are\ expanded\ only\ inside\ procedures\ defined\ with\ ::sugar::proc\n\ Second\ Change\ -\ Now\ macros\ get\ a\ list\ of\ arguments\ like\ normal\ procedures,\ but\ the\ first\ argument\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ macro\ name\ itself.\ All\ the\ macros\ in\ this\ tutorial\ will\ work\ substituting\ the\ 'argv'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ argument\ with\ 'args'.\n\n\ \ \ \ *\ Section\ 0\ -\ '''\[Sugar\]'''\n\ \ \ \ *\ Section\ 1\ -\ '''\[Sugar\ command\ macros\]'''\ (what\ you\ are\ reading)\n\ \ \ \ *\ Section\ 2\ -\ '''\[Sugar\ syntax\ macros\]'''\n\ \ \ \ *\ Section\ 3\ -\ '''\[Sugar\ transformers\]'''\n\n'''What\ is\ a\ Tcl\ macro'''.\n\nA\ macro\ is\ an\ operator\ implemented\ by\ transformation.\ Macros\ are\ procedures\nthat\ generate\ a\ Tcl\ program\ at\ compile\ time,\ and\ substitute\ it\ where\nthe\ programmer\ used\ their\ name\ as\ command.\n\nIt's\ a\ simple\ concept\ if\ explained\ by\ examples.\n\nSuppose\ you\ want\ to\ write\ a\ `clear`\ command\ that\ sets\ the\ ''varName''\ to\ a\ null\ string.\ It\ could\ be\ Implemented\ using\ `\[upvar\]`,\ like\ this:\n\n======\nproc\ clear\ varName\ \{\n\ \ \ \ upvar\ 1\ \$varName\ var\n\ \ \ \ set\ var\ \{\}\n\}\n======\n\nEvery\ time\ the\ user\ type\n\n======\nclear\ myvar\n======\n\nWhen\ `clear`\ is\ called,\ the\ `\$myvar`\ of\ the\ caller\ is\ set\ to\nto\ the\ \[empty\ string\].\n\nAs\ an\ alternative\ to\ call\ a\ procedure\ that\ is\ able\ to\ alter\ the\ caller's\nexecution\ environment,\ we\ may\ want\ to\ automatically\ substitute\ every\ occurrence\nof\ the\ command\ `clear\ varname`\ with\ `set\ varname\ \{\}`.\n\nSo\ basically\ we\ want\ that\ when\ we\ write\n\n======\nclear\ myvar\n======\n\nin\ a\ program,\ it\ is\ substitute\ with\n\n======\nset\ myvar\ \{\}\n======\n\nas\ if\ the\ programmer\ had\ really\ typed\ `set\ myvar\ \{\}`\ instead\ of\ `clear\ myvar`.\nThat's\ the\ goal\ of\ the\ simplest\ form\ of\ a\ \[Sugar\]'s\ macro.\n\nThe\ definition\ of\ a\ new\ macro\ is\ very\ similar\ to\ the\ creation\ of\ a\ procedure.\nThe\ following\ is\ the\ implementation\ of\ \[\[clear\]\]\ as\ a\ macro:\n\n======\nsugar::macro\ clear\ argv\ \{\n\ \ \ \ list\ set\ \[lindex\ \$argv\ 1\]\ \{\{\}\}\n\}\n======\n\nIt\ means:\ \"If\ you\ encounter\ a\ command\ called\ `clear`\ inside\ the\ source\ code,\ncall\ the\ following\ procedure\ putting\ all\ the\ parts\ of\ which\ the\ncommand\ is\ composed\ in\ `\$argv`,\ and\ substitute\ the\ occurrence\ of\ the\ clear\ncommand\ and\ arguments,\ with\ what\ the\ procedure\ will\ return.\"\n\nAgain,\ with\ other\ words:\n\nSo,\ what\ happens\ is\ that\ when\ a\ procedure\ is\ compiled,\ for\ every\noccurrence\ of\ the\ `clear`\ command\ inside\ the\ procedure,\ the\ above\nprocedure\ is\ called,\ with\ `\$argv`\ set\ to\ a\ list\ that\ represents\ the\ arguments\nused\ to\ call\ the\ macro\ (including\ the\ macro\ name\ itself\ as\ first\ argument).\nThe\ result\ value\ of\ the\ function,\ that\ should\ be\ a\ list\ of\ the\ same\ form,\ is\nsubstituted\ in\ place\ of\ the\ original\ macro\ call.\n\nTo\ make\ the\ example\ more\ concrete,\ see\ the\ following\ code:\n\n======\nproc\ foobar\ \{\n\ \ \ \ set\ x\ 10\n\ \ \ \ clear\ x\n\}\n======\n\n'''Before\ compiling\ the\ procedure''',\ Tcl\ will\ call\ the\ `clear`\ procedure\ \nwith\ `\$argv`\ set\ to\ `clear\ x`.\nThat\ procedure\ returns\ `set\ x\ \{\{\}\}`,\nThis\ return\ value\ will\ be\ substituted\ in\ place\ of\ \"clear\ x\".\n\nAfter\ the\ proc\ was\ defined,\ we\ can\ use\ `\[info\ body\]`\nto\ see\ what\ happened:\n\n======\ninfo\ body\ proc\n======\n\nwill\ output\n\n======\nset\ x\ 10\nset\ x\ \{\}\n======\n\n`\[Sugar\]`\ makes\ it\ possible\ to\ use\ a\ macro\ like\ `clear`\ as\ if\ it\ it\ was\ a\ Tcl\nprocedure,\ and\ the\ macro\ is\ called\ at\ compile\ time\ to\ produce\ the\ procedure\nthat\ replaces\ it.\n\nBut\ Tcl\ has\ `\[uplevel\]`\ and\ `\[upvar\]`,\ so\ what\ are\ macros\nuseful\ for?\ Fortunately\ they\ allow\ for\ many\ interesting\ things\nnot\ possible\ at\ all\ otherwise.\ \ The\ following\ example\nshows\ the\ first\ big\ advantage\ of\ macros:\n\n'''1)\ Macros\ makes\ Tcl\ faster,\ without\ forcing\ the\ user\ to\ inline\ code\nby\ hand.'''\n\nWhen\ `clear`\ is\ implemented\ as\ macro,\ it\ runs\ 3\ times\ faster\ in\ my\ Tcl\ 8.4.\n\nAlso,\ `\[upvar\]`\ is\ one\ of\ the\ biggest\ obstacles\ to\ the\ ability\nof\ the\ Tcl\ compiler\ to\ optimize\ Tcl\ \[bytecode\],\ it's\ not\ impossible\nthat\ at\ some\ point\ Tcl\ will\ be\ able\ to\ run\ much\ faster\nif\ the\ user\ will\ ensure\ a\ given\ procedure\ is\ never\ the\ target\ of\ `\[upvar\]`.\n\nSimple\ commands\ that\ involve\ the\ use\ of\ `\[upvar\]`\ can\ be\ even\nmore\ simple\ to\ write\ as\ macros.\ The\ following\ are\ four\ examples:\n\n======\n#\ \[first\ \$list\]\ -\ expands\ to\ \[lindex\ \$list\ 0\]\nsugar::macro\ first\ argv\ \{\n\ \ \ \ list\ lindex\ \[lindex\ \$argv\ 1\]\ 0\n\}\n\n#\ \[rest\ \$list\]\ -\ expands\ to\ \[lrange\ \$list\ 1\ end\]\nsugar::macro\ rest\ argv\ \{\n\ \ \ \ list\ lrange\ \[lindex\ \$argv\ 1\]\ 1\ end\n\}\n\n#\ \[last\ \$list\]\ -\ expands\ to\ \[lindex\ \$list\ end\]\nsugar::macro\ last\ argv\ \{\n\ \ \ \ list\ lindex\ \[lindex\ \$argv\ 1\]\ end\n\}\n\n#\ \[drop\ \$list\]\ -\ expands\ to\ \[lrange\ \$list\ 0\ end-1\]\nsugar::macro\ drop\ argv\ \{\n\ \ \ \ list\ lrange\ \[lindex\ \$argv\ 1\]\ 0\ end-1\n\}\n======\n\n\[Sugar\]\ supports\ three\ types\ of\ macros.\ We\ are\ dealing\ with\nthe\ simplest\ and\ more\ common\ macros:\ command\ macros.\n\nThe\ other\ two\ types,\ syntax\ macros,\ and\ transformers,\nwill\ be\ covered\ later.\ For\ now\ let's\ go\ to\ create\na\ more\ complex\ macro.\n\n'''A\ more\ complex\ example'''\n\nGood\ macros\ do\ source\ code\ transformation\ in\ a\ smart\ way,\nthey\ turn\ a\ form\ that\ is\ undestood\ by\ the\nprogrammer\ into\ code\ that\ is\ also\ understood\ by\ the\ compiler,\nthat's\ hard\ to\ type\ and\ use\ in\ raw\ form\ without\ the\nmacro\ support,\ but\ optimal\ otherwise.\n\nIdeally\ a\ macro\ should\ expand\ to\ a\ single\ command\ call\n(possibly\ including\ many\ other\ nested),\ and\ should\ not\nexpand\ to\ code\ that\ magically\ creates\ variables\ at\nruntime\ to\ store\ intermediate\ results\ all\ the\ times\ it\ncan\ be\ avoided\ (because\ there\ may\ be\ collisions\ with\nvariables\ in\ the\ function,\ or\ created\ by\ other\ bad\ macros.\nBtw,\ in\ the\ TODO\ list\ of\ sugar\ there\ is\ a\ way\ to\ generate\nunique\ local\ variable\ names).\n\nIf\ the\ macro\ is\ well\ written,\ then\ the\ programmer\ can\ use\ it\ like\nany\ other\ command\ without\ to\ care\ much.\n\nWe\ will\ see\ a\ more\ real\ example\ of\ macro\ that\ implements\na\ very\ efficient\ `\[lpop\]`\ operator.\ It\ accepts\ only\ one\nargument,\ the\ name\ of\ a\ variable,\ and\ returns\ the\ last\nelement\ of\ the\ list\ stored\ inside\ the\ given\ variable.\nAs\ side\ effect,\ `lpop`\ removes\ the\ last\ element\ from\ the\ list.\n(it's\ something\ like\ the\ complement\ of\ `\[lappend\]`).\n\nA\ pure-Tcl\ implementation\ is\ the\ following:\n\n======\nproc\ lpop\ listVar\ \{\n\ \ \ \ upvar\ 1\ \$listVar\ list\n\ \ \ \ set\ res\ \[lindex\ \$list\ end\]\n\ \ \ \ set\ list\ \[lrange\ \$list\ 1\ end\]\n\ \ \ \ return\ \$res\n\}\n======\n\nThis\ version\ of\ `lpop`\ is\ really\ too\ slow.\ In\ fact\ when\n`\[lrange\]`\ is\ called,\ it\ creates\ a\ new\ list\ object\ even\nif\ the\ original\ one\ stored\ in\ the\ `\$list`\ variable\ is\ going\nto\ be\ freed\ and\ replaced\ by\ the\ copy.\ To\ modify\ the\ list\nin-place\ is\ far\ better.\n\nThe\ `\[lrange\]`\ implementation\ is\ able\ to\ perform\ this\noptimization\ if\ the\ object\ in\ \"not\ shared\"\ (if\ you\ don't\nknow\ about\ this\ stuff\ try\ to\ read\ the\ Wiki\ page\ about\ the\n`\[K\]`\ operator\ before\ to\ continue)\n\nSo\ it's\ better\ to\ write\ the\ proc\ using\ the\ `\[K\]`\ operator.\nThe\ lrange\ line\ should\ be\ changed\ to\ this:\n\n======\nset\ list\ \[lrange\ \[K\ \$list\ \[set\ list\ \{\}\]\]\ 1\ end\]\n======\n\nWith\ `K`\ being:\n\n======\nproc\ K\ \{x\ y\}\ \{\n\ \ \ \ return\ \$x\n\}\n======\n\nBut\ even\ to\ call\ `\[K\]`\ is\ costly\ in\ terms\ of\ performace,\ so\nwhy\ not\ inline\ it\ also?\ Doing\ it\ requires\ changing\nthe\ previous\ lrange\ line\ to\ this:\n\n======\nset\ list\ \[lrange\ \[lindex\ \[list\ \$list\ \[set\ list\ \{\}\]\]\ 0\]\ 1\ end\]\n======\n\nThat's\ really\ a\ mess\ to\ read,\ but\ works\ at\ a\ different\ speed,\ and\neven\ more\ important,\ at\ a\ different\ time\ complexity!.\n\nWith\ a\ macro\ for\ `lpop`,\ we\ can\ go\ even\ faster,\ and\ the\ code\ is\ easier\ to\nmaintain\ and\nread.\ Macros\ are\ allowed\ to\ expand\ to\ commands\ containing\nother\ macros,\ recursively.\ This\ means\ that\ we\ can\ write\ a\ macro\nfor\ every\ single\ step\ of\ `lpop`.\ We\ need\ the\ `first`\n`last`\ and\ `drop`\ macros\ already\ developed,\ and\ a\ macro\ for\ `\[K\]`:\n\n======\nsugar::macro\ K\ argv\ \{\n\ \ \ \ foreach\ \{x\ y\}\ \$argv\ break\n\ \ \ \ list\ first\ \[list\ \$x\ \$y\]\n\}\n======\n\nNote\ that\ for\ speed,\ we\ used\ `\[foreach\]`\ instead\ of\ two\ calls\ to\ `\[lindex\]`.\nBut\ remember\ that\ macros\ '''don't\ have\ to\ be\ fast\ in\ the\ generation'''\ of\ the\nexpanded\ code.\n\n`K\ \$x\ \$y`\ expands\ to\ `first\ \[\[list\ \$x\ \$y\]\]`,\ which\ expands\ to\ `lindex\ \[\[list\ \$x\ \$y\]\]\ 0`.\n\nWe\ have\ one\ last\ problem.\ Even\ after\ the\ optimization\ and\ the\nuse\ of\ `K`\ inline,\ the\ procedure\ above\ required\ a\ local\nvariable\ 'res'\ to\ save\ the\ last\ argument\ of\ the\ list\ before\nto\ modify\ it,\ and\ use\ `\$res`\ later\ as\ return\ value\ for\ the\ procedure.\nWe\ don't\ want\ to\ create\ local\ vars\ into\ the\ code\ that\ calls\nthe\ `lpop`\ macro,\ nor\ do\ we\ want\ to\ expand\ to\ more\ than\ a\ single\ncommand.\ The\ `\[K\]`\ operator\ can\ help\ us\ to\ do\ so:\n\n======\nset\ res\ \[lindex\ \$list\ end\]\nset\ list\ \[lrange\ \[lindex\ \[list\ \$list\ \[set\ list\ \{\}\]\]\ 0\]\ 1\ end\]\nreturn\ \$res\n======\n\nleading\ to:\n\n======\nK\ \[lindex\ \$list\ end\]\ \[set\ list\ \[lrange\ \[lindex\ \[list\ \$list\ \[set\ list\ \{\}\]\]\ 0\]\ 1\ end\]\]\n======\n\nThat's\ ok,\ but\ what\ an\ unreadable\ code!\ Thanks\ to\ macros\nwe\ can\ abstract\ from\ the\ fact\ that\ to\ call\ procedures\ is\nslow,\ so\ we\ just\ write:\n\n======\n\[K\ \[last\ \$list\]\ \[set\ list\ \[rest\ \[K\ \$list\ \[set\ list\ \{\}\]\]\]\]\]\n======\n\nWill\ not\ win\ the\ clean-code\ context\ this\ year,\ but\ it's\ much\nbetter\ than\ the\ previous.\ Ok...\ now\ we\ want\ a\ macro\ that,\ every\ time\ we\ntype\ `lpop\ \$list`,\ will\ expand\ in\ the\ above\ line:\n\n======\nsugar::macro\ lpop\ argv\ \{\n\ \ \ \ set\ varname\ \[lindex\ \$argv\ 1\]\n\ \ \ \ set\ argv\ \[list\ K\ \\\n\ \ \ \ \ \ \ \ \{\[last\ \$%varname%\]\}\ \\\n\ \ \ \ \ \ \ \ \{\[set\ list\ \[drop\ \[K\ \$%varname%\ \[set\ %varname%\ \{\}\]\]\]\]\}\n\ \ \ \ \]\n\ \ \ \ foreach\ i\ \{1\ 2\}\ \{\n\ \ \ \ \ \ \ \ lset\ argv\ \$i\ \[string\ map\ \[list\ %varname%\ \$varname\]\ \[lindex\ \$argv\ \$i\]\]\n\ \ \ \ \}\n\ \ \ \ return\ \$argv\n\}\n======\n\nThere\ are\ few\ things\ to\ note\ about\ this\ code.\ The\ macro\ returns\na\ list,\ where\ every\ element\ is\ a\ token\ of\ a\ Tcl\ command\nin\ the\ source\ code.\ This\ does\ not\ mean\ we\ have\ to\ transform\ in\nlists\ even\ arguments\ that\ happens\ to\ represent\ a\ script.\ Also\nnote\ that\ the\ input\ list\ of\ the\ macro\ is\ just\ a\ list\ of\ tokens\nthat\ are\ *exactly*\ what\ the\ user\ typed\ they\ in\ the\ source\ code,\ verbatim.\nWhat\ follows\ is\ that\ the\ tokens\ are\ already\ quoted\ and\ valid\nrepresentations\ of\ a\ procedure\ argument.\nWe\ don't\ need\ to\ care\ about\ the\ fact\ that\ they\ must\ be\ interpreted\nas\ a\ single\ argument\ as\ we\ sould\ when\ generating\ code\ for\ `\[eval\]`.\n\nThis\ allows\ the\ macro\ developer\ to\ use\ templates\ for\ macros,\ in\nfact\ the\ `lpop`\ macro\ is\ just\ using\ a\ three\ argument\ template,\nand\ the\ final\ foreach\ will\ substitute\ the\ arguments\ that\ needs\nto\ refer\ to\ the\ variable\ name,\ with\ that\ name.\ You\ don't\ have\nto\ care\ what\ that\ variable\ name\ is.\ It\ can\ be\ a\ complex\ string\nformed\ by\ more\ commands,\ vars,\ and\ so\ on\ `\[\[like\]\]\[\[this\]\]\$and-this`.\nIf\ it\ was\ a\ single\ argument\ in\ the\ source\ code,\ it\ will\ be\ in\ the\ macro\nafter\ the\ expansion.\n\nAnother\ interesting\ thing\ to\ note\ is\ that\ we\ don't\ really\ have\nto\ return\ every\ token\ as\ a\ different\ element\ of\ the\ list.\ In\ pratice\nwe\ can\ return\ it\ even\ as\ a\ single-element\ list.\nThe\ rule\ is\ that\ the\ macro\ expander\ will\ care\ to\ put\ an\ argument\nseparator\ like\ a\ tab,\ or\ a\ space,\ for\ every\ element\ of\ the\nlist,\ and\ put\ a\ command\ separator\ like\ newline\ or\ `\;`\ at\ the\ end.\nIf\ we\ put\ spaces\ ourself,\ we\ can\ just\ return\ a\ single\ element\ list.\n\nSo,\ the\ `lpop`\ macro\ can\ also\ by\ written\ in\ this\ way:\n\n======\nsugar::macro\ lpop\ argv\ \{\n\ \ \ \ set\ varname\ \[lindex\ \$argv\ 1\]\n\ \ \ \ set\ cmd\ \[format\ \{\n\ \ \ \ \ \ \ \ K\ \[last\ \$%varname%\]\ \[set\ list\ \[drop\ \[K\ \$%varname%\ \[set\ %varname%\ \{\}\]\]\]\]\n\ \ \ \ \}\ \$varname\ \$varname\ \$varname\]\n\ \ \ \ return\ \[list\ \$cmd\]\n\}\n======\n\nThis\ is\ much\ more\ simple\ and\ clean,\ and\ actually\ it's\ possible\ to\nuse\ this\ style.\ The\ difference\ is\ that\ returning\ every\ token\ as\na\ different\ element\ of\ a\ list\ makes\ `\[Sugar\]`\ macros\ able\ to\nleft\ the\ indentation\ of\ the\ original\ code\ unaltered.\ This\ is\ helpful\nboth\ to\ take\ procedure\ error's\ line\ numbers\ correct,\ and\ to\nsee\ a\ good-looking\ output\ of\ `\[info\ body\]`.\ But\ as\ long\ as\nmost\ macros\ are\ about\ commands\ that\ are\ just\ typed\ in\ the\ same\ line\ntogether\ with\ all\ the\ arguments,\ for\ many\ macros\ is\ just\ a\ matter\ of\ tastes.\n\nIf\ you\ are\ implementing\ control\ structures\ that\ are:\n\n======\nindented\ in\ \{\n\ \ \ \ this\ way\n\}\n======\n\nIt's\ another\ question,\ and\ it's\ better\ to\ return\ every\ token\ as\ a\nlist\ element.\n\n'''Number\ of\ argument\ and\ other\ static\ checks\ in\ macros'''\n\nMacros\ expand\ to\ code\ that\ will\ raise\ an\ error\ if\ the\ number\ of\narguents\ is\ wrong\ in\ most\ cases,\ but\ it's\ possible\ to\ add\ this\ncontrol\ inside\ the\ macro.\ Actually\ it's\ a\ big\ advantage\ of\ macros\nbecause\ they\ are\ able\ to\ signal\ a\ bad\ number\ of\ arguments\ at\nrun\ time:\ this\ can\ help\ to\ write\ applications\ that\ are\ more\ reliable.\nIt's\ even\ possible\ to\ write\ a\ macro\ that\ expands\ to\ exactly\ what\nthe\ user\ typed\ in,\ but\ as\ side\ effect\ does\ a\ static\ check\ for\nbad\ number\ (or\ format)\ of\ arguments:\n\n======\nsugar::macro\ set\ argv\ \{\n\ \ \ if\ \{\[llength\ \$argv\]\ !=\ 3\ ||\ \[llength\ \$argv\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ error\ \"Bad\ number\ of\ arguments\ for\ set\"\n\ \ \ \}\n\ \ \ return\ \$argv\n\}\n======\n\nThis\ macro\ returns\ `\$argv`\ itself,\ so\ it's\ an\ identity\ transformation,\nbut\ will\ raise\ errors\ for\ `\[set\]`\ with\ a\ bad\ number\ of\narguments\ even\ for\ code\ that\ will\ never\ be\ reached\nin\ the\ application.\ Note\ that\ the\ previous\ macro\ for\ set\ is\ a\ bit\nincomplete:\ to\ get\ it\ right\ we\ should\ add\ checks\ for\ arguments\nthat\ starts\ with\ `\[\{*\}\]`,\ for\ this\ reason\ `\[Sugar\]`\ will\ provide\ a\ function\nto\ automatically\ search\ for\ a\ bad\ number\ of\ arguments\ in\ some\nnext\ version.\n\nNote\ that\ `\[\{*\}\]`\ introduces\ for\ the\ first\ time\ the\ possibility\ for\na\ command\ to\ get\ a\ number\ of\ arguments\ that\ is\ non\ evident\ reading\nthe\ source\ code\ but\ computed\ at\ runtime.\ Actually,\ `\{*\}`\ is\ an\nadvantage\ for\ static\ checks\ because\ prior\ to\ it,\ the\ way\ to\ngo\ was\ `\[eval\]`,\ that\ does\ totally\ \"hide\"\ the\ called\ command\ postponing\nall\ the\ work\ at\ run-time.\ With\ `\{*\}`\ it's\ always\ possible\nto\ say\ from\ the\ source\ code\ that\ a\ command\ is\ called\ with\ *at\ least*\ N\narguments.\ Still,\ to\ add\ new\ syntax\ to\ Tcl\ will\ probably\ not\ play\nwell\ with\ macros\ and\ other\ form\ of\ source\ code\ processing.\n\nIdentity\ macros\ are\ very\ powerful\ to\ perform\ static\ syntax\ checks,\nthey\ can\ not\ only\ warn\ on\ bad\ number\ of\ arguments,\ but\ with\ the\ntype\ of\ this\ arguments.\ See\ for\ example\ the\ following\ identity\nmacro\ for\ \"string\ is\":\n\n======\nproc\ valid_string_class\ class\ \{\n\ \ \ \ set\ classes\ \{alnum\ alpha\ ascii\ control\ boolean\ digit\ double\ false\ graph\ integer\ lower\ print\ punct\ space\ true\ upper\ wordchar\ xdigit\}\n\ \ \ \ set\ first\ \[string\ index\ \$class\ 0\]\n\ \ \ \ if\ \{\$first\ eq\ \{\$\}\}\ \{return\ 1\}\n\ \ \ \ if\ \{\$first\ eq\ \{\[\}\}\ \{return\ 1\}\n\ \ \ \ if\ \{\[lsearch\ \$classes\ \$class\]\ !=\ -1\}\ \{return\ 1\}\n\ \ \ \ return\ 0\n\}\n\nsugar::macro\ string\ argv\ \{\n\ \ \ \ if\ \{\[lindex\ \$argv\ 1\]\ eq\ \{is\}\ &&\ \[llength\ \$argv\]\ >\ 2\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[valid_string_class\ \[lindex\ \$argv\ 2\]\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Warning:\ invalid\ string\ class\ in\ procedure\ \[sugar::currentProcName\]\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$argv\n\}\n======\n\nThanks\ to\ this\ macro\ it's\ possible\ to\ ensure\ that\ errors\ that\ like\ to\ write\n`string\ is\ number`\ instead\ `\[string\ is\]\ integer`\ are\ discovered\ at\ncompile-time.\ In\ this\ respect\ macros\ can\ be\ seen\ as\ a\ programmable\nstatic\ syntax\ checker\ for\ Tcl.\ We\ will\ see\ how\ \"syntax\ macros\"\ are\neven\ more\ useful\ in\ this\ respect.\ This\ is\ the\ second\ feature\ that\nmacros\ add\ to\ Tcl:\n\n'''2)\ Macros\ are\ a\ powerful\ programmable\ static\ checker\ for\ Tcl\ scripts.'''\n\nActually\ I\ think\ it's\ worth\ to\ use\ macros\ even\ only\ for\ this\ during\nthe\ development\ process,\ and\ than\ flush\ they\ away.\n\n'''Conditional\ compilation'''\n\nThat's\ small\ and\ neat:\ we\ can\ write\ a\ simple\ macro\ that\ expands\ to\nsome\ code\ only\ if\ a\ global\ variable\ is\ set\ to\ non-zero.\ Let's\nwrite\ this\ macro\ that\ we\ call\ \[\[debug\]\].\n\n======\nsugar::macro\ debug\ argv\ \{\n\ \ \ if\ \{\$::debug_mode\}\ \{\n\ \ \ \ \ \ \ list\ if\ 1\ \[lindex\ \$argv\ 1\]\n\ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ list\n\ \ \ \}\n\}\n======\n\nThan\ you\ can\ use\ it\ in\ your\ application\ like\ if\ it\ was\ a\ conditional:\n\n======\n#\ Your\ application\ ...\ndebug\ \{\n\ \ \ \ set\ c\ 0\n\}\nwhile\ 1\ \{\n\ \ \ \ debug\ \{\n\ \ \ \ \ \ \ \ incr\ c\n\ \ \ \ \ \ \ \ if\ \{\$c\ >\ 100\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"Too\ many\ iteractions...\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ ....\ do\ something\ ....\n\}\n======\n\nif\ the\ value\ of\ `\$::debug_mode`\ is\ true,\ all\ the\ `debug\ \{someting\}`\ commands\nare\ compiled\ as\ `if\ 1\ \{something\}`.\ Otherwise,\ they\ will\ not\ be\ compiled\ at\nall.\n\nThat's\ the\ simplest\ example,\ you\ can\ write\ similar\ macros\ like\ `ifunix`,\n`ifwindows`,\ `ifmac`,\ or\ even\ to\ expand\ to\ different\ procedures\ call\nif\ a\ given\ command\ is\ called\ with\ 2,\ 3\ or\ 4\ arguments.\ The\ limit\ is\nthe\ immagination.\n\n'''New\ control\ stuctures'''\n\nNot\ all\ the\ programming\ languages\ allow\ to\ write\ new\ control\ structures.\nTcl\ is\ one\ of\ the\ better\ languages\ that\ don't\ put\ the\ programmer\ninside\ a\ jail,\ but\ not\ all\ the\ programming\ languages\ that\ allow\nto\ write\ new\ control\ structures\ are\ able\ to\ make\ them\ efficient.\n\nTcl\ macros\ can\ make\ new\ control\ structures\ as\ fast\ as\ \[bytecode%|%byte-compiled\]\ncontrol\ structures,\ because\ user\ defined\ ones\ are\ usually\ syntax\ glue\nfor\ code\ transformations.\ Being\ macro\ transformers\nthat\ translates\ a\ from\ to\ another,\ that's\ a\ good\ fit\ for\ macros.\n\nHere\ is\ a\ macro\ for\ the\ `?:`\ operator.\n\n======\n#\ ?:\ expands\n#\ \ \ ?:\ cond\ val1\ val2\n#\ to\n#\ \ \ if\ \$cond\ \{format\ val1\}\ \{format\ val2\}\nsugar::macro\ ?:\ argv\ \{\n\ \ \ \ if\ \{\[llength\ \$argv\]\ !=\ 4\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Wrong\ number\ of\ arguments\"\n\ \ \ \ \}\n\ \ \ \ foreach\ \{_\ cond\ val1\ val2\}\ \$argv\ break\n\ \ \ \ list\ if\ \$cond\ \[list\ \[list\ format\ \$val1\]\]\ \[list\ \[list\ format\ \$val2\]\]\n\}\n======\n\nThe\ macro's\ comment\ shows\ the\ expansion\ performed.\nBeing\ it\ translated\ to\ an\ `\[if\]`\ command,\ it's\ as\ fast\ as\ a\nTcl\ builtin.\n\n'''How\ macros\ knows\ what's\ a\ script?'''\n\nIn\ Tcl\ there\ are\ no\ types,\ nor\ special\ syntaxes\ for\ what\ is\ code\nand\ what\ is\ just\ a\ string,\ so\ you\ may\ wonder\ why\ macros\ are\nnot\ expanded\ in\ the\ following\ code:\n\n======\nputs\ \{\n\ \ \ \ set\ foo\ \{1\ 2\ 3\}\;\ \[first\ \$foo\]\n\}\n======\n\nBut\ they\ are\ expanded\ in\ this:\n\n======\nwhile\ 1\ \{\n\ \ \ \ set\ foo\ \{1\ 2\ 3\}\;\ \[first\ \$foo\]\n\}\n======\n\nI\ guess\ this\ is\ one\ of\ the\ main\ problems\ developers\ face\ designing\ a\nmacro\ system\ for\ Tcl,\ and\ even\ one\ of\ the\ better\ helpers\ of\ the\ idea\nthat\ a\ good\ macro\ system\ for\ Tcl\ is\ impossible\ because\ you\ can't\nsay\ what\ is\ code\ and\ what\ isn't.\n\n\[Sugar\]\ was\ designed\ to\ address\ this\ problem\ in\ the\ simplest\ possible\nof\ the\ ways:\ because\ it\ can't\ say\ if\ an\ argument\ is\ a\ script\ or\ not,\nmacro\ expansion\ is\ not\ performed\ in\ arguments,\ so\ in\ theory\ \[Sugar\]\nwill\ not\ expand\ the\ code\ that's\ argument\ to\ `\[puts\]`,\ nor\ `\[while\]`.\n\nBut\ of\ course,\ in\ the\ real\ world\ for\ a\ macro\ system\ to\ be\ usable,\nmacros\ should\ be\ expanded\ inside\ the\ `\[while\]`,\ and\ not\ expanded\ in\ `\[puts\]`,\nso\ the\ idea\ is\ that\ for\ commands\ that\ you\ know\ accept\ a\ script\ as\ an\ argument,\nyou\ write\ a\ macro\ that\ returns\ the\ same\ command\ but\ with\nscript\ arguments\ macro-expanded.\ It\ is\ very\ simple\ and\ in\ pratice\nthis\ works\ well.\ For\ example\ that's\ the\ macro\ for\ `\[while\]`:\n\n======\nsugar::macro\ while\ argv\ \{\n\ \ \ \ lset\ argv\ 1\ \[sugar::expandExprToken\ \[lindex\ \$argv\ 1\]\]\n\ \ \ \ lset\ argv\ 2\ \[sugar::expandScriptToken\ \[lindex\ \$argv\ 2\]\]\n\}\n======\n\nThat's\ the\ macro\ for\ \[if\]:\n\n======\nsugar::macro\ if\ argv\ \{\n\ \ \ \ lappend\ newargv\ \[lindex\ \$argv\ 0\]\n\ \ \ \ lappend\ newargv\ \[sugar::expandExprToken\ \[lindex\ \$argv\ 1\]\]\n\ \ \ \ set\ argv\ \[lrange\ \$argv\ 2\ end\]\n\ \ \ \ foreach\ a\ \$argv\ \{\n\ \ \ \ \ \ \ \ switch\ --\ \$a\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ else\ -\ elseif\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ newargv\ \$a\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \n\ \ \ \ \ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ newargv\ \[sugar::expandScriptToken\ \$a\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$newargv\n\}\n======\n\nAs\ you\ can\ see,\ \[Sugar\]\ exports\ an\ API\ to\ perform\ expansion\ in\nTcl\ scripts\ and\ Expr\ expressions.\ There\ are\ similar\ macros\ for\n`\[switch\]`,\ `\[for\]`,\ and\ so\ on.\ If\ you\ write\ a\ new\ conditional\ or\nloop\ command\ with\ macros,\ you\ don't\ need\ it\ at\ all\ because\nthe\ macro\ will\ translate\ to\ code\ that\ contains\ some\ form\ of\na\ well\ known\ built-in\ conditional\ or\ loop\ command,\ and\ we\ already\nhave\ macros\ for\ this\ (remember\ that\ macros\ can\ return\ code\ with\nmacros).\n\nIf\ you\ write\ any\ other\ command\ that\ accept\ as\ arguments\ a\ Tcl\ script\nor\ expr\ expression,\ just\ write\ a\ little\ macro\ for\ it\ to\ do\nmacro\ expansion.\ This\ has\ a\ nice\ side\ effect:\n\n======\nproc\ nomacro\ script\ \{\n\ \ \ \ uplevel\ 1\ \$script\n\}\n======\n\nDon't\ write\ a\ macro\ for\ nomacro,\ and\ you\ have\ a\ ready-to-use\ncommand\ that\ works\ as\ a\ barrier\ for\ macro\ expansion.\n\nContinue\ with\ section\ 2\ -\ '''\[Sugar\ syntax\ macros\]'''\n\n----\n\n\[WHD\]:\ This\ is\ very\ cool,\ but\ I\ have\ to\ ask--why\ not\ allow\ macros\ to\nhave\ a\ standard\ Tcl\ argument\ list?\ \ That\ is,\ \n\n======\nsugar::macro\ mymacro\ args\ \{...\}\n======\n\nGives\ the\ behavior\ you\ describe\ here,\ while\n\n======\nsugar::macro\ mymacro\ \{a\ b\ c\}\ \{...\}\n======\n\nexplicitly\ creates\ a\ macro\ that\ takes\ three\ arguments\ and\ will\ngenerate\ a\ standard\ error\ message\ if\ you\ supply\ some\ other\ number?\n\n----\n\n\[SS\]:\ This\ can\ be\ a\ good\ idea,\ being\ always\ possible\ to\nuse\ `args`\ as\ only\ argument\ to\ have\ the\ current\ behaviour.\ I\ used\na\ single\ list\ as\ input\ mainly\ because\ the\ same\ macro\ can\ have\ more\nthen\ a\ name,\ and\ in\ order\ to\ have\ the\ same\ interface\ for\ both\ncommand\ macros\ and\ syntax\ macros.\ For\ example:\n\n======\nsugar::macro\ \{*\ +\ -\ /\}\ argv\ \{\n\ \ \ \ list\ expr\ \[list\ \[join\ \[lrange\ \$argv\ 1\ end\]\ \"\ \[lindex\ \$argv\ 0\]\ \"\]\]\n\}\n======\n\nWill\ handle\ `*\ +\ -\ /`\ with\ the\ same\ code.\ Macros\ with\ more\ than\ a\ name\nmay\ in\ extreme\ cases\ even\ give\ different\ meanings\ for\ arguments\ in\nthe\ same\ position.\ Btw\ there\ is\ 'args'\ for\ this\ case.\ So\ I\ can\ change\nthe\ API\ to\ something\ like\ this:\n\n======\nsugar::macro\ \{name\ arg1\ arg2\ ...\}\ \{...\}\n======\n\nThat's\ like\ a\ Tcl\ proc,\ but\ with\ the\ name\ that\ was\ used\ to\ call\ the\ macro\nas\ the\ first\ argument.\ For\ syntax\ macros,\ this\ format\ actually\ may\ not\ make\ a\nlot\ of\ sense,\ but\ there\ is\ still\ `args`.\ I'll\ include\ this\ change\ in\ the\nnext\ version\ if\ I'll\ not\ receive\ feedbacks\ against\ it.\ Thanks\ for\ the\nfeedback\ WHD.\n\n\[WHD\]:\ I\ think\ that\ on\ the\ whole\ I\ prefer\ the\ previous\ syntax\ for\ command\nmacros\;\ the\ macro\ can\ always\ have\ an\ implicit\ argument\ that\ is\ the\nmacro\ name.\ \ For\ example,\n\n======\n#\ Identity\ macro\nsugar::macro\ \{+\ -\ *\ /\}\ \{args\}\ \{\ return\ \"\$macroname\ \$args\"\ \}\n======\n\n\[JMN\]:\ I'd\ just\ like\ to\ add\ my\ vote\ for\ removing\ the\ macroname\ as\ first\ argument\ syntax.\nFrom\ my\ hacking\ about,\ it\ seems\ easy\ to\ make\ it\ implicitly\ available\ more\ or\ less\ as\ WHD\ suggests.\n(I\ don't\ *think*\ I\ broke\ anything..\ )\n\n----\n\n\[SS\]:\ For\ a\ different\ question\ about\ the\ sugar\ API,\ I\ wonder\ if\ Tclers\ninterested\ in\ this\ macro\ system\ feel\ better\ about\ the\ current\ redefinition\nof\ `\[proc\]`,\ or\ if\ it's\ better\ to\ provide\ a\ `sugar::proc`\ that's\nexactly\ like\ `\[proc\]`\ but\ with\ macro\ expansion.\n\nIf\ the\ API\ will\ remain\ the\ current\ with\ `\[proc\]`\ redefined,\ I'll\ add\nin\ the\ wrapper\ an\ option\ `-nomacro`\ that\ will\ just\ call\ the\ original\ command.\nPlease\ add\ your\ name\ with\ optional\ motivation\ below.\n\nYes,\ I\ think\ it's\ better\ to\ wrapper\ the\ real\ `\[proc\]`:\n\ \ \ \ *\ Put\ your\ name\ here\ if\ you\ are\ for\ this\ solution.\n\nNo,\ I\ want\ macro\ expansion\ only\ using\ `sugar::proc`:\n\ \ \ \ *\ \[SS\]\ (avoid\ to\ waste\ CPU\ time\ for\ procs\ that\ don't\ use\ macros,\ this\ can\ be\ a\ big\ difference\ if\ you\ `\[package\ require\]`\ sugar\ before\ Tk\ or\ other\ big\ packages)\n\ \ \ *\ \[DKF\]:\ Avoiding\ overriding\ the\ real\ \[proc\]\ allows\ packages\ to\ use\ sugar\ if\ they\ want\ without\ surprising\ packages\ that\ don't\ expect\ it.\ \ Packages\ that\ do\ want\ it\ can\ just\ do\ \[\[\[namespace\ import\]\ ::sugar::proc\]\]\ into\ their\ own\ private\ workspace.\n\n\[WHD\]:\ Since\ you\ have\ to\ override\ the\ standard\ control\ structures\ to\ make\ macros\ work,\ it\ seems\ to\ me\ that\ what\ you\ really\ need\ is\ a\ pair\ of\ commands:\n\n======\nsugar::configure\ -enabled\ 1\n\n#\ Macros\ expanded\ in\ body\nproc\ myproc\ \{a\ b\ c\}\ \{....\}\n\n#\ Macros\ expanded\ in\ expression\ and\ body\nwhile\ \{\$a\ >\ \$b\}\ \{....\}\n\nsugar::configure\ -enabled\ 0\n\n#\ Macros\ no\ long\ expanded.\n======\n\n\[SS\]:\ Actually\ \[Sugar\]\ overrides\ nothing!\ (so\ it\ will\ expand\ all\ at\ compile\ time,\ no\ run-time\ overhead).\nIt\ does\ expansion\ inside\ control\ structures\ just\ using\ macros\ for\ `\[while\]`\ and\ so\ on.\nIn\ this\ page\ this\ is\ better\ explained\ in\ the\ section:\ '''How\ a\ macro\ knows\ what's\ a\ script?'''.\ So\ to\ override\ `\[proc\]`,\ or\ to\ provide\ a\ private\nproc-like\ command\ is\ just\ a\ matter\ of\ design\ (or\ tastes),\ all\ will\ work\ in\ both\ the\ cases.\n\n<<categories>>\ Dev.\ Tools\n\n======\n\[alpha_tcler\]\ \nThe\ library\ should\ allow\ easily\ to\ choose\ if\ I\ want\ macros\ inside\ ::sugar::proc\ or\ used\ elsewhere\ .\ \nSecondly,\ the\ examples\ should\ be\ corrected\ (\ the\ args\ replacing\ argv).\ \nGreat\ work\ ,\ macros\ make\ TCL\ a\ first\ class\ LISP\ equivalent\ language. regexp2} CALL {my render {Sugar command macros} ***\ NOTE\ ***\n\ The\ API\ changed\ in\ two\ ways,\ you\ should\ be\ aware\ of\ this\ if\ you\ want\ to\ try\ with\ the\ current\ release\ of\n\ sugar\ what\ is\ shown\ in\ this\ tutorial.\n\n\ First\ Change\ -\ Now\ macros\ are\ expanded\ only\ inside\ procedures\ defined\ with\ ::sugar::proc\n\ Second\ Change\ -\ Now\ macros\ get\ a\ list\ of\ arguments\ like\ normal\ procedures,\ but\ the\ first\ argument\ is\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ macro\ name\ itself.\ All\ the\ macros\ in\ this\ tutorial\ will\ work\ substituting\ the\ 'argv'\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ argument\ with\ 'args'.\n\n\ \ \ \ *\ Section\ 0\ -\ '''\[Sugar\]'''\n\ \ \ \ *\ Section\ 1\ -\ '''\[Sugar\ command\ macros\]'''\ (what\ you\ are\ reading)\n\ \ \ \ *\ Section\ 2\ -\ '''\[Sugar\ syntax\ macros\]'''\n\ \ \ \ *\ Section\ 3\ -\ '''\[Sugar\ transformers\]'''\n\n'''What\ is\ a\ Tcl\ macro'''.\n\nA\ macro\ is\ an\ operator\ implemented\ by\ transformation.\ Macros\ are\ procedures\nthat\ generate\ a\ Tcl\ program\ at\ compile\ time,\ and\ substitute\ it\ where\nthe\ programmer\ used\ their\ name\ as\ command.\n\nIt's\ a\ simple\ concept\ if\ explained\ by\ examples.\n\nSuppose\ you\ want\ to\ write\ a\ `clear`\ command\ that\ sets\ the\ ''varName''\ to\ a\ null\ string.\ It\ could\ be\ Implemented\ using\ `\[upvar\]`,\ like\ this:\n\n======\nproc\ clear\ varName\ \{\n\ \ \ \ upvar\ 1\ \$varName\ var\n\ \ \ \ set\ var\ \{\}\n\}\n======\n\nEvery\ time\ the\ user\ type\n\n======\nclear\ myvar\n======\n\nWhen\ `clear`\ is\ called,\ the\ `\$myvar`\ of\ the\ caller\ is\ set\ to\nto\ the\ \[empty\ string\].\n\nAs\ an\ alternative\ to\ call\ a\ procedure\ that\ is\ able\ to\ alter\ the\ caller's\nexecution\ environment,\ we\ may\ want\ to\ automatically\ substitute\ every\ occurrence\nof\ the\ command\ `clear\ varname`\ with\ `set\ varname\ \{\}`.\n\nSo\ basically\ we\ want\ that\ when\ we\ write\n\n======\nclear\ myvar\n======\n\nin\ a\ program,\ it\ is\ substitute\ with\n\n======\nset\ myvar\ \{\}\n======\n\nas\ if\ the\ programmer\ had\ really\ typed\ `set\ myvar\ \{\}`\ instead\ of\ `clear\ myvar`.\nThat's\ the\ goal\ of\ the\ simplest\ form\ of\ a\ \[Sugar\]'s\ macro.\n\nThe\ definition\ of\ a\ new\ macro\ is\ very\ similar\ to\ the\ creation\ of\ a\ procedure.\nThe\ following\ is\ the\ implementation\ of\ \[\[clear\]\]\ as\ a\ macro:\n\n======\nsugar::macro\ clear\ argv\ \{\n\ \ \ \ list\ set\ \[lindex\ \$argv\ 1\]\ \{\{\}\}\n\}\n======\n\nIt\ means:\ \"If\ you\ encounter\ a\ command\ called\ `clear`\ inside\ the\ source\ code,\ncall\ the\ following\ procedure\ putting\ all\ the\ parts\ of\ which\ the\ncommand\ is\ composed\ in\ `\$argv`,\ and\ substitute\ the\ occurrence\ of\ the\ clear\ncommand\ and\ arguments,\ with\ what\ the\ procedure\ will\ return.\"\n\nAgain,\ with\ other\ words:\n\nSo,\ what\ happens\ is\ that\ when\ a\ procedure\ is\ compiled,\ for\ every\noccurrence\ of\ the\ `clear`\ command\ inside\ the\ procedure,\ the\ above\nprocedure\ is\ called,\ with\ `\$argv`\ set\ to\ a\ list\ that\ represents\ the\ arguments\nused\ to\ call\ the\ macro\ (including\ the\ macro\ name\ itself\ as\ first\ argument).\nThe\ result\ value\ of\ the\ function,\ that\ should\ be\ a\ list\ of\ the\ same\ form,\ is\nsubstituted\ in\ place\ of\ the\ original\ macro\ call.\n\nTo\ make\ the\ example\ more\ concrete,\ see\ the\ following\ code:\n\n======\nproc\ foobar\ \{\n\ \ \ \ set\ x\ 10\n\ \ \ \ clear\ x\n\}\n======\n\n'''Before\ compiling\ the\ procedure''',\ Tcl\ will\ call\ the\ `clear`\ procedure\ \nwith\ `\$argv`\ set\ to\ `clear\ x`.\nThat\ procedure\ returns\ `set\ x\ \{\{\}\}`,\nThis\ return\ value\ will\ be\ substituted\ in\ place\ of\ \"clear\ x\".\n\nAfter\ the\ proc\ was\ defined,\ we\ can\ use\ `\[info\ body\]`\nto\ see\ what\ happened:\n\n======\ninfo\ body\ proc\n======\n\nwill\ output\n\n======\nset\ x\ 10\nset\ x\ \{\}\n======\n\n`\[Sugar\]`\ makes\ it\ possible\ to\ use\ a\ macro\ like\ `clear`\ as\ if\ it\ it\ was\ a\ Tcl\nprocedure,\ and\ the\ macro\ is\ called\ at\ compile\ time\ to\ produce\ the\ procedure\nthat\ replaces\ it.\n\nBut\ Tcl\ has\ `\[uplevel\]`\ and\ `\[upvar\]`,\ so\ what\ are\ macros\nuseful\ for?\ Fortunately\ they\ allow\ for\ many\ interesting\ things\nnot\ possible\ at\ all\ otherwise.\ \ The\ following\ example\nshows\ the\ first\ big\ advantage\ of\ macros:\n\n'''1)\ Macros\ makes\ Tcl\ faster,\ without\ forcing\ the\ user\ to\ inline\ code\nby\ hand.'''\n\nWhen\ `clear`\ is\ implemented\ as\ macro,\ it\ runs\ 3\ times\ faster\ in\ my\ Tcl\ 8.4.\n\nAlso,\ `\[upvar\]`\ is\ one\ of\ the\ biggest\ obstacles\ to\ the\ ability\nof\ the\ Tcl\ compiler\ to\ optimize\ Tcl\ \[bytecode\],\ it's\ not\ impossible\nthat\ at\ some\ point\ Tcl\ will\ be\ able\ to\ run\ much\ faster\nif\ the\ user\ will\ ensure\ a\ given\ procedure\ is\ never\ the\ target\ of\ `\[upvar\]`.\n\nSimple\ commands\ that\ involve\ the\ use\ of\ `\[upvar\]`\ can\ be\ even\nmore\ simple\ to\ write\ as\ macros.\ The\ following\ are\ four\ examples:\n\n======\n#\ \[first\ \$list\]\ -\ expands\ to\ \[lindex\ \$list\ 0\]\nsugar::macro\ first\ argv\ \{\n\ \ \ \ list\ lindex\ \[lindex\ \$argv\ 1\]\ 0\n\}\n\n#\ \[rest\ \$list\]\ -\ expands\ to\ \[lrange\ \$list\ 1\ end\]\nsugar::macro\ rest\ argv\ \{\n\ \ \ \ list\ lrange\ \[lindex\ \$argv\ 1\]\ 1\ end\n\}\n\n#\ \[last\ \$list\]\ -\ expands\ to\ \[lindex\ \$list\ end\]\nsugar::macro\ last\ argv\ \{\n\ \ \ \ list\ lindex\ \[lindex\ \$argv\ 1\]\ end\n\}\n\n#\ \[drop\ \$list\]\ -\ expands\ to\ \[lrange\ \$list\ 0\ end-1\]\nsugar::macro\ drop\ argv\ \{\n\ \ \ \ list\ lrange\ \[lindex\ \$argv\ 1\]\ 0\ end-1\n\}\n======\n\n\[Sugar\]\ supports\ three\ types\ of\ macros.\ We\ are\ dealing\ with\nthe\ simplest\ and\ more\ common\ macros:\ command\ macros.\n\nThe\ other\ two\ types,\ syntax\ macros,\ and\ transformers,\nwill\ be\ covered\ later.\ For\ now\ let's\ go\ to\ create\na\ more\ complex\ macro.\n\n'''A\ more\ complex\ example'''\n\nGood\ macros\ do\ source\ code\ transformation\ in\ a\ smart\ way,\nthey\ turn\ a\ form\ that\ is\ undestood\ by\ the\nprogrammer\ into\ code\ that\ is\ also\ understood\ by\ the\ compiler,\nthat's\ hard\ to\ type\ and\ use\ in\ raw\ form\ without\ the\nmacro\ support,\ but\ optimal\ otherwise.\n\nIdeally\ a\ macro\ should\ expand\ to\ a\ single\ command\ call\n(possibly\ including\ many\ other\ nested),\ and\ should\ not\nexpand\ to\ code\ that\ magically\ creates\ variables\ at\nruntime\ to\ store\ intermediate\ results\ all\ the\ times\ it\ncan\ be\ avoided\ (because\ there\ may\ be\ collisions\ with\nvariables\ in\ the\ function,\ or\ created\ by\ other\ bad\ macros.\nBtw,\ in\ the\ TODO\ list\ of\ sugar\ there\ is\ a\ way\ to\ generate\nunique\ local\ variable\ names).\n\nIf\ the\ macro\ is\ well\ written,\ then\ the\ programmer\ can\ use\ it\ like\nany\ other\ command\ without\ to\ care\ much.\n\nWe\ will\ see\ a\ more\ real\ example\ of\ macro\ that\ implements\na\ very\ efficient\ `\[lpop\]`\ operator.\ It\ accepts\ only\ one\nargument,\ the\ name\ of\ a\ variable,\ and\ returns\ the\ last\nelement\ of\ the\ list\ stored\ inside\ the\ given\ variable.\nAs\ side\ effect,\ `lpop`\ removes\ the\ last\ element\ from\ the\ list.\n(it's\ something\ like\ the\ complement\ of\ `\[lappend\]`).\n\nA\ pure-Tcl\ implementation\ is\ the\ following:\n\n======\nproc\ lpop\ listVar\ \{\n\ \ \ \ upvar\ 1\ \$listVar\ list\n\ \ \ \ set\ res\ \[lindex\ \$list\ end\]\n\ \ \ \ set\ list\ \[lrange\ \$list\ 1\ end\]\n\ \ \ \ return\ \$res\n\}\n======\n\nThis\ version\ of\ `lpop`\ is\ really\ too\ slow.\ In\ fact\ when\n`\[lrange\]`\ is\ called,\ it\ creates\ a\ new\ list\ object\ even\nif\ the\ original\ one\ stored\ in\ the\ `\$list`\ variable\ is\ going\nto\ be\ freed\ and\ replaced\ by\ the\ copy.\ To\ modify\ the\ list\nin-place\ is\ far\ better.\n\nThe\ `\[lrange\]`\ implementation\ is\ able\ to\ perform\ this\noptimization\ if\ the\ object\ in\ \"not\ shared\"\ (if\ you\ don't\nknow\ about\ this\ stuff\ try\ to\ read\ the\ Wiki\ page\ about\ the\n`\[K\]`\ operator\ before\ to\ continue)\n\nSo\ it's\ better\ to\ write\ the\ proc\ using\ the\ `\[K\]`\ operator.\nThe\ lrange\ line\ should\ be\ changed\ to\ this:\n\n======\nset\ list\ \[lrange\ \[K\ \$list\ \[set\ list\ \{\}\]\]\ 1\ end\]\n======\n\nWith\ `K`\ being:\n\n======\nproc\ K\ \{x\ y\}\ \{\n\ \ \ \ return\ \$x\n\}\n======\n\nBut\ even\ to\ call\ `\[K\]`\ is\ costly\ in\ terms\ of\ performace,\ so\nwhy\ not\ inline\ it\ also?\ Doing\ it\ requires\ changing\nthe\ previous\ lrange\ line\ to\ this:\n\n======\nset\ list\ \[lrange\ \[lindex\ \[list\ \$list\ \[set\ list\ \{\}\]\]\ 0\]\ 1\ end\]\n======\n\nThat's\ really\ a\ mess\ to\ read,\ but\ works\ at\ a\ different\ speed,\ and\neven\ more\ important,\ at\ a\ different\ time\ complexity!.\n\nWith\ a\ macro\ for\ `lpop`,\ we\ can\ go\ even\ faster,\ and\ the\ code\ is\ easier\ to\nmaintain\ and\nread.\ Macros\ are\ allowed\ to\ expand\ to\ commands\ containing\nother\ macros,\ recursively.\ This\ means\ that\ we\ can\ write\ a\ macro\nfor\ every\ single\ step\ of\ `lpop`.\ We\ need\ the\ `first`\n`last`\ and\ `drop`\ macros\ already\ developed,\ and\ a\ macro\ for\ `\[K\]`:\n\n======\nsugar::macro\ K\ argv\ \{\n\ \ \ \ foreach\ \{x\ y\}\ \$argv\ break\n\ \ \ \ list\ first\ \[list\ \$x\ \$y\]\n\}\n======\n\nNote\ that\ for\ speed,\ we\ used\ `\[foreach\]`\ instead\ of\ two\ calls\ to\ `\[lindex\]`.\nBut\ remember\ that\ macros\ '''don't\ have\ to\ be\ fast\ in\ the\ generation'''\ of\ the\nexpanded\ code.\n\n`K\ \$x\ \$y`\ expands\ to\ `first\ \[\[list\ \$x\ \$y\]\]`,\ which\ expands\ to\ `lindex\ \[\[list\ \$x\ \$y\]\]\ 0`.\n\nWe\ have\ one\ last\ problem.\ Even\ after\ the\ optimization\ and\ the\nuse\ of\ `K`\ inline,\ the\ procedure\ above\ required\ a\ local\nvariable\ 'res'\ to\ save\ the\ last\ argument\ of\ the\ list\ before\nto\ modify\ it,\ and\ use\ `\$res`\ later\ as\ return\ value\ for\ the\ procedure.\nWe\ don't\ want\ to\ create\ local\ vars\ into\ the\ code\ that\ calls\nthe\ `lpop`\ macro,\ nor\ do\ we\ want\ to\ expand\ to\ more\ than\ a\ single\ncommand.\ The\ `\[K\]`\ operator\ can\ help\ us\ to\ do\ so:\n\n======\nset\ res\ \[lindex\ \$list\ end\]\nset\ list\ \[lrange\ \[lindex\ \[list\ \$list\ \[set\ list\ \{\}\]\]\ 0\]\ 1\ end\]\nreturn\ \$res\n======\n\nleading\ to:\n\n======\nK\ \[lindex\ \$list\ end\]\ \[set\ list\ \[lrange\ \[lindex\ \[list\ \$list\ \[set\ list\ \{\}\]\]\ 0\]\ 1\ end\]\]\n======\n\nThat's\ ok,\ but\ what\ an\ unreadable\ code!\ Thanks\ to\ macros\nwe\ can\ abstract\ from\ the\ fact\ that\ to\ call\ procedures\ is\nslow,\ so\ we\ just\ write:\n\n======\n\[K\ \[last\ \$list\]\ \[set\ list\ \[rest\ \[K\ \$list\ \[set\ list\ \{\}\]\]\]\]\]\n======\n\nWill\ not\ win\ the\ clean-code\ context\ this\ year,\ but\ it's\ much\nbetter\ than\ the\ previous.\ Ok...\ now\ we\ want\ a\ macro\ that,\ every\ time\ we\ntype\ `lpop\ \$list`,\ will\ expand\ in\ the\ above\ line:\n\n======\nsugar::macro\ lpop\ argv\ \{\n\ \ \ \ set\ varname\ \[lindex\ \$argv\ 1\]\n\ \ \ \ set\ argv\ \[list\ K\ \\\n\ \ \ \ \ \ \ \ \{\[last\ \$%varname%\]\}\ \\\n\ \ \ \ \ \ \ \ \{\[set\ list\ \[drop\ \[K\ \$%varname%\ \[set\ %varname%\ \{\}\]\]\]\]\}\n\ \ \ \ \]\n\ \ \ \ foreach\ i\ \{1\ 2\}\ \{\n\ \ \ \ \ \ \ \ lset\ argv\ \$i\ \[string\ map\ \[list\ %varname%\ \$varname\]\ \[lindex\ \$argv\ \$i\]\]\n\ \ \ \ \}\n\ \ \ \ return\ \$argv\n\}\n======\n\nThere\ are\ few\ things\ to\ note\ about\ this\ code.\ The\ macro\ returns\na\ list,\ where\ every\ element\ is\ a\ token\ of\ a\ Tcl\ command\nin\ the\ source\ code.\ This\ does\ not\ mean\ we\ have\ to\ transform\ in\nlists\ even\ arguments\ that\ happens\ to\ represent\ a\ script.\ Also\nnote\ that\ the\ input\ list\ of\ the\ macro\ is\ just\ a\ list\ of\ tokens\nthat\ are\ *exactly*\ what\ the\ user\ typed\ they\ in\ the\ source\ code,\ verbatim.\nWhat\ follows\ is\ that\ the\ tokens\ are\ already\ quoted\ and\ valid\nrepresentations\ of\ a\ procedure\ argument.\nWe\ don't\ need\ to\ care\ about\ the\ fact\ that\ they\ must\ be\ interpreted\nas\ a\ single\ argument\ as\ we\ sould\ when\ generating\ code\ for\ `\[eval\]`.\n\nThis\ allows\ the\ macro\ developer\ to\ use\ templates\ for\ macros,\ in\nfact\ the\ `lpop`\ macro\ is\ just\ using\ a\ three\ argument\ template,\nand\ the\ final\ foreach\ will\ substitute\ the\ arguments\ that\ needs\nto\ refer\ to\ the\ variable\ name,\ with\ that\ name.\ You\ don't\ have\nto\ care\ what\ that\ variable\ name\ is.\ It\ can\ be\ a\ complex\ string\nformed\ by\ more\ commands,\ vars,\ and\ so\ on\ `\[\[like\]\]\[\[this\]\]\$and-this`.\nIf\ it\ was\ a\ single\ argument\ in\ the\ source\ code,\ it\ will\ be\ in\ the\ macro\nafter\ the\ expansion.\n\nAnother\ interesting\ thing\ to\ note\ is\ that\ we\ don't\ really\ have\nto\ return\ every\ token\ as\ a\ different\ element\ of\ the\ list.\ In\ pratice\nwe\ can\ return\ it\ even\ as\ a\ single-element\ list.\nThe\ rule\ is\ that\ the\ macro\ expander\ will\ care\ to\ put\ an\ argument\nseparator\ like\ a\ tab,\ or\ a\ space,\ for\ every\ element\ of\ the\nlist,\ and\ put\ a\ command\ separator\ like\ newline\ or\ `\;`\ at\ the\ end.\nIf\ we\ put\ spaces\ ourself,\ we\ can\ just\ return\ a\ single\ element\ list.\n\nSo,\ the\ `lpop`\ macro\ can\ also\ by\ written\ in\ this\ way:\n\n======\nsugar::macro\ lpop\ argv\ \{\n\ \ \ \ set\ varname\ \[lindex\ \$argv\ 1\]\n\ \ \ \ set\ cmd\ \[format\ \{\n\ \ \ \ \ \ \ \ K\ \[last\ \$%varname%\]\ \[set\ list\ \[drop\ \[K\ \$%varname%\ \[set\ %varname%\ \{\}\]\]\]\]\n\ \ \ \ \}\ \$varname\ \$varname\ \$varname\]\n\ \ \ \ return\ \[list\ \$cmd\]\n\}\n======\n\nThis\ is\ much\ more\ simple\ and\ clean,\ and\ actually\ it's\ possible\ to\nuse\ this\ style.\ The\ difference\ is\ that\ returning\ every\ token\ as\na\ different\ element\ of\ a\ list\ makes\ `\[Sugar\]`\ macros\ able\ to\nleft\ the\ indentation\ of\ the\ original\ code\ unaltered.\ This\ is\ helpful\nboth\ to\ take\ procedure\ error's\ line\ numbers\ correct,\ and\ to\nsee\ a\ good-looking\ output\ of\ `\[info\ body\]`.\ But\ as\ long\ as\nmost\ macros\ are\ about\ commands\ that\ are\ just\ typed\ in\ the\ same\ line\ntogether\ with\ all\ the\ arguments,\ for\ many\ macros\ is\ just\ a\ matter\ of\ tastes.\n\nIf\ you\ are\ implementing\ control\ structures\ that\ are:\n\n======\nindented\ in\ \{\n\ \ \ \ this\ way\n\}\n======\n\nIt's\ another\ question,\ and\ it's\ better\ to\ return\ every\ token\ as\ a\nlist\ element.\n\n'''Number\ of\ argument\ and\ other\ static\ checks\ in\ macros'''\n\nMacros\ expand\ to\ code\ that\ will\ raise\ an\ error\ if\ the\ number\ of\narguents\ is\ wrong\ in\ most\ cases,\ but\ it's\ possible\ to\ add\ this\ncontrol\ inside\ the\ macro.\ Actually\ it's\ a\ big\ advantage\ of\ macros\nbecause\ they\ are\ able\ to\ signal\ a\ bad\ number\ of\ arguments\ at\nrun\ time:\ this\ can\ help\ to\ write\ applications\ that\ are\ more\ reliable.\nIt's\ even\ possible\ to\ write\ a\ macro\ that\ expands\ to\ exactly\ what\nthe\ user\ typed\ in,\ but\ as\ side\ effect\ does\ a\ static\ check\ for\nbad\ number\ (or\ format)\ of\ arguments:\n\n======\nsugar::macro\ set\ argv\ \{\n\ \ \ if\ \{\[llength\ \$argv\]\ !=\ 3\ ||\ \[llength\ \$argv\]\ !=\ 2\}\ \{\n\ \ \ \ \ \ \ error\ \"Bad\ number\ of\ arguments\ for\ set\"\n\ \ \ \}\n\ \ \ return\ \$argv\n\}\n======\n\nThis\ macro\ returns\ `\$argv`\ itself,\ so\ it's\ an\ identity\ transformation,\nbut\ will\ raise\ errors\ for\ `\[set\]`\ with\ a\ bad\ number\ of\narguments\ even\ for\ code\ that\ will\ never\ be\ reached\nin\ the\ application.\ Note\ that\ the\ previous\ macro\ for\ set\ is\ a\ bit\nincomplete:\ to\ get\ it\ right\ we\ should\ add\ checks\ for\ arguments\nthat\ starts\ with\ `\[\{*\}\]`,\ for\ this\ reason\ `\[Sugar\]`\ will\ provide\ a\ function\nto\ automatically\ search\ for\ a\ bad\ number\ of\ arguments\ in\ some\nnext\ version.\n\nNote\ that\ `\[\{*\}\]`\ introduces\ for\ the\ first\ time\ the\ possibility\ for\na\ command\ to\ get\ a\ number\ of\ arguments\ that\ is\ non\ evident\ reading\nthe\ source\ code\ but\ computed\ at\ runtime.\ Actually,\ `\{*\}`\ is\ an\nadvantage\ for\ static\ checks\ because\ prior\ to\ it,\ the\ way\ to\ngo\ was\ `\[eval\]`,\ that\ does\ totally\ \"hide\"\ the\ called\ command\ postponing\nall\ the\ work\ at\ run-time.\ With\ `\{*\}`\ it's\ always\ possible\nto\ say\ from\ the\ source\ code\ that\ a\ command\ is\ called\ with\ *at\ least*\ N\narguments.\ Still,\ to\ add\ new\ syntax\ to\ Tcl\ will\ probably\ not\ play\nwell\ with\ macros\ and\ other\ form\ of\ source\ code\ processing.\n\nIdentity\ macros\ are\ very\ powerful\ to\ perform\ static\ syntax\ checks,\nthey\ can\ not\ only\ warn\ on\ bad\ number\ of\ arguments,\ but\ with\ the\ntype\ of\ this\ arguments.\ See\ for\ example\ the\ following\ identity\nmacro\ for\ \"string\ is\":\n\n======\nproc\ valid_string_class\ class\ \{\n\ \ \ \ set\ classes\ \{alnum\ alpha\ ascii\ control\ boolean\ digit\ double\ false\ graph\ integer\ lower\ print\ punct\ space\ true\ upper\ wordchar\ xdigit\}\n\ \ \ \ set\ first\ \[string\ index\ \$class\ 0\]\n\ \ \ \ if\ \{\$first\ eq\ \{\$\}\}\ \{return\ 1\}\n\ \ \ \ if\ \{\$first\ eq\ \{\[\}\}\ \{return\ 1\}\n\ \ \ \ if\ \{\[lsearch\ \$classes\ \$class\]\ !=\ -1\}\ \{return\ 1\}\n\ \ \ \ return\ 0\n\}\n\nsugar::macro\ string\ argv\ \{\n\ \ \ \ if\ \{\[lindex\ \$argv\ 1\]\ eq\ \{is\}\ &&\ \[llength\ \$argv\]\ >\ 2\}\ \{\n\ \ \ \ \ \ \ \ if\ \{!\[valid_string_class\ \[lindex\ \$argv\ 2\]\]\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ puts\ stderr\ \"Warning:\ invalid\ string\ class\ in\ procedure\ \[sugar::currentProcName\]\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$argv\n\}\n======\n\nThanks\ to\ this\ macro\ it's\ possible\ to\ ensure\ that\ errors\ that\ like\ to\ write\n`string\ is\ number`\ instead\ `\[string\ is\]\ integer`\ are\ discovered\ at\ncompile-time.\ In\ this\ respect\ macros\ can\ be\ seen\ as\ a\ programmable\nstatic\ syntax\ checker\ for\ Tcl.\ We\ will\ see\ how\ \"syntax\ macros\"\ are\neven\ more\ useful\ in\ this\ respect.\ This\ is\ the\ second\ feature\ that\nmacros\ add\ to\ Tcl:\n\n'''2)\ Macros\ are\ a\ powerful\ programmable\ static\ checker\ for\ Tcl\ scripts.'''\n\nActually\ I\ think\ it's\ worth\ to\ use\ macros\ even\ only\ for\ this\ during\nthe\ development\ process,\ and\ than\ flush\ they\ away.\n\n'''Conditional\ compilation'''\n\nThat's\ small\ and\ neat:\ we\ can\ write\ a\ simple\ macro\ that\ expands\ to\nsome\ code\ only\ if\ a\ global\ variable\ is\ set\ to\ non-zero.\ Let's\nwrite\ this\ macro\ that\ we\ call\ \[\[debug\]\].\n\n======\nsugar::macro\ debug\ argv\ \{\n\ \ \ if\ \{\$::debug_mode\}\ \{\n\ \ \ \ \ \ \ list\ if\ 1\ \[lindex\ \$argv\ 1\]\n\ \ \ \}\ else\ \{\n\ \ \ \ \ \ \ list\n\ \ \ \}\n\}\n======\n\nThan\ you\ can\ use\ it\ in\ your\ application\ like\ if\ it\ was\ a\ conditional:\n\n======\n#\ Your\ application\ ...\ndebug\ \{\n\ \ \ \ set\ c\ 0\n\}\nwhile\ 1\ \{\n\ \ \ \ debug\ \{\n\ \ \ \ \ \ \ \ incr\ c\n\ \ \ \ \ \ \ \ if\ \{\$c\ >\ 100\}\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ error\ \"Too\ many\ iteractions...\"\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ ....\ do\ something\ ....\n\}\n======\n\nif\ the\ value\ of\ `\$::debug_mode`\ is\ true,\ all\ the\ `debug\ \{someting\}`\ commands\nare\ compiled\ as\ `if\ 1\ \{something\}`.\ Otherwise,\ they\ will\ not\ be\ compiled\ at\nall.\n\nThat's\ the\ simplest\ example,\ you\ can\ write\ similar\ macros\ like\ `ifunix`,\n`ifwindows`,\ `ifmac`,\ or\ even\ to\ expand\ to\ different\ procedures\ call\nif\ a\ given\ command\ is\ called\ with\ 2,\ 3\ or\ 4\ arguments.\ The\ limit\ is\nthe\ immagination.\n\n'''New\ control\ stuctures'''\n\nNot\ all\ the\ programming\ languages\ allow\ to\ write\ new\ control\ structures.\nTcl\ is\ one\ of\ the\ better\ languages\ that\ don't\ put\ the\ programmer\ninside\ a\ jail,\ but\ not\ all\ the\ programming\ languages\ that\ allow\nto\ write\ new\ control\ structures\ are\ able\ to\ make\ them\ efficient.\n\nTcl\ macros\ can\ make\ new\ control\ structures\ as\ fast\ as\ \[bytecode%|%byte-compiled\]\ncontrol\ structures,\ because\ user\ defined\ ones\ are\ usually\ syntax\ glue\nfor\ code\ transformations.\ Being\ macro\ transformers\nthat\ translates\ a\ from\ to\ another,\ that's\ a\ good\ fit\ for\ macros.\n\nHere\ is\ a\ macro\ for\ the\ `?:`\ operator.\n\n======\n#\ ?:\ expands\n#\ \ \ ?:\ cond\ val1\ val2\n#\ to\n#\ \ \ if\ \$cond\ \{format\ val1\}\ \{format\ val2\}\nsugar::macro\ ?:\ argv\ \{\n\ \ \ \ if\ \{\[llength\ \$argv\]\ !=\ 4\}\ \{\n\ \ \ \ \ \ \ \ error\ \"Wrong\ number\ of\ arguments\"\n\ \ \ \ \}\n\ \ \ \ foreach\ \{_\ cond\ val1\ val2\}\ \$argv\ break\n\ \ \ \ list\ if\ \$cond\ \[list\ \[list\ format\ \$val1\]\]\ \[list\ \[list\ format\ \$val2\]\]\n\}\n======\n\nThe\ macro's\ comment\ shows\ the\ expansion\ performed.\nBeing\ it\ translated\ to\ an\ `\[if\]`\ command,\ it's\ as\ fast\ as\ a\nTcl\ builtin.\n\n'''How\ macros\ knows\ what's\ a\ script?'''\n\nIn\ Tcl\ there\ are\ no\ types,\ nor\ special\ syntaxes\ for\ what\ is\ code\nand\ what\ is\ just\ a\ string,\ so\ you\ may\ wonder\ why\ macros\ are\nnot\ expanded\ in\ the\ following\ code:\n\n======\nputs\ \{\n\ \ \ \ set\ foo\ \{1\ 2\ 3\}\;\ \[first\ \$foo\]\n\}\n======\n\nBut\ they\ are\ expanded\ in\ this:\n\n======\nwhile\ 1\ \{\n\ \ \ \ set\ foo\ \{1\ 2\ 3\}\;\ \[first\ \$foo\]\n\}\n======\n\nI\ guess\ this\ is\ one\ of\ the\ main\ problems\ developers\ face\ designing\ a\nmacro\ system\ for\ Tcl,\ and\ even\ one\ of\ the\ better\ helpers\ of\ the\ idea\nthat\ a\ good\ macro\ system\ for\ Tcl\ is\ impossible\ because\ you\ can't\nsay\ what\ is\ code\ and\ what\ isn't.\n\n\[Sugar\]\ was\ designed\ to\ address\ this\ problem\ in\ the\ simplest\ possible\nof\ the\ ways:\ because\ it\ can't\ say\ if\ an\ argument\ is\ a\ script\ or\ not,\nmacro\ expansion\ is\ not\ performed\ in\ arguments,\ so\ in\ theory\ \[Sugar\]\nwill\ not\ expand\ the\ code\ that's\ argument\ to\ `\[puts\]`,\ nor\ `\[while\]`.\n\nBut\ of\ course,\ in\ the\ real\ world\ for\ a\ macro\ system\ to\ be\ usable,\nmacros\ should\ be\ expanded\ inside\ the\ `\[while\]`,\ and\ not\ expanded\ in\ `\[puts\]`,\nso\ the\ idea\ is\ that\ for\ commands\ that\ you\ know\ accept\ a\ script\ as\ an\ argument,\nyou\ write\ a\ macro\ that\ returns\ the\ same\ command\ but\ with\nscript\ arguments\ macro-expanded.\ It\ is\ very\ simple\ and\ in\ pratice\nthis\ works\ well.\ For\ example\ that's\ the\ macro\ for\ `\[while\]`:\n\n======\nsugar::macro\ while\ argv\ \{\n\ \ \ \ lset\ argv\ 1\ \[sugar::expandExprToken\ \[lindex\ \$argv\ 1\]\]\n\ \ \ \ lset\ argv\ 2\ \[sugar::expandScriptToken\ \[lindex\ \$argv\ 2\]\]\n\}\n======\n\nThat's\ the\ macro\ for\ \[if\]:\n\n======\nsugar::macro\ if\ argv\ \{\n\ \ \ \ lappend\ newargv\ \[lindex\ \$argv\ 0\]\n\ \ \ \ lappend\ newargv\ \[sugar::expandExprToken\ \[lindex\ \$argv\ 1\]\]\n\ \ \ \ set\ argv\ \[lrange\ \$argv\ 2\ end\]\n\ \ \ \ foreach\ a\ \$argv\ \{\n\ \ \ \ \ \ \ \ switch\ --\ \$a\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ else\ -\ elseif\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ newargv\ \$a\n\ \ \ \ \ \ \ \ \ \ \ \ \}\ \n\ \ \ \ \ \ \ \ \ \ \ \ default\ \{\n\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ lappend\ newargv\ \[sugar::expandScriptToken\ \$a\]\n\ \ \ \ \ \ \ \ \ \ \ \ \}\n\ \ \ \ \ \ \ \ \}\n\ \ \ \ \}\n\ \ \ \ return\ \$newargv\n\}\n======\n\nAs\ you\ can\ see,\ \[Sugar\]\ exports\ an\ API\ to\ perform\ expansion\ in\nTcl\ scripts\ and\ Expr\ expressions.\ There\ are\ similar\ macros\ for\n`\[switch\]`,\ `\[for\]`,\ and\ so\ on.\ If\ you\ write\ a\ new\ conditional\ or\nloop\ command\ with\ macros,\ you\ don't\ need\ it\ at\ all\ because\nthe\ macro\ will\ translate\ to\ code\ that\ contains\ some\ form\ of\na\ well\ known\ built-in\ conditional\ or\ loop\ command,\ and\ we\ already\nhave\ macros\ for\ this\ (remember\ that\ macros\ can\ return\ code\ with\nmacros).\n\nIf\ you\ write\ any\ other\ command\ that\ accept\ as\ arguments\ a\ Tcl\ script\nor\ expr\ expression,\ just\ write\ a\ little\ macro\ for\ it\ to\ do\nmacro\ expansion.\ This\ has\ a\ nice\ side\ effect:\n\n======\nproc\ nomacro\ script\ \{\n\ \ \ \ uplevel\ 1\ \$script\n\}\n======\n\nDon't\ write\ a\ macro\ for\ nomacro,\ and\ you\ have\ a\ ready-to-use\ncommand\ that\ works\ as\ a\ barrier\ for\ macro\ expansion.\n\nContinue\ with\ section\ 2\ -\ '''\[Sugar\ syntax\ macros\]'''\n\n----\n\n\[WHD\]:\ This\ is\ very\ cool,\ but\ I\ have\ to\ ask--why\ not\ allow\ macros\ to\nhave\ a\ standard\ Tcl\ argument\ list?\ \ That\ is,\ \n\n======\nsugar::macro\ mymacro\ args\ \{...\}\n======\n\nGives\ the\ behavior\ you\ describe\ here,\ while\n\n======\nsugar::macro\ mymacro\ \{a\ b\ c\}\ \{...\}\n======\n\nexplicitly\ creates\ a\ macro\ that\ takes\ three\ arguments\ and\ will\ngenerate\ a\ standard\ error\ message\ if\ you\ supply\ some\ other\ number?\n\n----\n\n\[SS\]:\ This\ can\ be\ a\ good\ idea,\ being\ always\ possible\ to\nuse\ `args`\ as\ only\ argument\ to\ have\ the\ current\ behaviour.\ I\ used\na\ single\ list\ as\ input\ mainly\ because\ the\ same\ macro\ can\ have\ more\nthen\ a\ name,\ and\ in\ order\ to\ have\ the\ same\ interface\ for\ both\ncommand\ macros\ and\ syntax\ macros.\ For\ example:\n\n======\nsugar::macro\ \{*\ +\ -\ /\}\ argv\ \{\n\ \ \ \ list\ expr\ \[list\ \[join\ \[lrange\ \$argv\ 1\ end\]\ \"\ \[lindex\ \$argv\ 0\]\ \"\]\]\n\}\n======\n\nWill\ handle\ `*\ +\ -\ /`\ with\ the\ same\ code.\ Macros\ with\ more\ than\ a\ name\nmay\ in\ extreme\ cases\ even\ give\ different\ meanings\ for\ arguments\ in\nthe\ same\ position.\ Btw\ there\ is\ 'args'\ for\ this\ case.\ So\ I\ can\ change\nthe\ API\ to\ something\ like\ this:\n\n======\nsugar::macro\ \{name\ arg1\ arg2\ ...\}\ \{...\}\n======\n\nThat's\ like\ a\ Tcl\ proc,\ but\ with\ the\ name\ that\ was\ used\ to\ call\ the\ macro\nas\ the\ first\ argument.\ For\ syntax\ macros,\ this\ format\ actually\ may\ not\ make\ a\nlot\ of\ sense,\ but\ there\ is\ still\ `args`.\ I'll\ include\ this\ change\ in\ the\nnext\ version\ if\ I'll\ not\ receive\ feedbacks\ against\ it.\ Thanks\ for\ the\nfeedback\ WHD.\n\n\[WHD\]:\ I\ think\ that\ on\ the\ whole\ I\ prefer\ the\ previous\ syntax\ for\ command\nmacros\;\ the\ macro\ can\ always\ have\ an\ implicit\ argument\ that\ is\ the\nmacro\ name.\ \ For\ example,\n\n======\n#\ Identity\ macro\nsugar::macro\ \{+\ -\ *\ /\}\ \{args\}\ \{\ return\ \"\$macroname\ \$args\"\ \}\n======\n\n\[JMN\]:\ I'd\ just\ like\ to\ add\ my\ vote\ for\ removing\ the\ macroname\ as\ first\ argument\ syntax.\nFrom\ my\ hacking\ about,\ it\ seems\ easy\ to\ make\ it\ implicitly\ available\ more\ or\ less\ as\ WHD\ suggests.\n(I\ don't\ *think*\ I\ broke\ anything..\ )\n\n----\n\n\[SS\]:\ For\ a\ different\ question\ about\ the\ sugar\ API,\ I\ wonder\ if\ Tclers\ninterested\ in\ this\ macro\ system\ feel\ better\ about\ the\ current\ redefinition\nof\ `\[proc\]`,\ or\ if\ it's\ better\ to\ provide\ a\ `sugar::proc`\ that's\nexactly\ like\ `\[proc\]`\ but\ with\ macro\ expansion.\n\nIf\ the\ API\ will\ remain\ the\ current\ with\ `\[proc\]`\ redefined,\ I'll\ add\nin\ the\ wrapper\ an\ option\ `-nomacro`\ that\ will\ just\ call\ the\ original\ command.\nPlease\ add\ your\ name\ with\ optional\ motivation\ below.\n\nYes,\ I\ think\ it's\ better\ to\ wrapper\ the\ real\ `\[proc\]`:\n\ \ \ \ *\ Put\ your\ name\ here\ if\ you\ are\ for\ this\ solution.\n\nNo,\ I\ want\ macro\ expansion\ only\ using\ `sugar::proc`:\n\ \ \ \ *\ \[SS\]\ (avoid\ to\ waste\ CPU\ time\ for\ procs\ that\ don't\ use\ macros,\ this\ can\ be\ a\ big\ difference\ if\ you\ `\[package\ require\]`\ sugar\ before\ Tk\ or\ other\ big\ packages)\n\ \ \ *\ \[DKF\]:\ Avoiding\ overriding\ the\ real\ \[proc\]\ allows\ packages\ to\ use\ sugar\ if\ they\ want\ without\ surprising\ packages\ that\ don't\ expect\ it.\ \ Packages\ that\ do\ want\ it\ can\ just\ do\ \[\[\[namespace\ import\]\ ::sugar::proc\]\]\ into\ their\ own\ private\ workspace.\n\n\[WHD\]:\ Since\ you\ have\ to\ override\ the\ standard\ control\ structures\ to\ make\ macros\ work,\ it\ seems\ to\ me\ that\ what\ you\ really\ need\ is\ a\ pair\ of\ commands:\n\n======\nsugar::configure\ -enabled\ 1\n\n#\ Macros\ expanded\ in\ body\nproc\ myproc\ \{a\ b\ c\}\ \{....\}\n\n#\ Macros\ expanded\ in\ expression\ and\ body\nwhile\ \{\$a\ >\ \$b\}\ \{....\}\n\nsugar::configure\ -enabled\ 0\n\n#\ Macros\ no\ long\ expanded.\n======\n\n\[SS\]:\ Actually\ \[Sugar\]\ overrides\ nothing!\ (so\ it\ will\ expand\ all\ at\ compile\ time,\ no\ run-time\ overhead).\nIt\ does\ expansion\ inside\ control\ structures\ just\ using\ macros\ for\ `\[while\]`\ and\ so\ on.\nIn\ this\ page\ this\ is\ better\ explained\ in\ the\ section:\ '''How\ a\ macro\ knows\ what's\ a\ script?'''.\ So\ to\ override\ `\[proc\]`,\ or\ to\ provide\ a\ private\nproc-like\ command\ is\ just\ a\ matter\ of\ design\ (or\ tastes),\ all\ will\ work\ in\ both\ the\ cases.\n\n<<categories>>\ Dev.\ Tools\n\n======\n\[alpha_tcler\]\ \nThe\ library\ should\ allow\ easily\ to\ choose\ if\ I\ want\ macros\ inside\ ::sugar::proc\ or\ used\ elsewhere\ .\ \nSecondly,\ the\ examples\ should\ be\ corrected\ (\ the\ args\ replacing\ argv).\ \nGreat\ work\ ,\ macros\ make\ TCL\ a\ first\ class\ LISP\ equivalent\ language.} CALL {my revision {Sugar command macros}} CALL {::oo::Obj4108623 process revision/Sugar+command+macros} CALL {::oo::Obj4108621 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4