A POSIX-compliant AWK interpreter written in Go

GoAWK: an AWK interpreter written in Go

GoDoc TravisCI Build AppVeyor Build

AWK is a fascinating text-processing language, and somehow after reading the delightfully-terse The AWK Programming Language I was inspired to write an interpreter for it in Go. So here it is, feature-complete and tested against "the one true AWK" test suite.

Read more about how GoAWK works and performs here.

Basic usage

To use the command-line version, simply use go get to install it, and then run it using goawk (assuming $GOPATH/bin is in your PATH):

$ go get github.com/benhoyt/goawk
$ goawk 'BEGIN { print "foo", 42 }'
foo 42
$ echo 1 2 3 | goawk '{ print $1 + $3 }'
4

On Windows, " is the shell quoting character, so use " around the entire AWK program on the command line, and use ' around AWK strings -- this is a non-POSIX extension to make GoAWK easier to use on Windows:

C:\> goawk "BEGIN { print 'foo', 42 }"
foo 42

To use it in your Go programs, you can call interp.Exec() directly for simple needs:

input := bytes.NewReader([]byte("foo bar\n\nbaz buz"))
err := interp.Exec("$0 { print $1 }", " ", input, nil)
if err != nil {
    fmt.Println(err)
    return
}
// Output:
// foo
// baz

Or you can use the parser module and then interp.ExecProgram() to control execution, set variables, etc:

src := "{ print NR, tolower($0) }"
input := "A\naB\nAbC"

prog, err := parser.ParseProgram([]byte(src), nil)
if err != nil {
    fmt.Println(err)
    return
}
config := &interp.Config{
    Stdin: bytes.NewReader([]byte(input)),
    Vars:  []string{"OFS", ":"},
}
_, err = interp.ExecProgram(prog, config)
if err != nil {
    fmt.Println(err)
    return
}
// Output:
// 1:a
// 2:ab
// 3:abc

Read the GoDoc documentation for more details.

Differences from AWK

The intention is for GoAWK to conform to awk's behavior and to the POSIX AWK spec, but this section describes some areas where it's different.

