github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/README.md (about) 1 [![Build Status](https://travis-ci.com/arnodel/golua.svg?branch=master)](https://travis-ci.com/arnodel/golua) 2 [![Go Report Card](https://goreportcard.com/badge/github.com/arnodel/golua)](https://goreportcard.com/report/github.com/arnodel/golua) 3 [![Coverage](https://codecov.io/gh/arnodel/golua/branch/master/graph/badge.svg)](https://codecov.io/gh/arnodel/golua) 4 5 # GoLua 6 7 Implementation of Lua **5.4** in Go with **no third party dependencies**. The 8 compiler and runtime are complete (including coroutines), the standard Lua 9 library is mostly implemented. 10 11 - [GoLua](#golua) 12 - [Quick start: running golua](#quick-start-running-golua) 13 - [Safe execution environment (alpha)](#safe-execution-environment-alpha) 14 - [Importing and using Go packages](#importing-and-using-go-packages) 15 - [Quick start: embedding golua](#quick-start-embedding-golua) 16 - [Quick start: extending golua](#quick-start-extending-golua) 17 - [Aim](#aim) 18 - [Design constraints](#design-constraints) 19 - [Components](#components) 20 - [Lexer / Parser](#lexer--parser) 21 - [AST → IR Compilation](#ast--ir-compilation) 22 - [IR → Code Compilation](#ir--code-compilation) 23 - [Runtime](#runtime) 24 - [Test Suite](#test-suite) 25 - [The "official" Lua 5.4.3 Test Suite](#the-official-lua-543-test-suite) 26 - [Standard Library](#standard-library) 27 28 ## Quick start: running golua 29 30 To install, run: 31 32 ```sh 33 $ go get github.com/arnodel/golua 34 ``` 35 36 To run interactively (in a repl): 37 38 ```lua 39 $ golua 40 > function fac(n) 41 | if n == 0 then 42 | return 1 43 | else 44 | return n * fac(n - 1) 45 | end 46 | end 47 > -- For convenience the repl also evaluates expressions 48 > -- and prints their value 49 > fac(10) 50 3628800 51 > for i = 0, 5 do 52 | print(i, fac(i)) 53 | end 54 0 1 55 1 1 56 2 2 57 3 6 58 4 24 59 5 120 60 > 61 ``` 62 63 ### Safe execution environment (alpha) 64 65 A unique feature of Golua is that you can run code in a safe execution 66 environment where cpu and memory are restricted. E.g. 67 68 ```lua 69 $ golua -cpulimit=10000000 70 > while true do end 71 !!! CPU limit of 10000000 exceeded 72 Reset limits and continue? [yN] 73 ``` 74 75 You can even do this within Lua itself: 76 77 ```lua 78 $ golua 79 > a = "a" 80 > runtime.callcontext({kill={memory=1000000}}, function() while true do a = a..a end end) 81 killed 82 > #a 83 262144 84 ``` 85 86 For more details read more [here](quotas.md). 87 88 ### Importing and using Go packages 89 90 You can dynamically _import Go packages_ very easily as long as they are already 91 downloaded - this include the standard library. Here is an example of running an 92 http server in the repl: 93 94 ```lua 95 $ golua 96 > go = require('golib') 97 > http = go.import('net/http') 98 > http.HandleFunc('/hello/', function(w, r) 99 | w.Write('hi there from Lua! You requested ' .. r.URL.Path) 100 | end) 101 > http.ListenAndServe(':7777') 102 ``` 103 104 In another terminal you can do: 105 106 ```sh 107 $ curl http://localhost:7777/hello/golua 108 hi there from Lua! You requested /hello/golua 109 ``` 110 111 To run a lua file: 112 113 ```sh 114 $ golua myfile.lua 115 ``` 116 117 Or 118 119 ```sh 120 cat myfile.lua | golua 121 ``` 122 123 E.g. if the file `myfile.lua` contains: 124 125 ```lua 126 local function counter(start, step) 127 return function() 128 local val = start 129 start = start + step 130 return val 131 end 132 end 133 134 local nxt = counter(5, 3) 135 print(nxt(), nxt(), nxt(), nxt()) 136 ``` 137 138 Then: 139 140 ```sh 141 $ golua myfile.lua 142 5 8 11 14 143 ``` 144 145 Errors produce useful tracebacks, e.g. if the file `err.lua` contains: 146 147 ```lua 148 function foo(x) 149 print(x) 150 error("do not do this") 151 end 152 153 function bar(x) 154 print(x) 155 foo(x*x) 156 end 157 158 bar(2) 159 ``` 160 161 Then: 162 163 ``` 164 $ golua err.lua 165 2 166 4 167 !!! error: do not do this 168 in function foo (file err.lua:3) 169 in function bar (file err.lua:8) 170 in function <main chunk> (file err.lua:11) 171 ``` 172 173 ## Quick start: embedding golua 174 175 It's very easy to embed the golua compiler / runtime in a Go program. The example below compiles a lua function, runs it and displays the result. 176 177 ```golang 178 // First we obtain a new Lua runtime which outputs to stdout 179 r := rt.New(os.Stdout) 180 181 // This is the chunk we want to run. It returns an adding function. 182 source := []byte(`return function(x, y) return x + y end`) 183 184 // Compile the chunk. Note that compiling doesn't require a runtime. 185 chunk, _ := r.CompileAndLoadLuaChunk("test", source, rt.TableValue(r.GlobalEnv())) 186 187 // Run the chunk in the runtime's main thread. Its output is the Lua adding 188 // function. 189 add, _ := rt.Call1(r.MainThread(), rt.FunctionValue(chunk)) 190 191 // Now, run the Lua function in the main thread. 192 sum, _ := rt.Call1(r.MainThread(), add, rt.IntValue(40), rt.IntValue(2)) 193 194 // --> 42 195 fmt.Println(sum.AsInt()) 196 ``` 197 198 ## Quick start: extending golua 199 200 It's also very easy to add write Go functions that can be called from Lua code. 201 The example below shows how to. 202 203 This is the Go function that we are going to call from Lua. Its inputs are: 204 205 - `t`: the thread the function is running in. 206 - `c`: the go continuation that represents the context the function is called in. 207 It contains the arguments to the function and the next continuation (the 208 one which receives the values computed by this function). 209 210 It returns the next continuation on success, else an error. 211 212 ```golang 213 func addints(t *rt.Thread, c *rt.GoCont) (rt.Cont, error) { 214 var x, y rt.Int 215 216 // First check there are two arguments 217 err := c.CheckNArgs(2) 218 if err == nil { 219 // Ok then try to convert the first argument to a lua integer (rt.Int). 220 x, err = c.IntArg(0) 221 } 222 if err == nil { 223 // Ok then try to convert the first argument to a lua integer (rt.Int). 224 y, err = c.IntArg(1) 225 } 226 if err != nil { 227 // Some error occured, we return it in our context 228 return nil, err 229 } 230 // Arguments parsed! First get the next continuation. 231 next := c.Next() 232 233 // Then compute the result and push it to the continuation. 234 t.Push1(next, x + y) 235 236 // Finally return the next continuation. 237 return next, nil 238 239 // Note: the last 3 steps could have been written as: 240 // return c.PushingNext(x + y), nil 241 } 242 ``` 243 244 The code sample below shows how this function can be added to the Lua runtime 245 environment and demonstrates calling it from Lua. 246 247 ```golang 248 // First we obtain a new Lua runtime which outputs to stdout 249 r := rt.New(os.Stdout) 250 251 // Load the basic library into the runtime (we need print) 252 base.Load(r) 253 254 // Then we add our addints function to the global environment of the 255 // runtime. 256 r.SetEnvGoFunc(r.GlobalEnv(), "addints", addints, 2, false) 257 258 // This is the chunk we want to run. It calls the addints function. 259 source := []byte(`print("hello", addints(40, 2))`) 260 261 // Compile the chunk. 262 chunk, _ := rt.CompileAndLoadLuaChunk("test", source, r.GlobalEnv()) 263 264 // Run the chunk in the runtime's main thread. It should output 42! 265 _, _ = rt.Call1(r.MainThread(), chunk) 266 ``` 267 268 You can also make custom libraries and use Go values in Lua (using e.g. the 269 `runtime.UserData` type). There is an example implementing a `regex` Lua 270 package that uses Go `regexp.Regexp` in [examples/userdata](examples/userdata) 271 272 ## Aim 273 274 To implememt the Lua programming language in Go, easily embeddable in 275 Go applications. It should be able to run any pure Lua code 276 277 ## Design constraints 278 279 - clean room implementation: do not look at existing implementations 280 - self contained: no dependencies 281 - small: avoid re-implementing features which are already present in 282 the Go language or in the standard library (e.g. garbage collection) 283 - register based VM 284 - no call stack (continuation passing), tail call optimisation. 285 286 ## Components 287 288 ### Lexer / Parser 289 290 - The lexer is implemented in the package `scanner`. 291 - The parser is hand-written and implemented in the `parsing` package. 292 293 ### AST → IR Compilation 294 295 The `ast` package defines all the AST nodes. The `astcomp` package defines a 296 `Compiler` type that is able to compile an AST to IR, using an instance of 297 `ir.CodeBuilder`. 298 299 The `ir` package defines all the IR instructions and the IR compiler. 300 301 ### IR → Code Compilation 302 303 The runtime bytecode is defined in the `code` package. The `ircomp` package 304 defines a `ConstantCompiler` type that is able to compile IR code to runtime 305 bytecode, using an instance of `code.Builder`. 306 307 ### Runtime 308 309 The runtime is implemented in the `runtime` package. This defines a 310 `Runtime` type which contains the global state of a runtime, a 311 `Thread` type which can run a continuation, can yield and can be 312 resumed, the various runtime data types (e.g. `String`, `Int`...). The 313 bytecode interpreter is implemented in the `RunInThread` method of the 314 `LuaCont` data type. 315 316 ### Test Suite 317 318 There is a framework for running lua tests in the package `luatesting`. In the 319 various Go packages, if there is a `lua` directory, each `.lua` file is a test. 320 Expected output is specified in the file as comments of a special form, starting 321 with `-->`: 322 323 ```lua 324 print(1 + 2) 325 --> =3 326 -- "=" means match literally the output line 327 328 print("ababab") 329 --> ~^(ab)*$ 330 -- "~" means match with a regexp (syntax is go regexp) 331 ``` 332 333 Most of the code is covered with such Lua tests. Specific packages or functions 334 are covered with Go tests. 335 336 ### The "official" Lua 5.4.3 Test Suite 337 338 Lua provides a test suites for each version (https://www.lua.org/tests/). There 339 is an adapted version of the 5.4.3 tests 340 [here](https://github.com/arnodel/golua-tests/pull/3) which is supposed to be 341 passed by the latest version of Golua. It is the form of a PR so that the 342 difference with the original test suite can be seen easily. 343 344 Assuming `golua` is installed on your system, those tests can be run from the 345 root of the repository above as follows. 346 347 ```sh 348 golua -u -e "_U=true" all.lua 349 ``` 350 351 For the moment `db.lua` is disabled (the file testing the debug module). All 352 other "soft" tests are run, some with adaptations. The most significant 353 differences are in error messages. 354 355 ### Standard Library 356 357 The `lib` directory contains a number of package, each implementing a 358 lua library. 359 360 - `base`: basic library. It is complete. 361 - `coroutine`: the coroutine library, which is done. 362 - `packagelib`: the package library. It is able to load lua modules 363 but not "native" modules, which would be written in Go. Obviously 364 this is not part of the official Lua specification. Perhaps using 365 the plugin mechanism (https://golang.org/pkg/plugin/) would be a way 366 of doing it. I have no plan to support Lua C modules! 367 - `stringlib`: the string library. It is complete. 368 - `mathlib`: the math library, It is complete. 369 - `tablelib`: the table library. It is complete. 370 - `iolib`: the io library. It is complete. 371 - `utf8lib`: the utf8 library. It is complete. 372 - `debug`: partially implemented (mainly to pass the lua test suite). The 373 `getupvalue`, `setupvalue`, `upvalueid`, `upvaluejoin`, `setmetatable`, 374 functions are implemented fully. The `getinfo` function is partially 375 implemented. The `traceback` function is implemented but its output is 376 different from the C Lua implementation. The `sethook` and `gethook` values 377 are implemented - line hooks may not be as accurate as for C Lua. 378 - `os` package is almost complete - `exit` doesn't support "closing" the Lua 379 state (need to figure out what it means.)