summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/d5/tengo/compiler/bytecode.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/d5/tengo/compiler/bytecode.go')
-rw-r--r--vendor/github.com/d5/tengo/compiler/bytecode.go134
1 files changed, 134 insertions, 0 deletions
diff --git a/vendor/github.com/d5/tengo/compiler/bytecode.go b/vendor/github.com/d5/tengo/compiler/bytecode.go
new file mode 100644
index 00000000..42527731
--- /dev/null
+++ b/vendor/github.com/d5/tengo/compiler/bytecode.go
@@ -0,0 +1,134 @@
+package compiler
+
+import (
+ "encoding/gob"
+ "fmt"
+ "io"
+ "reflect"
+
+ "github.com/d5/tengo/compiler/source"
+ "github.com/d5/tengo/objects"
+)
+
+// Bytecode is a compiled instructions and constants.
+type Bytecode struct {
+ FileSet *source.FileSet
+ MainFunction *objects.CompiledFunction
+ Constants []objects.Object
+}
+
+// Decode reads Bytecode data from the reader.
+func (b *Bytecode) Decode(r io.Reader) error {
+ dec := gob.NewDecoder(r)
+
+ if err := dec.Decode(&b.FileSet); err != nil {
+ return err
+ }
+ // TODO: files in b.FileSet.File does not have their 'set' field properly set to b.FileSet
+ // as it's private field and not serialized by gob encoder/decoder.
+
+ if err := dec.Decode(&b.MainFunction); err != nil {
+ return err
+ }
+
+ if err := dec.Decode(&b.Constants); err != nil {
+ return err
+ }
+
+ // replace Bool and Undefined with known value
+ for i, v := range b.Constants {
+ b.Constants[i] = cleanupObjects(v)
+ }
+
+ return nil
+}
+
+// Encode writes Bytecode data to the writer.
+func (b *Bytecode) Encode(w io.Writer) error {
+ enc := gob.NewEncoder(w)
+
+ if err := enc.Encode(b.FileSet); err != nil {
+ return err
+ }
+
+ if err := enc.Encode(b.MainFunction); err != nil {
+ return err
+ }
+
+ // constants
+ return enc.Encode(b.Constants)
+}
+
+// FormatInstructions returns human readable string representations of
+// compiled instructions.
+func (b *Bytecode) FormatInstructions() []string {
+ return FormatInstructions(b.MainFunction.Instructions, 0)
+}
+
+// FormatConstants returns human readable string representations of
+// compiled constants.
+func (b *Bytecode) FormatConstants() (output []string) {
+ for cidx, cn := range b.Constants {
+ switch cn := cn.(type) {
+ case *objects.CompiledFunction:
+ output = append(output, fmt.Sprintf("[% 3d] (Compiled Function|%p)", cidx, &cn))
+ for _, l := range FormatInstructions(cn.Instructions, 0) {
+ output = append(output, fmt.Sprintf(" %s", l))
+ }
+ default:
+ output = append(output, fmt.Sprintf("[% 3d] %s (%s|%p)", cidx, cn, reflect.TypeOf(cn).Elem().Name(), &cn))
+ }
+ }
+
+ return
+}
+
+func cleanupObjects(o objects.Object) objects.Object {
+ switch o := o.(type) {
+ case *objects.Bool:
+ if o.IsFalsy() {
+ return objects.FalseValue
+ }
+ return objects.TrueValue
+ case *objects.Undefined:
+ return objects.UndefinedValue
+ case *objects.Array:
+ for i, v := range o.Value {
+ o.Value[i] = cleanupObjects(v)
+ }
+ case *objects.Map:
+ for k, v := range o.Value {
+ o.Value[k] = cleanupObjects(v)
+ }
+ }
+
+ return o
+}
+
+func init() {
+ gob.Register(&source.FileSet{})
+ gob.Register(&source.File{})
+ gob.Register(&objects.Array{})
+ gob.Register(&objects.ArrayIterator{})
+ gob.Register(&objects.Bool{})
+ gob.Register(&objects.Break{})
+ gob.Register(&objects.BuiltinFunction{})
+ gob.Register(&objects.Bytes{})
+ gob.Register(&objects.Char{})
+ gob.Register(&objects.Closure{})
+ gob.Register(&objects.CompiledFunction{})
+ gob.Register(&objects.Continue{})
+ gob.Register(&objects.Error{})
+ gob.Register(&objects.Float{})
+ gob.Register(&objects.ImmutableArray{})
+ gob.Register(&objects.ImmutableMap{})
+ gob.Register(&objects.Int{})
+ gob.Register(&objects.Map{})
+ gob.Register(&objects.MapIterator{})
+ gob.Register(&objects.ReturnValue{})
+ gob.Register(&objects.String{})
+ gob.Register(&objects.StringIterator{})
+ gob.Register(&objects.Time{})
+ gob.Register(&objects.Undefined{})
+ gob.Register(&objects.UserFunction{})
+}