wip(3tcl)
β¨ wip(3tcl) β Word Interpreter β¨
okay bestie, buckle up, we're reading the wip(3tcl) manual page together and honestly? it's giving tiny language engine that could. π This is the Word Interpreter β a whole micro interpreter for lists of words, and I'm gonna walk you through every single bit of it, no cap. π¦
πΈ NAME πΈ
wip β Word Interpreter
π SYNOPSIS π
package require Tcl 8.5 9
package require wip ?2.3?
package require snit ?1.4?
package require struct::set
::wip wipName engine arg...
def name
def name method_prefix
wipName option ?arg arg ...?
wip::dsl ?suffix?
wipName def name ?method_prefix?
wipName defl names
wipName defd dict
wipName deflva name...
wipName defdva (name method_prefix)...
wipName undefl names
wipName undefva name...
wipName unknown cmdprefix
wipName runl wordlist
wipName run word...
wipName run_next
wipName run_next_while acceptable
wipName run_next_until rejected
wipName run_next_if acceptable
wipName run_next_ifnot rejected
wipName next
wipName peek
wipName peekall
wipName insertl at wordlist
wipName replacel wordlist
wipName pushl wordlist
wipName addl wordlist
wipName insert at word...
wipName replace word...
wipName push word...
wipName add word...
π DESCRIPTION π
So this package hands you a micro interpreter for lists of words. If you build a domain specific language on top of it, it's gonna have a little bit of a Forth feel β the input stream gets chopped into words, and literally all the other structuring is left up to whatever language you're cooking up. And like, note that what's here is in essence only the core dispatch loop. There are no actual commands whatsoever. So it's definitely just a Forth feel, not an actual Forth. π«Ά
The idea is derived from Colin McCormack's treeql processor, but it got remixed to require less boiler plate inside the command implementations β at the cost of, probably, execution speed. π And on top of that, the interface between the processor core and the commands is more complex too. Trade-offs, babe.
π GENERAL BEHAVIOUR π
Word interpreters have a mapping from the names of the language commands they're supposed to recognize, over to the methods in the engine that get invoked for them β plus possibly some fixed arguments for those methods. This mapping is largely static, but plot twist: it is possible to change it during the execution of a word list (= program). π
At the time a language command gets defined, the word interpreter uses snit's introspection capabilities to figure out how many arguments the engine's method expects. Then, together with the number of fixed arguments supplied in the method prefix of the mapping, it knows exactly how many arguments the language command is expecting. That's the command's arity. β¨
β οΈ Variable-argument methods (i.e. ones with the last argument namedargs) are not allowed and will make the word interpreter throw an error at definition time. Noargs, bestie. That's the rule.
And note β even though I said snit's abilities, the engine object can be written any which way you like, as long as it understands the method info args, which takes a method name and returns the list of arguments for that method. Slay, flexible king. π
When executing a list of words (aka a program), the first word is always taken as the name of a language command, and the next words are its arguments, per the arity of the command. Command words and argument words get removed from the list, and then the associated method of the engine is executed with the argument words. Then the process repeats using the then-first word of the list. π
And note that the methods implementing the language commands may have full access to the list of words and are allowed to manipulate it however they see fit. Which means:
- This means, for example, that while we cannot specify variable-argument methods directly, they can consume words after their fixed arguments before returning to the execution loop. This may be under the control of their fixed arguments.
- Another possibility is the use of method
run_nextand its variants to execute commands coming after the current command, changing the order of execution. - Execution can be further changed by use of the program accessor methods which allow a command implementation to modify the remaining list of words (insert, replace, prepend, append words) without executing them immediately.
- At last the basic
runmethods save and restore an existing list of words when used, enabling recursive use from within command implementations.
π CLASS API π
The main command of the package is:
::wip wipName engine arg...β This command creates a new word interpreter object with an associated global Tcl command whose name is wipName. If however the string%AUTO%was used as the object name, the package will generate its own unique name for the object. π«
The engine is the object the word interpreter will dispatch all recognized commands to, and the *arg*s are a word list which defines an initial mapping from language words to engine methods.
The recognized language of this word list is:
def nameβ Defines name as a command of the language, to be mapped to a method of the engine having the same name.def name method_prefixβ Defines name as a command of the language, to be mapped to the method of the engine named in the method_prefix.
The returned command may be used to invoke various operations on the object. It has the following general form:
wipName option ?arg arg ...?β Option and the *arg*s determine the exact behavior of the command.
The package additionally exports the command:
wip::dsl ?suffix?β This command is for use within snit types which wish to use one or morewipinterpreters as a component. Use within the type definition installs most of the boilerplate needed to setup and use a word interpreter. π§
It installs a component named wip, and a method wip_setup for initializing it. This method has to be called from within the constructor of the type using the word interpreter. If further installs a series of procedures which make the object API of the word interpreter directly available to the type's methods, without having to specify the component.
Note that this does and cannot install the language to interpret, i.e. the mapping from words to engine methods. π
It is possible to instantiate multiple word interpreter components within a type by using different *suffix*es as arguments to the command. In that case the name of the component changes to wip_$suffix, the setup command becomes wip_$suffix_setup, and all the procedures also get the suffix _$suffix. π
β¨ OBJECT API β¨
okay bestie, these are all the commands you can throw at a word interpreter object. buckle up, there's a bunch, but every single one of them is doing something cute π
wipName def name ?method_prefix?β defines a language command called name and maps it to the method that lives in the engine's method_prefix. if you don't pass a method_prefix at all? it's just the name of the language command, no extra drama πwipName defl namesβ defines a whole series of language commands, handed to it as the list names. every one of them gets mapped to the engine method with the same name. so many at once, so efficient, we love a batch operation π«ΆwipName defd dictβ same energy as above but with a dictionary dict of names and method prefixes. you get to pick the mapping, main character behaviour honestly πwipName deflva name...β literally the same as the methoddefl, except the list of names comes in through multiple arguments instead of one list.wipName defdva (name method_prefix)...β literally the same as the methoddefd, except the dictionary of names and method prefixes comes in through multiple arguments.wipName undefl namesβ removes the named series of language commands (the list names) from the mapping. goodbye, we hardly knew ye πwipName undefva name...β same as the methodundefl, but the list of names comes in through multiple arguments.wipName unknown cmdprefixβ sets the handler for unknown words to cmdprefix. this command prefix takes exactly one argument β the current word β and then it either throws some error, or returns the result of executing the word, however the handler decides to define that. the default handler? it simply throws an error. no vibes, just rejection πwipName runl wordlistβ treats the list of words in wordlist as a program and executes the commands inside it one by one. the result of the command that ran last is what gets returned as the result of this command.
the wordlist is stored inside the object so the other run-methods and the general program accessor methods (they're further down, don't worry) can get at it. a previously stored wordlist gets saved while this method runs and restored before it returns. why do we care? because that's what makes it possible to execute word lists inside word lists, recursively, forever, iconic π
wipName run word...β same as the methodrunl, except the list of words to execute arrives through multiple arguments.wipName run_nextβ low-level method alert. it figures out the next word in the list of words plus that word's arguments, and then executes it. the result of the executed word is the result of this method.
this one is exposed so you can use it inside command implementations. the methods run and runl use it to keep executing words until their word list runs out.
wipName run_next_while acceptableβ low-level method. calls the methodrun_nextfor as long as the next word is in the set of acceptable words and the program isn't empty. the result of the command that ran last is returned as the result of this command.
exposed for use inside command implementations, specifically so you can change the order of execution. chaos, but make it deliberate β¨
wipName run_next_until rejectedβ low-level method. calls the methodrun_nextuntil the next word is in the set of rejected words, and the program isn't empty. the result of the command that ran last is returned as the result of this command.
exposed for use inside command implementations to change the order of execution.
wipName run_next_if acceptableβ low-level method. calls the methodrun_nextif the next word is in the set of acceptable words, and the program isn't empty. the result of the command that ran last is returned as the result of this command.
exposed for use inside command implementations to change the order of execution.
wipName run_next_ifnot rejectedβ low-level method. calls the methodrun_nextif the next word is not in the set of rejected words, and the program isn't empty. the result of the command that ran last is returned as the result of this command.
exposed for use inside command implementations to change the order of execution.
wipName nextβ returns the next word in the program. and yeah, the word gets removed too. one-time deal, no takebacks πwipName peekβ returns the next word in the program, but without removing it. just looking, bestie, not touching πwipName peekallβ returns the remaining program in toto. the whole thing, all of it, at once πwipName insertl at wordlistβ basic program accessor method. inserts the given wordlist into the program, right before the word at position at. positions are counted from zero, like a real programmer.wipName replacel wordlistβ basic program accessor method. replaces the entire stored program with the given wordlist. total glow-up, the old program is gone.wipName pushl wordlistβ program accessor method. the given wordlist gets added to the front of the remaining program. it's exactly the same as
$wip insertl 0 $wordlist
wipName addl wordlistβ program accessor method. the given wordlist gets appended at the end of the remaining program. it's exactly the same as
$wip insertl end $wordlist
wipName insert at word...β like the methodinsertl, except the words come in through multiple arguments.wipName replace word...β like the methodsetl, except the words come in through multiple arguments.wipName push word...β like the methodpushl, except the words come in through multiple arguments.wipName add word...β like the methodaddl, except the words come in through multiple arguments.
πΈ EXAMPLES πΈ
No examples yet. π (ngl, same. the author said "no examples yet" and honestly? respect for the honesty.)
π«Ά BUGS, IDEAS, FEEDBACK π«Ά
this document, and the package it describes, will undoubtedly contain bugs and other problems. that's just how software is, bestie, no cap. please report such in the category wip of the Tcllib Trackers at [http://core.tcl.tk/tcllib/reportlist]. and please also report any ideas for enhancements you may have for either the package and/or the documentation β we want them, we're obsessed, bring them to us π
when proposing code changes, please provide unified diffs, i.e the output of diff -u.
also note further that attachments are strongly preferred over inlined patches. how do you attach one? go to the Edit form of the ticket immediately after its creation, and then use the left-most button in the secondary navigation bar. that's the one. that's the button. π
β KEYWORDS β
interpreter, list, word
π CATEGORY π
Programming tools
π COPYRIGHT π
Copyright (c) 2007-2010 Andreas Kupries <andreas_kupries@users.sourceforge.net>
and that's a wrap on the wip(3tcl) page, bestie π¦ this one ships from tcllib, version 2.3, and it's dated right there in the footer next to the wip(3tcl) title. go forth and interpret those words, you absolute legend πβ¨
π¦ where this page comes from
- debian trixie: tcllib 2.0+dfsg-4 Β· Tcl
- ubuntu questing: tcllib 2.0+dfsg-4
- ubuntu resolute: tcllib 2.0+dfsg-5 Β· Tcl
- ubuntu stonking: tcllib 2.0+dfsg-6 Β· Tcl
- Copyright (c) 2007-2010 Andreas Kupries <andreas_kupries@users\&.sourceforge\&.net>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms