{"id":22508965,"url":"https://github.com/viant/igo","last_synced_at":"2025-08-03T13:31:11.734Z","repository":{"id":57658263,"uuid":"467980262","full_name":"viant/igo","owner":"viant","description":"Go evaluator in go ","archived":false,"fork":false,"pushed_at":"2024-04-24T16:23:10.000Z","size":238,"stargazers_count":3,"open_issues_count":0,"forks_count":1,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-06-21T06:42:14.430Z","etag":null,"topics":["evaluator","go","interpreter"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/viant.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-09T15:17:53.000Z","updated_at":"2024-04-24T16:14:34.000Z","dependencies_parsed_at":"2024-04-24T17:45:58.881Z","dependency_job_id":"a193934d-1fd9-4793-9030-e5e855f90aa9","html_url":"https://github.com/viant/igo","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viant%2Figo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viant%2Figo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viant%2Figo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/viant%2Figo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/viant","download_url":"https://codeload.github.com/viant/igo/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228547518,"owners_count":17935093,"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":["evaluator","go","interpreter"],"created_at":"2024-12-07T01:26:24.822Z","updated_at":"2024-12-07T01:26:25.324Z","avatar_url":"https://github.com/viant.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# igo (go evaluator in go)\n\n[![GoReportCard](https://goreportcard.com/badge/github.com/viant/igo)](https://goreportcard.com/report/github.com/viant/igo)\n[![GoDoc](https://godoc.org/github.com/viant/igo?status.svg)](https://godoc.org/github.com/viant/igo)\n\nThis library is compatible with Go 1.17+\n\nPlease refer to [`CHANGELOG.md`](CHANGELOG.md) if you encounter breaking changes.\n\n- [Motivation](#motivation)\n- [Introduction](#introduction)\n- [Usage](#usage)\n- [Performance](#performance)\n- [Bugs](#bugs)\n- [Contribution](#contributing-to-igo)\n- [License](#license)\n\n## Motivation\n\nThe goal of this library is to be able dynamically execute go code directly from Go/WebAssembly \nwithin reasonable time. Some existing alternative providing go evaluation on the fly are prohibitively slow: \n- [GoEval](https://github.com/xtaci/goeval)\n- [GoVal](https://github.com/maja42/goval) \n- [Yaegi](https://github.com/traefik/yaegi) .\n\nSee [performance](#performance) section for details.\n\n## Introduction\n\nIn order to reduce execution time, this project first produces execution plan alongside with state needed to execute it.\nOne execution plan can be shared alongside many instances state needed by executor. \nState holds both variables and execution state used in the evaluation code.\n\n```go\npackage mypkg\n\nimport \"github.com/viant/igo\"\n\nfunc usage() {\n\tscope := igo.NewScope()\n\tcode := \"go code here\"\n\texecutor, stateNew, err := scope.Compile(code)\n\tif err != nil {\n\t\tpanic(err)\n\t}\n\tstate := stateNew() //creates memory instance needed by executor \n\texecutor.Exec(state)\n}\n\t\n```\n\n## Usage\n\n### Expression\n\n```go\npackage mypkg\n\nimport (\n\t\"log\"\n\t\"reflect\"\n\t\"github.com/viant/igo\"\n)\n\nfunc ExampleScope_BoolExpression() {\n\ttype Performance struct {\n\t\tId      int\n\t\tPrice   float64\n\t\tMetricX float64\n\t}\n\tscope := igo.NewScope()\n\t_, err := scope.DefineVariable(\"perf\", reflect.TypeOf(Performance{}))\n\t_, err = scope.DefineVariable(\"threshold\", reflect.TypeOf(0.0))\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\t//Compile bool expression\n\texpr, err := scope.BoolExpression(\"perf.MetricX \u003e threshold \u0026\u0026 perf.Price \u003e 1.0\")\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tperfs := []Performance{\n\t\t{MetricX: 1.5, Price: 3.2},\n\t\t{MetricX: 1.2, Price: 1.2},\n\t\t{MetricX: 1.7, Price: 0.4},\n\t}\n\tvar eval = make([]bool, len(perfs))\n\tfor i := range perfs {\n\t\t_ = expr.Vars.SetValue(\"perf\", perfs[i])\n\t\t_ = expr.Vars.SetFloat64(\"threshold\", 0.7)\n\t\teval[i] = expr.Compute()\n\t}\n}\n```\n\n### Go evaluation\n\n```go\npackage mypkg\n\nimport (\n\t\"log\"\n\t\"fmt\"\n\t\"github.com/viant/igo\"\n)\n\nfunc ExampleScope_Compile() {\n\tcode := `type Foo struct {\n        ID int\n        Name string\n    }\n    var foos = make([]*Foo, 0)\n    for i:=0;i\u003c10;i++ {\n        foos = append(foos, \u0026Foo{ID:i, Name:\"nxc\"})\n    }\n    s := 0\n    for i, foo := range foos {\n        if i %2  == 0 {\n        s += foo.ID\n    }\n}`\n\n\tscope := igo.NewScope()\n\texecutor, stateNew, err := scope.Compile(code)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\n\tstate := stateNew() //variables constructor, one per each concurent execution, execution can be shared\n\texecutor.Exec(state)\n\tresult, _ := state.Int(\"s\")\n\tfmt.Printf(\"result: %v\\n\", result)\n}\n```\n\nSetting code variables\n\n```go\npackage mypkg\n\nimport (\n\t\"log\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"github.com/viant/igo\"\n)\n\nfunc ExampleScope_DefineVariable() {\n\tcode := `\n\tx := 0.0\n\tfor _, account := range accounts {\n\t\tx += account.Total\n\t}\n\t`\n\ttype Account struct {\n\t\tTotal float64\n\t}\n\n\tscope := igo.NewScope()\n\terr := scope.RegisterType(reflect.TypeOf(Account{})) //Register all non-primitive types used in code \n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\texecutor, stateNew, err := scope.Compile(code)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\tstate := stateNew()\n\terr = state.SetValue(\"accounts\", []Account{\n\t\t{Total: 1.3},\n\t\t{Total: 3.7},\n\t})\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\texecutor.Exec(state)\n\tresult, _ := state.Float64(\"x\")\n\tfmt.Printf(\"result: %v\\n\", result)\n}\n```\n\n### Go function\n\n```go\npackage mypkg\n\nimport (\n\t\"log\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"github.com/viant/igo\"\n)\n\nfunc ExampleScope_Function() {\n\ttype Foo struct {\n\t\tZ int\n\t}\n\tscope := igo.NewScope()\n\t_ = scope.RegisterType(reflect.TypeOf(Foo{}))\n\tfn, err := scope.Function(`func(x, y int, foo Foo) int {\n            return (x+y)/foo.Z\n        }`)\n\tif err != nil {\n\t\tlog.Fatalln(err)\n\t}\n\ttypeFn, ok := fn.(func(int, int, Foo) int)\n\tif !ok {\n\t\tlog.Fatalf(\"expected: %T, but had: %T\", typeFn, fn)\n\t}\n\tr := typeFn(1, 2, Foo{3})\n\tfmt.Printf(\"%v\\n\", r)\n}\n```\n## Registering types\n\nTo use data types defined outside the code, register type with `(Scope).RegisterType(type)` function or\n`(Scope).RegisterNamedType(name, type)`\n\n```go\n    scope := igo.NewScope()\n    _ = scope.RegisterType(reflect.TypeOf(Foo{}))\n\n```\n\n\nDefineVariable\n## Registering function\n\nTo use function defined outside the code, register type with `(Scope).RegisterFunc(name, function)` function\n\n```go\n    scope := igo.NewScope()\n    scope.RegisterFunc(testCase.fnName, testCase.fn)\n\n```\n\n\n\n## Performance\n\n### Expression evaluation\n\nSee benchmark for the following expression evaluation:\n\n```10 + (5 * x / y * (z - 7))```\n\n```text\nBenchmarkScope_IntExpression_Native-16          134789700                8.627 ns/op           0 B/op          0 allocs/op\nBenchmarkScope_IntExpression-16                 19722770                57.06 ns/op            8 B/op          1 allocs/op\nBenchmarkScope_IntExpression_GoVal-16             625620                2040 ns/op          2328 B/op        11 allocs/op\n```\n\n[GoVal](https://github.com/maja42/goval) is ~255 slower for the presented expression comparing to natively compiled code, \nwhile Igo is only ~7 times slower\n\n\n### Code execution\n\nSee benchmark for the following code:\n```go\ncount :=0\nfor i :=0;i\u003c100;i++ {\n    count += i\n}\nprint(count)\n```\n\n[GoEval](https://github.com/xtaci/goeval) evaluation takes almost ~24K time longer than natively compiled code,\nwhereas this project is only around ~35 slower. As point of reference using native go reflection adds on average\naround 100x time execution overhead.\n\n```text\nBenchmark_Loop_Native-16                        35385890               30.36 ns/op             0 B/op          0 allocs/op\nBenchmark_Loop_Igo-16                            1000000              1081  ns/op               0 B/op          0 allocs/op\nBenchmark_Loop_GoEval-16                            1429            739672  ns/op          788350 B/op       3180 allocs/op\n```\n\nSee the following benchmark that runs 100 000 000 loop iteration:\n```text\n\tz := 0\n\ta := 100000000\n\tr := 1\n\tfor i := 1; i \u003c= a; i++ {\n\t\tr += i\n\t}\n\tz = r\n```\n\n```text\nBenchmarkLoop_Yaegi-16    \t                      1\t       3581461319 ns/op\t          47560 B/op\t    681 allocs/op\nBenchmarkLongLoop_Igo-16                          2         661982642 ns/op               8 B/op          0 allocs/op\nBenchmarkLongLoop_Native-16                      48          24813792 ns/op               0 B/op          0 allocs/op\n```\nIgo is ~26x times slower than natively compile code, \nwhereas Yaegi is ~144x times slower than natively compile code\n\n## Bugs\n\nThis project does not implement full golang spec, but just a subset.\nAt least following expression/types/construct are not supported\n- map type\n- named interface types (since pointers are used to access/mutate data)\n- go routines\n- select expression\n- switch expression\n- closures\n\n\n## Contributing to igo\n\nIgo is an open source project and contributors are welcome!\n\nSee [TODO](TODO.md) list\n\n## Credits and Acknowledgements\n\n**Library Author:** Adrian Witas\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fviant%2Figo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fviant%2Figo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fviant%2Figo/lists"}