{"id":15517320,"url":"https://github.com/skx/critical","last_synced_at":"2025-04-23T04:05:35.603Z","repository":{"id":36956910,"uuid":"505020357","full_name":"skx/critical","owner":"skx","description":"A simple/minimal TCL interpreter, written in golang","archived":false,"fork":false,"pushed_at":"2022-11-26T03:39:32.000Z","size":1254,"stargazers_count":36,"open_issues_count":1,"forks_count":5,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-23T04:05:28.028Z","etag":null,"topics":["cli","command-line-tool","embedded-scripting-language","golang","interpreter","scripting-language","tcl"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/skx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":"skx","custom":"https://steve.fi/donate/"}},"created_at":"2022-06-19T05:28:38.000Z","updated_at":"2025-03-15T19:01:35.000Z","dependencies_parsed_at":"2023-01-17T08:16:08.670Z","dependency_job_id":null,"html_url":"https://github.com/skx/critical","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fcritical","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fcritical/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fcritical/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/skx%2Fcritical/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/skx","download_url":"https://codeload.github.com/skx/critical/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250366726,"owners_count":21418771,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","command-line-tool","embedded-scripting-language","golang","interpreter","scripting-language","tcl"],"created_at":"2024-10-02T10:12:29.972Z","updated_at":"2025-04-23T04:05:35.583Z","avatar_url":"https://github.com/skx.png","language":"Go","readme":"[![GoDoc](https://img.shields.io/static/v1?label=godoc\u0026message=reference\u0026color=blue)](https://pkg.go.dev/github.com/skx/critical)\n[![Go Report Card](https://goreportcard.com/badge/github.com/skx/critical)](https://goreportcard.com/report/github.com/skx/critical)\n[![license](https://img.shields.io/github/license/skx/critical.svg)](https://github.com/skx/critical/blob/master/LICENSE)\n\n\n* [criTiCaL - A TCL interpreter written in golang](#critical---a-tcl-interpreter-written-in-golang)\n* [Building \u0026 Usage](#building--usage)\n* [Examples](#examples)\n  * [Available Commands](#available-commands)\n  * [Features](#features)\n  * [Missing Features](#missing-features)\n* [Testing](#testing)\n* [See Also](#see-also)\n* [Bugs?](#bugs?)\n\n# criTiCaL - A TCL interpreter written in golang\n\nAfter re-reading [TCL the Misunderstood](http://antirez.com/articoli/tclmisunderstood.html), I decided to create a simple TCL evaluator of my own.  This project is the result, and it has feature-parity with the two existing \"small TCL\" projects, written in C, which I examined:\n\n* [picol](http://oldblog.antirez.com/page/picol.html)\n  - By @antirez.\n* [partcl](https://zserge.com/posts/tcl-interpreter/)\n  - By @zserge.\n\nThere is a simple introduction to this project, and TCL syntax, on my blog here:\n\n* [Writing a simple TCL interpreter in golang](https://blog.steve.fi/writing_a_simple_tcl_interpreter_in_golang.html)\n\n\n\u003e The name of this project was generated by looking for words containing the letters \"T\", \"C\", and \"L\", in order.  I almost chose `arTiCLe`, `TreaCLe`, `myThiCaL`, or `mysTiCaL`.\n\u003e Perhaps somebody else can write their own version of this project with one of those names!\n\n\n\n## Building \u0026 Usage\n\nThis repository contains a TCL-like interpreter, along with a sample driver.\n\nYou can build both in the way you'd expect for golang applications:\n\n```sh\n$ go build .\n```\n\nOnce built you can execute the application, supplying the path to a TCL\nscript which you wish to execute.  For example:\n\n```sh\n    $ ./critical examples/prime.tcl\n    0\n    1\n    2 is prime\n    3 is prime\n    ..\n```\n\nThe interpreter contains an embedded \"standard-library\", which you can view at [stdlib/stdlib.tcl](stdlib/stdlib.tcl), which is loaded along with any file that you specify.\n\nTo disable the use of the standard library run:\n\n```sh\n   $ ./critical -no-stdlib path/to/file.tcl\n```\n\nGenerally the point of a scripting language is you can embed it inside\na (host) application of your own - exporting project-specific variables\nand functions.\n\nYou'll find an example of doing that beneath the [embedded/](embedded/) directory:\n\n* [Embedding the criTiCaL interpreter](embedded/)\n\n\n\n## Examples\n\nThe following is a simple example program which shows what the code here looks like:\n\n\n```tcl\n//\n// Fibonacci sequence, written in the naive/recursive fashion.\n//\nproc fib {x} {\n    if { \u003c= $x 1 } {\n        return 1\n    } else {\n        return [expr [fib [expr $x - 1]] + [fib [expr $x - 2]]]\n    }\n}\n\n//\n// Lets run this in a loop\n//\nset i 0\nset max 20\n\nwhile {\u003c= $i $max } {\n   puts \"Fib $i is [fib $i]\"\n   incr i\n}\n\n```\n\nAnother example is the test-code which @antirez posted with his [picol writeup](http://oldblog.antirez.com/page/picol.html) which looks like this:\n\n```tcl\nproc square {x} {\n    * $x $x\n}\n\nset a 1\nwhile {\u003c= $a 10} {\n    if {== $a 5} {\n        puts {Missing five!}\n        set a [+ $a 1]\n        continue\n    }\n    puts \"I can compute that $a*$a = [square $a]\"\n    set a [+ $a 1]\n}\n```\n\nThis example is contained within this repository as [picol.tcl](picol.tcl), so you can run it directly:\n\n```sh\n     $ ./critical ./picol.tcl\n     I can compute that 1*1 = 1\n     I can compute that 2*2 = 4\n     ..\n```\n\nAdditional TCL-code can be found beneath [examples/](examples/).\n\n\n\n### Available Commands\n\nThe following commands are available, and work as you'd expect:\n\n* `append`, `break`, `continue`, `decr`, `env`, `eval`, `exit`, `expr`, `for`, `if`, `incr`, `proc`, `puts`, `regexp`, `return`, `set`, `while`.\n\nThe complete list of standard [TCL commands](https://www.tcl.tk/man/tcl/TclCmd/contents.html) will almost certainly never be implemented, but pull-request to add omissions you need will be applied with thanks.\n\n\n\n### Features\n\nRead the file [input.tcl](input.tcl) to get a feel for the language, but in-brief you've got the following facilities available:\n\n* Floating-point mathematical operations for `expr`\n  * `+` `-` `/` `*` `%`.\n* Comparison operations for `expr`\n  * `\u003c` `\u003e` `\u003c=` `\u003e=`, `==`, `!=`, `eq`, `ne`\n* Output to STDOUT via `puts`.\n* Inline command expansion, for example `puts [* 3 4]`\n* Inline variable expansion, for example `puts \"$$name is $name\"`.\n* The ability to define procedures, via `proc`.\n  * See the later examples, or examine code such as [examples/prime.tcl](examples/prime.tcl).\n\n\n### Missing Features\n\nThe biggest missing feature is the complete absence of support for lists of any kind.  This is common in the more minimal-TCL interpreters I examined.\n\nThe other obvious missing feature is support for the `upvalue` command, which means we're always a little at risk of scope-related issues.\n\nAdding `upvalue` would be possible, but adding list-processing would be more work than I'd prefer to carry out at this time - see #19 for details of what would be required to implement this support.\n\n\n\n## Testing\n\nOur code has 100% test-coverage, which you can exercise via the standard golang facilities:\n\n```sh\n$ go test ./...\n```\n\nThere are also fuzz-based testers supplied for the [lexer](lexer/) and [parser](parser/) packages, to run these run one of the following two sets of commands:\n\n```sh\ncd parser\ngo test -fuzztime=300s -parallel=1 -fuzz=FuzzParser -v\n```\n\n```sh\ncd lexer\ngo test -fuzztime=300s -parallel=1 -fuzz=FuzzLexer -v\n\n```\n\n\n\n# See Also\n\nThis repository was put together after [experimenting with a scripting language](https://github.com/skx/monkey/), an [evaluation engine](https://github.com/skx/evalfilter/), putting together a [FORTH-like scripting language](https://github.com/skx/foth), writing a [BASIC interpreter](https://github.com/skx/gobasic) and creating [yet another lisp](https://github.com/skx/yal)..\n\nI've also played around with a couple of compilers which might be interesting to refer to:\n\n* Brainfuck compiler:\n  * [https://github.com/skx/bfcc/](https://github.com/skx/bfcc/)\n* A math-compiler:\n  * [https://github.com/skx/math-compiler](https://github.com/skx/math-compiler)\n\n\n\n\n## Bugs?\n\nPlease feel free to open a new issue **with your example** included so I can see how to fix it.\n\n\nSteve\n","funding_links":["https://github.com/sponsors/skx","https://steve.fi/donate/"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskx%2Fcritical","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fskx%2Fcritical","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fskx%2Fcritical/lists"}