{"id":20559192,"url":"https://github.com/coyove/nj","last_synced_at":"2025-08-07T05:26:52.012Z","repository":{"id":37701637,"uuid":"129978127","full_name":"coyove/nj","owner":"coyove","description":"NJ is a simple script engine in golang with Lua-like syntax.","archived":false,"fork":false,"pushed_at":"2022-11-10T08:50:07.000Z","size":4614,"stargazers_count":17,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-06-03T22:03:11.922Z","etag":null,"topics":["closure","coroutine","go","interpreter","lua","script-language","yield"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coyove.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-04-17T23:52:58.000Z","updated_at":"2023-08-02T19:22:48.000Z","dependencies_parsed_at":"2022-07-13T03:10:31.416Z","dependency_job_id":null,"html_url":"https://github.com/coyove/nj","commit_stats":null,"previous_names":["coyove/script","coyove/potatolang"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/coyove/nj","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coyove%2Fnj","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coyove%2Fnj/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coyove%2Fnj/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coyove%2Fnj/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coyove","download_url":"https://codeload.github.com/coyove/nj/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coyove%2Fnj/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":269203114,"owners_count":24377844,"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","status":"online","status_checked_at":"2025-08-07T02:00:09.698Z","response_time":73,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["closure","coroutine","go","interpreter","lua","script-language","yield"],"created_at":"2024-11-16T03:49:28.394Z","updated_at":"2025-08-07T05:26:51.974Z","avatar_url":"https://github.com/coyove.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"NJ is a simple script engine written in golang with Lua-like syntax.\n\n(If you are looking for a Lua 5.2 compatible engine, refer to tag `v0.2`)\n\n## Differ from Lua\n\n- There is no `table`, instead there are `array` and `object` respectively:\n\t- `a=[1, 2, 3]`.\n\t- `a={a=1, b=2}`.\n\t- Empty array and empty object are `true` when used as booleans.\n- There are `typed` array and `untyped` array:\n\t- Untyped arrays are generic arrays created by `[...]`, it is the builtin array type.\n\t- Typed arrays are special arrays created by Go, say `[]byte`:\n\t\t- `a = bytes(16)` creates a 16-byte long `[]byte`.\n\t\t- `a.append(1)` appends 1 to it.\n\t\t- `a.append(true)` will panic.\n\t\t- `a.untype().append(true)` will `untype` the array into a (new) generic array.\n- Functions are callable objects:\n\t- `function foo() end; assert(type(foo), \"object\")`\n\t- `function foo() end; assert(foo is callable)`\n- Closures are created by capturing all symbols seen in the current scope and binding them to the returned function:\n\t- `function foo(a, b) return function(c) return self.a + self.b + c end end`\n    - `assert(foo(1, 2)(3), 6)`\n- Syntax of calling functions strictly requires no spaces between the callee and '(':\n\t- `print(1)` is the only right way of calling a function.\n\t- `print (1)` literally means two things: 1) get value of `print` and discard it, 2) evaluate `(1)`.\n    - Also note that all required arguments must be provided to call a function properly:\n        - `function foo(a, b) end; foo(1)` is invalid.\n- Spacing rule also applies to unary operator `-`:\n\t- `a = 1-a \u003c=\u003e a = 1 - a` means assign the result of `1-a` to `a`.\n\t- `a = 1 -a` means assign `1` to `a` and negate `a`.\n\t- `a = 1 -a+1` means assign `1` to `a` and eval `-a+1`.\n\t- `a = -a` means negate `a` and assign the result to `a`.\n\t- `a = - a` is invalid.\n- There are two ways to write `if`:\n\t- `if cond then true else false end` as a statement.\n\t- `local a = if(cond, true, false)` as an expression.\n\t- `if(cond) then ... end` is invalid, spaces after `if` statement is mandatory.\n\t- `if (cond, true, false)` is invalid, spaces after `if` expression is not allowed.\n- To write variadic functions:\n\t- `function foo(a, b...) end; args = [1, 2, 3]; foo(args...)`.\n    - Parameters after `...` are optional:\n\t    - `function foo(a ... b, c) end; foo(1); foo(1, 2); foo(1, 2, 3)`\n- Returning multiple arguments will be translated into returning an array, e.g.:\n\t- `function foo() return 1, 2 end \u003c=\u003e function foo() return [1, 2] end`\n\t- `local a, b, c = d \u003c=\u003e local a, b, c = d[0], d[1], d[2]`\n- Everything starts at ZERO. For-loops start inclusively and end exclusively, e.g.:\n\t- `a=[1, 2]; assert(a[0] == 1)`.\n\t- `for i=0,n do ... end` ranges `[0, n-1]`.\n\t- `for i=n-1,-1,-1 do ... end` ranges `[n-1, 0]`.\n- For method function, it can access `this` which points to the receiver:\n\t- `a={}; function a.foo(x) this.x = x end; a.foo(1); assert(a.x, 1)`\n- For any function, use `self` to get itself in the body:\n    - `function foo(x) self.x = x end; foo(1); assert(foo.x, 1)`\n- You can define up to 32000 variables (varies depending on the number of temporal variables generated by interpreter) in a function.\n- Numbers are `int64 + float64` internally, interpreter may promote it to `float64` when needed and downgrade it to `int64` when possible.\n- You can `return` anywhere inside functions, `continue` inside for-loops, `goto` any label within the same function.\n\n## Run\n\n```golang\nprogram, err := nj.LoadString(\"return 1\")\nv, err := program.Run() // v == 1\n```\n\n### Global Values\n\n```golang\nbas.AddGlobal(\"G\", bas.ValueOf(func() int { return 1 }))\n\nprogram, _ := nj.LoadString(\"return G() + 1\")\nv, err := program.Run() // v == 2\n\nprogram, _ = nj.LoadString(\"return G() + 2\")\nv, err = program.Run() // v == 3\n\nprogram, _ = nj.LoadString(\"return G + 2\", \u0026CompileOptions{\n\tGlobals: bas.NewObject(0).SetProp(\"G\", 10).ToMap(), // override the global 'G'\n})\nv, err = program.Run() // v == 12\n```\n\n## Benchmarks\n\nRefer to [here](https://github.com/coyove/nj/blob/master/tests/bench/perf.md).\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoyove%2Fnj","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoyove%2Fnj","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoyove%2Fnj/lists"}