d5 / tengo Goto Github PK
View Code? Open in Web Editor NEWA fast script language for Go
Home Page: https://tengolang.com
License: MIT License
A fast script language for Go
Home Page: https://tengolang.com
License: MIT License
// global recursive function: works perfectly
sum_g := func(a) {
return a == 0 ? 0 : a + sum_g(a-1)
}
print(sum_g(10)) // 55
// local recursive function: causes an error
func() {
sum := func(a) {
return a == 0 ? 0 : a + sum(a-1) // error
}
return sum(10)
}()
// workaround
func() {
sum := undefined
sum = func(a) {
return a == 0 ? 0 : a + sum(a-1) // ok
}
return sum(10)
}()
Instructions:
0000 CONST 5
0003 CALL 0
0005 SETG 0
Constants:
[0] 0 (int)
[1] 0 (int)
[2] 1 (int)
[3] (function)
0000 GETL 0
0002 CONST 0
0005 EQL
0006 JMPF 15
0009 CONST 1
0012 JMP 28
0015 GETL 0
0017 GETF 0
0019 GETL 0
0021 CONST 2
0024 SUB
0025 CALL 1
0027 ADD
0028 RETVAL 1
[4] 10 (int)
[5] (function)
0000 GETL 0
0002 CLOSURE 3 1
0006 DEFL 0
0008 GETL 0
0010 CONST 4
0013 CALL 1
0015 RETVAL 1
Been observing new issues like #44 #45 and #46
Instead of duplicating the Go standard library in Tengo; Why not crate an FFI? This has the added advantage of allowing users to build new modules of anything they need that isn't already part of the Tengo standard library (exposing Go standard library modules/functions).
condition ? true_expr : false_expr
To be able to directly define a user function
s.Add("myFunc", myFunc)
Now, you need to do
s.Add("myFunc", &objects.UserFunction{Value: myFunc})
https://github.com/d5/tengo/blob/master/docs/objects.md
Update with new types and add different custom types (now that Time is one of runtime types).
I think to_json should be added into docs or example
foo := func(...args) {
for x in args {
print(x)
}
}
I found the module documentation in https://github.com/d5/tengo/blob/master/docs/tutorial.md (not sure if there is another document). I was wondering, if and how I can "hide" module-internal stuff, like helper functions etc.
Basically, import expression returns all the global variables defined in the module as a Map-like value.
If all "global defined" variables in a module are exported, there is currently no way to hide module internals, correct?
I was also wondering, what your thought process was for doing it that way, compared e.g. to mark variables as exported.
btw: Thank you a lot for tengo. I'm not using it for anything else then playing around, but I'm learning a lot by trying to understand how you build it! 💕
I don't see any references in your code to os.exec can this execute any external commands?
I was looking into how easy it would be to add an encoding/json
module.
However when i put a tengo map, like:
testMap := {foo: "bar"}
the output result will be:
{"foo":{"Value": "bar"}}
Since the Tengo string object contains the Value field, the result would be like the above.
The proposal would be to add another method signature to the objects.Object interface:
type Object interface{
Value() interface{}
}
which would in the case of the Tengo objects return the value as it is saved in the struct
Do you think something like that would be useful or that it would only make the interface to complicated for simple use?
Unless there are other plans for making a Map Object more accessible in Go?
In the mean time it should also be possible to just do type conversion and work with that, i'll give that a shot too
Would be nice if the error returned by c.Run() would at least give the line number of the script where the error occurred. A stack-trace would even be nicer in case there was some recursion, or user defined function call.
if c, err := s.Compile(); err != nil {
t.Errorf("compile error=%s",err )
} else {
if err := c.Run(); err != nil {
t.Errorf("error %s",err)
}
}
Currently index-get behavior of array is to raise a run-time error. Maybe it can simplify things if array returns undefined
instead.
Also, if this array retuning undefined
makes sense, we may also want to implement IndexGet of Undefined type to return undefined
: undefined[index] => undefined
a := []
b := a[1][2][3] // b == undefined
c := {}
d := c.foo["bar"][1] // d == undefined
Other things to think about (for consistency):
arr[low:high]
: currently it raises error if out-of-bounds. should we keep it?/cc @earncef
Just a thought on architecting for speed, portability, security:
Given that Google has put hundreds of engineer-years into optimizing the v8 Just-in-time compiler, it is not surprising that it can run the recursive fib(35) in about 2x that of Go.
> function fib(n) { if (n<2) { return n; } else { return fib(n-1)+fib(n-2); }
> console.time("hi"); fib(35) ;console.timeEnd("hi")
hi: 128.559ms
So for crazy good performance, it would be great to target wasm bytecode and let v8 run it.
The other nice aspect of targeting wasm would be that for those times when you need portability, there are at least two wasm bytecode interpreters written in pure Go. e.g. https://github.com/perlin-network/life and https://github.com/go-interpreter/wagon
Finally, a third benefit would be high security. V8 offers Isolates and Contexts, which Cloudflare has exploited for the ultimate in scalable-yet-secure "run someone else's untrusted code". See https://blog.cloudflare.com/cloud-computing-without-containers/ for example.
Consider, even just for a moment in a flight of imagination, how hard would it be for tengo to output wasm bytecode? I realize this is ambitious.
p.s. https://github.com/augustoroman/v8 is available for experiment.
Are datas can be used for conditions?
i.e.
for <-foo {
// stops if foo is nil/false
}
I want to supply a Callable to my script via Indexable. But I want the arg to my Callable to be a func() declared in the script. The func() comes to the script as "*CompiledFunction". But I have no way to call the compiled function. My use case is to implement things like map/reduce, where the script is declaring lambda's.
`
`
For example,
v1 := int("foo") // v1 == undefined
v2 := int("foo", 10) // v2 == 10
I notice that,some code use fmt.Sprintf("[%s]", strings.join(",", some array))
to join string
For example ,in some Object String
May be,we can use strings.Builder(go1.10) to speed up it
If you think so,i well push some merge request(1 for use go 1.10, 2 for refactor to use strings.Builder)
Thank you
REPL shares the symbol table and the globals between each line of commands so it keeps the global variables between the lines. It also needs to keep the constants because some values (e.g. closures) and references to those constants need to be shared too.
I'm trying to call a function defined inside the script from the embedning host. Is this possible? I can't seam to find any type of run or call like feature on them.
s := script.New([]byte(`
out := func(state, keyboard, b) {
}
`))
c, _ := s.Compile()
c.Run()
f := c.Get("out").Value().(objects.CompiledFunction)
// ??? f(&objects.String{Value: "a"}, &objects.String{Value: "b"}, &objects.String{Value: "c"})
We can add time
module in a similar way as os
module: Time
as an immutable map object with some method -like functions.
there is an another script language named qlang developed by qiniu. And both the syntax and implementations are similer, so my question is, what is the difference between these two language?
When compiling imported scripts (added via Script.AddModule
), we need to disable all builtins and std-modules that are disabled in the main script. (Imported script inherits the same security rules.)
First off, tengo looks really great. Thanks for making it!
For using tengo as a scripting language, is it possible to have the host program inject variables or functions into the script namespace for the script to use?
Along these lines, Alan Donovan on the Go team has done some nice reflection work for starlark-go on the wip-stargo branch. Any Go library can be called from script in this manner, as long as bindings have been compiled in.
https://github.com/google/starlark-go/tree/wip-stargo
Since it is 3-clause BSD licensed, good ideas there could be borrowed.
This looks great, been looking for something to do some embedded scripting with and this appears to be the best so far - outside of the lua's which i am not a fan of - well done, cannot believe this is a few weeks of work!
When running embedded scripts there's a real risk that they would get stuck forever - maybe someone exec's something that is blocking.
So would be great if there was a Run()
or Script()
that had context support to set deadlines for example. Be interesting to see how we handle spawned things to avoid zombies in that case though.
hey!
i liked the idea of being able to easily use closures in a close-to-go syntax with dynamic checks
however, I cant seem to find some docs about the lang implementation/definition.
Maybe something about the vm: does it do JIT compilation? Can it?
Idk i'd to read some material about the lang itself
First of all, congrats for this amazing project. Well done @d5.
I hope my HN post to bring more people in because this project looks promising.
I have a couple of questions:
print('hello world')
and couldn't make it work.That's it for now, I cannot think of anything else.
As soon as you provide more examples, I will start playing with it to see how I could use it and see whether I could replace some ancient shell scripting projects of mine or not.
Let me know.
Cheers.
Everyone knows that immutability can be useful in many ways.
A couple of questions to answer:
Immutable
object that wraps another object.Other criteria includes:
It seems almost impossible to read a file, read takes a count of how many bytes to read but there is no way to get the size of a file to make the buffer, stat will help
How does it compare to https://github.com/dop251/goja?
Authors approach: https://www.reddit.com/r/golang/comments/5c3vb6/almost_fully_compliant_ecmascript_51/d9uih8q/
how to use go package in tengo
freeze
to transform the value immutable recursively (deep immutability)
Compiler.addConstant
should re-use constant if the same value already exists.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.