Additional features GoAWK has over AWK:

  • It's embeddable in your Go programs! You can even call custom Go functions from your AWK scripts.
  • I/O-bound AWK scripts (which is most of them) are significantly faster than awk, and on a par with gawk and mawk.
  • The parser supports 'single-quoted strings' in addition to "double-quoted strings", primarily to make Windows one-liners easier (the Windows cmd.exe shell uses " as the quote character).

Things AWK has over GoAWK:

  • CPU-bound AWK scripts are slightly slower than awk, and about twice as slow as gawk and mawk.
  • AWK is written by Brian Kernighan.

Stability

This project has a good suite of tests, and I've used it a bunch personally, but it's certainly not battle-tested or heavily used, so please use at your own risk. I intend not to change the Go API in a breaking way.

License

GoAWK is licensed under an open source MIT license.

The end

Have fun, and please contact me if you're using GoAWK or have any feedback!

Owner
Ben Hoyt
By day I’m a software engineer at Canonical, by night a Go hacker and husband/father.
Ben Hoyt
Comments
  • Code coverage support

    Code coverage support

    This PR implements #144 and tries to address all CR notes in https://github.com/benhoyt/goawk/issues/144#issuecomment-1223087337.

    This PR is based on top of previous related PRs #148, #153 in order to eliminate the necessity for different hacky solutions.

    I think code-wise this is ready. The only thing I still want to add - a documentation in own file coverage.md. While I'm working on this I would be really glad if you @benhoyt check the current implementation in this PR. Hopefully now it should be in much better shape than with prevous hacky approach.

  • Variable not detected as array type in presence of recursion

    Variable not detected as array type in presence of recursion

    Nelson Beebe reported the following issue, where goawk doesn't detect array as an array variable - presumably due to the presence of recursion. This code works fine in gawk and mawk.

    # t.awk
    function less(a,b)
    {
        return (a < b)
    }
    
    function partition(array,left,right,    i,j,swap,v)
    {
        i = left - 1
        j = right
        v = array[right]
        for (;;)
        {
            while (less(array[++i],v))
                ;
            while (less(v,array[--j]))
            {
                if (j == left)
                    break
            }
            if (i >= j)
                break
            swap = array[i]
            array[i] = array[j]
            array[j] = swap
        }
        swap = array[i]
        array[i] = array[right]
        array[right] = swap
        return (i)
    }
    
    function quicksort(array,left,right,    i)
    {
        # The code in partition() and quicksort() is a direct translation
        # of the simple quicksort algorithm given in Robert Sedgewick's
        # ``Algorithms in C'', 3rd edition, Addison-Wesley, 1998,
        # pp. 305--307.  We need an O(N lg N) algorithm here instead of a
        # simpler O(N^2) algorithm because the font list has thousands of
        # entries.  There are many things that one can do to tweak
        # quicksort() to make its worst-case behavior of O(N^2) unlikely,
        # and to improve its performance on small sequences by switching
        # to other sorting algorithms.  However, we do not attempt any of
        # those refinements here.
        #
        # The user-defined less(a,b) function conceals the details of how
        # array items are compared.
    
        if (right <= left)
            return
        i = partition(array,left,right)
        quicksort(array, left, i - 1)
        quicksort(array, i + 1, right)
    }
    
    BEGIN {
        a[1] = "aye"
        a[2] = "c"
        a[3] = "bee"
        quicksort(a, 1, 3)
        print 1, a[1]
        print 2, a[2]
        print 3, a[3]
    }
    

    The output is:

    $ go run . -f t.awk
    -------------------------------------------------------------
        i = partition(array,left,right)
            ^
    -------------------------------------------------------------
    parse error at 50:9: can't pass scalar "array" as array param
    exit status 1
    
  • Optimize CONCAT(CONCAT(a, b), c)

    Optimize CONCAT(CONCAT(a, b), c)

    Optimize CONCAT(CONCAT(a, b), c) reported in https://github.com/benhoyt/goawk/issues/91

    Added a ConcatN opcode. Could have used MultiIndex opcode (I tried and it works as is) but "concat" should not be using a separator.

  • Removing duplicate lines

    Removing duplicate lines

    Dear @benhoyt, I’m confused right from the start because

    awk "!line[$0]++" wordlist.txt > deduplicated.txt
    

    works as expected whereas

    goawk "!line[$0]++" wordlist.txt > deduplicated.txt     
    ----------------------------------------------------            
    !line[$0]++                                                     
             ^                                                      
    ----------------------------------------------------            
    parse error at 1:10: expected lvalue before ++ or --            
    

    throws aforementioned error. What would you recommend to do here?

  • Code coverage for GoAWK

    Code coverage for GoAWK

    In this branch I'm working on code coverage functionality for GoAWK, similar to the one built in the Golang itself (https://go.dev/blog/cover).

    In fact, I was able to make the go tool cover to produce the meaningful HTML coverage report for AWK.

    I wonder if you @benhoyt would be interested in adding this to the project. My solution is a bit hacky here and there, but the approach seems to work well.

    I'm still working on adding tests and documentation, and maybe some minor code adjustments, but I would be glad to start getting some feedback from you @benhoyt.

    image

  • Add API to reduce allocations when re-executing the same program

    Add API to reduce allocations when re-executing the same program

    As described in https://github.com/benhoyt/goawk/issues/94, for some use cases it'd be good to have a new API to allow reusing the heavy allocations/initialization that ExecProgram does to set up the interpreter. You use it like so:

    // do this once to parse the program and set up
    prog, err := parser.ParseProgram([]byte(`BEGIN {}`), nil)
    // handle err
    p, err := interp.New(prog)
    // handle err
    
    // do this many times
    p.ResetVars() // this is optional (call if you want to reset the variables between runs)
    status, err := p.Execute(&interp.Config{
    	Stdin:   inputReader,
    	Output:  ioutil.Discard,
    	Environ: []string{},
    })
    // handle err
    

    Benchmarks of the existing ExecProgram API against this new one show just how much the overhead is reduced when repeating the execution of a program. For a trivial program, it's 100x (!) as fast when you don't do I/O, and almost 20x as fast when you do. The memory allocations per execute are also vastly reduced.

    $ go test ./interp -run=^$ -bench=Repeat -benchmem
    goos: linux
    goarch: amd64
    pkg: github.com/benhoyt/goawk/interp
    cpu: Intel(R) Core(TM) i7-6700HQ CPU @ 2.60GHz
    BenchmarkRepeatExecProgram-8     	   82119	     13686 ns/op	   12680 B/op	      17 allocs/op
    BenchmarkRepeatNew-8             	 9028881	       126.8 ns/op	       0 B/op	       0 allocs/op
    BenchmarkRepeatIOExecProgram-8   	   51138	     22887 ns/op	   78488 B/op	      30 allocs/op
    BenchmarkRepeatIONew-8           	  976191	      1224 ns/op	     240 B/op	      11 allocs/op
    PASS
    
  • Decouple parse & resolve steps

    Decouple parse & resolve steps

    This PR is prepared in context of #144.

    It implements the part

    However, that would require separating out the resolver to a separate pass ... which is probably good to do anyway, but a bit of work.

    Since the change is reasonably big I would add couple clarifications.

    1. I tried to do only minimal work to get the task in question done, though I could not resist some (hopefully) minor refactorings and restructuring.
    2. It appears that resolving step needs some positions information, but not for all nodes. So at this point to keep the things simple and limited I wired the position only through very few of AST nodes. If need be we can equip all AST nodes with positions in generic way later but no need at this point.
    3. I decided that we don't need to move ALL things that were in resolve.go to separate step. To me some things logically belong more to parsing than resolution. Example: multiExprs thing.
    4. Since the parsing & resolving needed the same approach to errors with positions I generified this a bit by introducing the PositionError which is now panic-thrown internally by both parser & resolver. However I kept the external parser interface intact to return documented ParseError.
    5. I checked the test suite - seems to work fine.
  • Go AWK seems to have problems with constructs other interpreters don't

    Go AWK seems to have problems with constructs other interpreters don't

    I have a pure-AWK implementation of wcwdith(3) that I've written that can be found at https://github.com/ericpruitt/wcwidth.awk. The test suite for that script runs against BusyBox AWK, GNU Awk, MAWK and "One True AWK" without issue, but it doesn't work with your Go AWK. There appear to be at least two issues. One is parsing; Go AWK doesn't like the placement of one of my break statements:

    buildbox@sinister:wcwidth.awk [1]$ goawk -f wcwidth.awk
    -------------------------------------------------------
                break
                ^
    -------------------------------------------------------
    parse error at 165:13: break must be inside a loop body
    (1)
    buildbox@sinister:wcwidth.awk [1]$ cat -n wcwidth.awk | grep -C2 165
       163          } else if (WCWIDTH_POSIX_MODE) {
       164              _total = -1
       165              break
       166          } else {
       167              # Ignore non-printable ASCII characters.
    

    The other issue has to do with the way command line arguments are handled. AWK lets you modify the ARGV array, so not all arguments need to be options or file paths. Go AWK tries to treat an argument as a file path when it shouldn't:

    buildbox@sinister:wcwidth.awk [1]$ goawk -f wcwidth.awk -f test.awk -v TERSE=1 width-data:width-data
    open width-data:width-data: no such file or directory
    (1)
    

    Original AWK (and the other interpreters) have no problem with this:

    buildbox@sinister:wcwidth.awk [1]$ original-awk -f wcwidth.awk -f test.awk -v TERSE=1 width-data:width-data
    buildbox@sinister:wcwidth.awk [1]$
    
  • Add a runtime timeout using context

    Add a runtime timeout using context

    For embedded use a runtime timeout would make running Awk much safer IMO. I have read using context does impact performance however it doesn't leak goroutines. This was the simplest way I could think of to add a timeout to the runtime of the script.

  • it can't work on windows?

    it can't work on windows?

    I download the newest release version, and run as example (Win7/X64, under cmder):

    $ goawk 'BEGIN { print "foo", 42 }'
    ---------------------------------------------------
    'BEGIN
          ^
    ---------------------------------------------------
    parse error at 1:7: didn't find end quote in string
    
    $ echo 1 2 3 | goawk '{ print $1 + $3 }'
    ---------------------------------------------------
    '{
      ^
    ---------------------------------------------------
    parse error at 1:3: didn't find end quote in string
    

    If I use use double-quoted instead single-quoted, it can work:

    $ goawk "BEGIN { print "foo", 42 }"
     42
    
    

    this result is 42, lose 'foo' ?

    $ echo 1 2 3 | goawk "{ print $1 + $3 }"
    4
    
    $ goawk "BEGIN { print 'foo', 42 }"
    foo 42
    

    work ok.

    IF I RUN THAT:

    $ goawk "{print 'foo'}"
    

    !!!RUN WITH ENDLESS!!!

  • goawk's printf family of functions under Windows

    goawk's printf family of functions under Windows

    Please let single-quotes be used in the printf family of functions. Example:

    C:\bin>dir c:\windows\system32 /s/a-d/-c | mawk "{sum+=$4} END {printf('Total size: %.0f bytes,  %3.2f (GB) for %1d files.\n', sum, (sum/1073741824.0), NR)}"
    Total size: 4559643636 bytes,  4.25 (GB) for 24857 files.
    

    Under goawk:

    C:\bin>dir c:\windows\system32 /s/a-d/-c | goawk "{sum+=$4} END {printf('Total size: %.0f bytes,  %3.2f (GB) for %1d files.\n', sum, (sum/1073741824.0), NR)}"
    ------------------------------------
    {sum+=$4} END {printf('Total size: %.0f bytes,  %3.2f (GB) for %1d files.\n', sum, (sum/1073741824.0), NR)}
                          ^
    ------------------------------------
    parse error at 1:23: unexpected '\''
    

    Under Windows, the double-quote has to be used to combine space-containing arguments into one single, command-line argument. Single quotes can not be used. Therefore, single-quotes must be allowed in the goawk implementation of the printf family of functions. Can you please make it so that the printf family can use either single or double quotes?

  • Add optimization for a[1] -> a[

    Add optimization for a[1] -> a["1"]

    Based on conversation in https://github.com/benhoyt/goawk/pull/154#discussion_r995566431, I realized we (c|sh)ould actually make GoAWK do this micro-optimization: whenever it sees "array indexed by constant integer" like a[1] it could convert that to a["1"] for a slight speedup (though we should verify that it's actually faster!).

  • Add JSON Lines support

    Add JSON Lines support

    The JSON Lines text format (aka JSONL or newline-delimited JSON) has one JSON object per line. It's often used for structured log files or as a well-specified alternative to CSV.

    Here are some ideas how the JSON Lines format could be supported in GoAWK. To be honest I'm not completely sure if this is a good idea, but I've found it interesting to think about. This write-up captures some of my thoughts.

    I can imagine different levels of sophistication. We could start simple and then in later versions support more complex input data and ways to interact with it.

    One JSON array of scalars per line

    ["Name", "Session", "Score", "Completed"]
    ["Gilbert", "2013", 24, true]
    ["Alexa", "2013", 29, true]
    ["May", "2012B", 14, null]
    ["Deloise", "2012A", 19, true] 
    

    Suggestions:

    • Add a jsonl input mode.
    • Columns could be parsed to $1, $2, $3, ...
    • Error handling like with CSV

    Questions:

    • How to handle JSON booleans (true/false) and null?
    • Does Unicode cause some problems?

    One JSON object per line, with pairs of keys and scalar values

    This is used by the Graylog Extended Log Format (GELF).

    {"version":"1.1", "host":"example.org", "short_message": "A log message", "facility":"test", "_foo":"bar"}
    {"version":"1.1", "host":"test.example.org", "short_message": "Another msg", "facility":"test", "_foo":"baz"}
    

    Users wanting to parse Logfmt messages (like myself, see #149) should be able to convert their data into this format quite easily.

    Suggestions:

    • Re-use existing named-field syntax to get the fields (e.g. @"short_message")
    • Update FIELDS array for each line. Don't expect all lines to have the same number or order of fields.

    Nested data

    {"one": 1, "four": [1,2,3,4], "five": {"alpha": ["fo", "fum"], "beta": {"hey": "How's tricks?"}}}
    {"one": 1, "four": [4], "five": {"alpha": ["fa", "fim"], "beta": {"hi": "How's tracks?"}}}
    

    Suggestions:

    • I guess we want to keep the syntax simple and not support something sophisticated like jsonpath or jmespath syntax to extract fields.
    • Maybe just return nested data as JSON strings: `@"four" -> "[1,2,3,4]"
    • Enhance named-field syntax with dots and square brackets to get subfields and array elements: @"five.alpha[1] returns "fum", "five.beta returns "{"hey": "How's tricks?"}" (Quoting issue, see below).
    • Add a function to map JSON array elements to AWK fields, e.g. getjsonarr("five.alpha"). Now $1 is fo, $2 is fum.
    • Maybe add a function to set a new root for field extraction, e.g. setjsonroot("five.beta"); print @"hey". returns How's tricks?
    • Use gron's collection of JSON testdata.

    Questions:

    • How to escape double quotes in returned JSON strings?
    • How to map the first element of a JSON arrays to an AWK field? JSON arrays are 0-based, AWK-fields are 1-based.
  • Dynamically changing RS

    Dynamically changing RS

    I've got a file where the first few bites define some of the attributes of the file. The 9th bite is the record separator.

    I need to read this file, set RS and then read the file "again" but now separated by this new record separator.

    Input file (here the record separator is '):

    UNA:+,? 'UNB+UNOC:3+4042805000102:14+4016001000655:14+201231:0206+EC33218279A++TL'UNH+1+MSCONS:D:04B:UN:2.3'BGM+7+EC33218279A-1+9'DTM+137:202012310206:203'RFF+Z13:13018'NAD+MS+4042805000102::9'NAD+MR+4016001000655::9'UNS+D'NAD+DP'LOC+172+DE00108108359V0000000000000088446'DTM+163:202012300000?+01:303
    

    This works on GNU awk:

    BEGIN { RS=".{9}" }
    NR==1 { $0=substr(RT,1,8); RS=substr(RT,9,1) }
    { print $0 }
    

    output:

    UNA:+,?
    UNB+UNOC:3+4042805000102:14+4016001000655:14+201231:0206+EC33218279A++TL
    UNH+1+MSCONS:D:04B:UN:2.3
    BGM+7+EC33218279A-1+9
    DTM+137:202012310206:203
    RFF+Z13:13018
    NAD+MS+4042805000102::9
    NAD+MR+4016001000655::9
    UNS+D
    NAD+DP
    LOC+172+DE00108108359V0000000000000088446
    DTM+163:202012300000?+01:303
    

    but not on goawk:

    UNA:+,? 
    
    
    
    
    
    
    
    
    
  • Add library of helper functions for creating/processing CSV files

    Add library of helper functions for creating/processing CSV files

    This PR adds a lib.awk library with various helper functions, intended mainly for CSV processing and CSV file creation. The idea here is to try these out in pure AWK form (with fairly inefficient implementations!) and then move to native Go implementations later if they prove useful.

    printheader / printfields

    The intention here is to allow you to create CSV files from scratch. Set OFIELDS and use printheader() in BEGIN to set up and print the field names, then use printfields(a) to output the rows. I'm not sure whether setfields() should be "public" or not. Or maybe we could just have setfields() and to print you'd just say setfields(a); print. The printfields() function is a bit handier though.

    Note: I'm still not convinced we need these functions at all, and would like to see real-world use cases where they actually make the code clearer or simpler. See the "Why not just this?" comments under the examples below.

    # Set fields from array a according to the order in OFIELDS, which must have
    # field numbers as keys (from 1 to N) and field names as values, for example
    # OFIELDS[1] = "name"; OFIELDS[2] = "age".
    function setfields(a,    i) { ... }
    
    # Call setfields(a) and then print the current row.
    function printfields(a) { ... }
    
    # Print the header (field names) from OFIELDS
    function printheader(    i) { ... }
    

    Example usage, to create a 3-row CSV file (plus header row):

    BEGIN {
    	OFIELDS[1] = "name"
    	OFIELDS[2] = "age"
    	printheader()
    
    	a["name"] = "Smith, Bob"
    	a["age"] = 42
    	printfields(a)
    
    	a["name"] = "Brown, Jill"
    	a["age"] = 37
    	printfields(a)
    
    	delete a
    	a["name"] = "Bug, June"
    	printfields(a)
    }
    
    # Why not just this?
    #BEGIN {
    #	print "name", "age"
    #
    #	print "Smith, Bob", 42
    #	print "Brown, Jill", 37
    #	print "Bug, June", ""
    #}
    

    Or, to create a CSV file from a much larger input:

    BEGIN {
    	OFIELDS[1] = "ID"
    	OFIELDS[2] = "Name"
    	printheader()
    }
    
    {
    	a["ID"] = @"School_Id"
    	a["Name"] = @"Org_Name"
    	printfields(a)
    }
    
    # Why not just this?
    #BEGIN { print "ID", "Name" }
    #{ print @"School_Id", @"Org_Name" }
    

    delfield, insfield, fieldnum

    The intention with delfield and insfield is to allow you to easily delete or insert columns from many-columned CSV files where that is simpler than re-printing all the fields.

    I think the delete/insert one field would be the common case, hence the singular names, but it is a bit weird when you're using them to delete/insert multiple fields (maybe we should have both delfield(n) and delfields(n, num)? It's also arguably a bit unexpected that if you called delfield(n, 0) or insfield(n, 0) it would actually delete/insert 1 field, not 0 (because of how AWK "default" arguments work).

    Both functions can be used with the fieldnum() helper that returns the number of a given field name from FIELDS.

    # Delete the nth field from $0. If num is given, delete num fields starting
    # from the nth field.
    function delfield(n, num,    i) { ... }
    
    # Insert a new empty field just before the nth field in $0. If num is given,
    # insert num empty fields just before the nth field.
    function insfield(n, num,    i) { ... }
    
    # Return the number of the given named field, or 0 if there's no field with
    # that name. Only works in -H/header mode.
    function fieldnum(name,    i) { ... }
    

    Examples:

    # To delete the first two fields:
    { delfield(1, 2); print }
    
    # To delete the field named "School_Id":
    { delfield(fieldnum("School_Id")) }
    
    # To add a "Num" record number field as the first field:
    { insfield(1); $1 = NR==1?"Num":NR-1; print }
    

    Fixes #125.

  • Add helper functions for CSV processing

    Add helper functions for CSV processing

    It'd be good to add a library of various functions to help with processing CSV files (or other tabular data, it wouldn't be limited to CSV). For example:

    • The printrow() function mentioned in csv.md.
    • If we add the above, may also want a printheader() function that prints the names in OFIELDS (or just use print?).
    • A function to delete a field or fields, for example delfield(n) to delete a single field, or maybe delfield(n[, c]) to delete c fields starting at field n (c defaults to 1). For one implementation, see the rmcol definition in this StackOverflow answer.
      • Do we also need a delfieldbyname()? Though with a better name.
    • A function to insert a field or fields, eg insfield(n, val). With standard AWK you can kind of cheat with something like {$n=val FS $n;}, but that doesn't work for CSV escaping.

    We could start by making this a simple AWK library that you include, eg goawk -f lib.awk -f prog.awk (prepend/append the library to the source when using the Go API).

    When we want to add them as builtins to GoAWK, we should do it in a backwards-compatible way (i.e., not make them keywords like the other builtins, but if the user redefines a function or variable with that same name, that takes precedence).

Scriptable interpreter written in golang
Scriptable interpreter written in golang

Anko Anko is a scriptable interpreter written in Go. (Picture licensed under CC BY-SA 3.0, photo by Ocdp) Usage Example - Embedded package main impor

Dec 23, 2022
A BASIC interpreter written in golang.
A BASIC interpreter written in golang.

05 PRINT "Index" 10 PRINT "GOBASIC!" 20 PRINT "Limitations" Arrays Line Numbers IF Statement DATA / READ Statements Builtin Functions Types 30 PRINT "

Dec 24, 2022
A simple virtual machine - compiler & interpreter - written in golang

go.vm Installation Build without Go Modules (Go before 1.11) Build with Go Modules (Go 1.11 or higher) Usage Opcodes Notes The compiler The interprete

Dec 17, 2022
Mini lisp interpreter written in Go.

Mini Go Lisp Mini lisp interpreter written in Go. It is implemented with reference to the d-tsuji/SDLisp repository written in Java. Support System Fu

Nov 25, 2022
interpreter for the basic language written in golang
interpreter for the basic language written in golang

jirachi interpreter for the basic language written in golang The plan supports the following functions: Arithmetic Operations (+, -, *, /, ^) Comparis

Sep 17, 2022
◻️ A Whitespace interpreter written in Go.

whitespace-go A Whitespace interpreter written in Go. Whitespace is a esoteric programming language made up entirely of spaces, tabs, and newlines. Th

May 18, 2022
🧠 A Brainfuck interpreter written in Go

brainfuck-go A Brainfuck interpreter written in Go. How Brainfuck works Brainfuck is an esoteric programming language designed to have the simplest co

Sep 30, 2022
A little brainfuck interpreter written in Go

Brainfuck_go_interpreter A little brainfuck interpreter written in Go from what I've done in coding game Usage $ go build brainfuck.go $ ./brainfuck P

Dec 13, 2021
An interpreter written in go for a brainfuck-based language called €*

eurostar-go-interpreter This is an interpreter written in go for a brainfuck-bas

Sep 14, 2022
Simple-lisp - A Simple Lisp Interpreter written in Go

Simple Lisp A simple Lisp interpreter written in Go. The fixed-precision-numbers

Jun 21, 2022
Bf - A brainfuck interpreter written in Go while the programmer was drunk
Bf - A brainfuck interpreter written in Go while the programmer was drunk

BF A (not well tested) brainfuck interpreter written in Go while the programmer

Feb 17, 2022
Prolog interpreter in Go

golog Prolog interpreter in Go with aspirations to be ISO compatible. See the full package documentation for usage details. Install with go get github

Nov 12, 2022
A JavaScript interpreter in Go (golang)

otto -- import "github.com/robertkrimen/otto" Package otto is a JavaScript parser and interpreter written natively in Go. http://godoc.org/github.com/

Jan 2, 2023
Yaegi is Another Elegant Go Interpreter
Yaegi is Another Elegant Go Interpreter

Yaegi is Another Elegant Go Interpreter. It powers executable Go scripts and plugins, in embedded interpreters or interactive shells, on top of the Go

Dec 30, 2022
A shell parser, formatter, and interpreter with bash support; includes shfmt

sh A shell parser, formatter, and interpreter. Supports POSIX Shell, Bash, and mksh. Requires Go 1.14 or later. Quick start To parse shell scripts, in

Jan 8, 2023
Lisp Interpreter

golisp Lisp Interpreter Usage $ golisp < foo.lisp Installation $ go get github.com/mattn/golisp/cmd/golisp Features Call Go functions. Print random in

Dec 15, 2022
Toy Lisp 1.5 interpreter

Lisp 1.5 To install: go get robpike.io/lisp. This is an implementation of the language defined, with sublime concision, in the first few pages of the

Jan 1, 2023
Small Clojure interpreter, linter and formatter.
Small Clojure interpreter, linter and formatter.

Joker is a small Clojure interpreter, linter and formatter written in Go. Installation On macOS, the easiest way to install Joker is via Homebrew: bre

Dec 30, 2022
Go bindings to QuickJS: a fast, small, and embeddable ES2020 JavaScript interpreter.

quickjs Go bindings to QuickJS: a fast, small, and embeddable ES2020 JavaScript interpreter. These bindings are a WIP and do not match full parity wit

Dec 28, 2022