Repository: goplus/gop
Pull request #538 (2020-08-10 01:32:36)

only struct support

codecov-commenter: # [Codecov](https://codecov.io/gh/goplus/gop/pull/538?src=pr&el=h1) Report
> Merging [#538](https://codecov.io/gh/goplus/gop/pull/538?src=pr&el=desc) into [master](https://codecov.io/gh/goplus/gop/commit/80914cf3c672deda0cbdd64e5a7d11fb5942797c&el=desc) will **decrease** coverage by `0.06%`.
> The diff coverage is `81.48%`.

[![Impacted file tree graph](https://codecov.io/gh/goplus/gop/pull/538/graphs/tree.svg?width=650&height=150&src=pr&token=4qln9Wk3Pn)](https://codecov.io/gh/goplus/gop/pull/538?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #538      +/-   ##
==========================================
- Coverage   89.56%   89.49%   -0.07%     
==========================================
  Files          40       40              
  Lines        9922    10056     +134     
==========================================
+ Hits         8887     9000     +113     
- Misses        760      772      +12     
- Partials      275      284       +9     
```


| [Impacted Files](https://codecov.io/gh/goplus/gop/pull/538?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [cl/context.go](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree#diff-Y2wvY29udGV4dC5nbw==) | `82.54% <ø> (ø)` | |
| [exec/bytecode/code.go](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9jb2RlLmdv) | `100.00% <ø> (ø)` | |
| [exec/bytecode/context.go](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9jb250ZXh0Lmdv) | `94.54% <ø> (ø)` | |
| [cl/type\_decl.go](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree#diff-Y2wvdHlwZV9kZWNsLmdv) | `82.94% <75.00%> (+0.99%)` | :arrow_up: |
| [exec/bytecode/struct.go](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9zdHJ1Y3QuZ28=) | `82.41% <76.66%> (-2.83%)` | :arrow_down: |
| [cl/expr.go](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree#diff-Y2wvZXhwci5nbw==) | `84.04% <78.12%> (-0.25%)` | :arrow_down: |
| [exec/golang/type.go](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree#diff-ZXhlYy9nb2xhbmcvdHlwZS5nbw==) | `90.42% <80.00%> (-0.72%)` | :arrow_down: |
| [exec/golang/expr.go](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree#diff-ZXhlYy9nb2xhbmcvZXhwci5nbw==) | `93.65% <92.85%> (-0.07%)` | :arrow_down: |
| [exec/bytecode/interface.go](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree#diff-ZXhlYy9ieXRlY29kZS9pbnRlcmZhY2UuZ28=) | `99.08% <100.00%> (+0.01%)` | :arrow_up: |
| [exec/golang/interface.go](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree#diff-ZXhlYy9nb2xhbmcvaW50ZXJmYWNlLmdv) | `93.51% <100.00%> (+0.09%)` | :arrow_up: |
| ... and [3 more](https://codecov.io/gh/goplus/gop/pull/538/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/goplus/gop/pull/538?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/goplus/gop/pull/538?src=pr&el=footer). Last update [80914cf...93ef6b3](https://codecov.io/gh/goplus/gop/pull/538?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).


Patch:
diff --git a/cl/context.go b/cl/context.go
index 98dbfdee..442c751d 100644
--- a/cl/context.go
+++ b/cl/context.go
@@ -189,6 +189,7 @@ type blockCtx struct {
 	parent         *blockCtx
 	syms           map[string]iSymbol
 	noExecCtx      bool
+	takeAddr       bool
 	checkFlag      bool
 	checkArrayAddr bool
 }
diff --git a/cl/expr.go b/cl/expr.go
index 6f1e1413..83d10430 100644
--- a/cl/expr.go
+++ b/cl/expr.go
@@ -294,6 +294,35 @@ func compileCompositeLit(ctx *blockCtx, v *ast.CompositeLit) func() {
 			}
 			ctx.out.MakeMap(typMap, len(v.Elts))
 		}
+	case reflect.Struct:
+		typStruct := typ.(reflect.Type)
+		ctx.infer.Push(&goValue{t: typStruct})
+		return func() {
+			for i, elt := range v.Elts {
+				switch e := elt.(type) {
+				case *ast.KeyValueExpr:
+					fieldName := e.Key.(*ast.Ident).Name
+					ctx.out.Push(fieldName)
+					field, _ := typStruct.FieldByName(fieldName)
+					typVal := field.Type
+					compileExpr(ctx, e.Value)()
+					checkType(typVal, ctx.infer.Pop(), ctx.out)
+				default:
+					// ast.Expr
+					field := typStruct.Field(i)
+					ctx.out.Push(field.Name)
+					typVal := field.Type
+					compileExpr(ctx, elt)()
+					checkType(typVal, ctx.infer.Pop(), ctx.out)
+				}
+			}
+
+			if ctx.takeAddr {
+				ctx.out.Struct(reflect.PtrTo(typStruct), len(v.Elts))
+			} else {
+				ctx.out.Struct(typStruct, len(v.Elts))
+			}
+		}
 	default:
 		log.Panicln("compileCompositeLit failed: unknown -", reflect.TypeOf(typ))
 		return nil
@@ -507,6 +536,17 @@ func compileUnaryExpr(ctx *blockCtx, v *ast.UnaryExpr) func() {
 		if v.Op == token.ADD { // +x
 			return exprX
 		}
+		if v.Op == token.AND {
+			vx := x.(iValue)
+			t := reflect.TypeOf(reflect.New(vx.Type()).Interface())
+			ret := &goValue{t: t}
+			ctx.infer.Ret(1, ret)
+			return func() {
+				ctx.takeAddr = true
+				exprX()
+				ctx.takeAddr = false
+			}
+		}
 	}
 	xcons, xok := x.(*constVal)
 	if xok { // op <const>
diff --git a/cl/stmt.go b/cl/stmt.go
index 4930d7bb..1f83a98f 100644
--- a/cl/stmt.go
+++ b/cl/stmt.go
@@ -233,9 +233,6 @@ func compileBranchStmt(ctx *blockCtx, v *ast.BranchStmt) {
 
 func compileLabeledStmt(ctx *blockCtx, v *ast.LabeledStmt) {
 	label := ctx.defineLabel(v.Label.Name)
-	// make sure all labels in golang code  will be used
-	// TODO improvement exec/bytecode not to jump if delta==0
-	ctx.out.Jmp(label)
 	ctx.out.Label(label)
 	ctx.currentLabel = v
 	compileStmt(ctx, v.Stmt)
diff --git a/cl/type_decl.go b/cl/type_decl.go
index 54f284ba..61e02b23 100644
--- a/cl/type_decl.go
+++ b/cl/type_decl.go
@@ -214,7 +214,11 @@ func toArgTypes(ctx *blockCtx, fields *ast.FieldList) ([]reflect.Type, []string,
 }
 
 func toStructType(ctx *blockCtx, v *ast.StructType) iType {
-	panic("toStructType: todo")
+	var fields []reflect.StructField
+	for _, field := range v.Fields.List {
+		fields = append(fields, toStructField(ctx, field)...)
+	}
+	return reflect.StructOf(fields)
 }
 
 func toInterfaceType(ctx *blockCtx, v *ast.InterfaceType) iType {
@@ -281,6 +285,35 @@ func toInt(ctx *blockCtx, e ast.Expr) int {
 	return int(iv)
 }
 
+func toStructField(ctx *blockCtx, field *ast.Field) []reflect.StructField {
+	var fields []reflect.StructField
+	if field.Names == nil {
+		fields = append(fields, buildField(ctx, field, true, ""))
+	} else {
+		for _, name := range field.Names {
+			fields = append(fields, buildField(ctx, field, false, name.Name))
+		}
+	}
+	return fields
+}
+
+func buildField(ctx *blockCtx, field *ast.Field, anonymous bool, fieldName string) reflect.StructField {
+	var f = reflect.StructField{}
+	if !anonymous {
+		f = reflect.StructField{}
+	}
+	f = reflect.StructField{
+		Name:      fieldName,
+		Type:      toType(ctx, field.Type).(reflect.Type),
+		Anonymous: anonymous,
+	}
+	if field.Tag != nil {
+		tag, _ := strconv.Unquote(field.Tag.Value)
+		f.Tag = reflect.StructTag(tag)
+	}
+	return f
+}
+
 // -----------------------------------------------------------------------------
 
 type typeDecl struct {
diff --git a/exec.spec/interface.go b/exec.spec/interface.go
index b0870580..d5caa9b5 100644
--- a/exec.spec/interface.go
+++ b/exec.spec/interface.go
@@ -310,6 +310,9 @@ type Builder interface {
 	// Make instr
 	Make(typ reflect.Type, arity int) Builder
 
+	// Val instr
+	Struct(typ reflect.Type, arity int) Builder
+
 	// Append instr
 	Append(typ reflect.Type, arity int) Builder
 
diff --git a/exec/bytecode/code.go b/exec/bytecode/code.go
index 17f9b88f..02e174d5 100644
--- a/exec/bytecode/code.go
+++ b/exec/bytecode/code.go
@@ -124,6 +124,7 @@ const (
 	opWrapIfErr     = 43 // reserved(2) offset(24)
 	opDefer         = 44 // reserved(26)
 	opGo            = 45 // arity(26)
+	opStruct        = 46
 )
 
 const (
@@ -211,6 +212,7 @@ var instrInfos = []InstrInfo{
 	opWrapIfErr:     {"wrapIfErr", "", "offset", 26},                      // reserved(2) offset(24)
 	opDefer:         {"defer", "", "", 0},                                 // reserved(26)
 	opGo:            {"go", "", "arity", 26},                              // arity(26)
+	opStruct:        {"struct", "funvArity", "type", (10 << 8) | 16},
 }
 
 // -----------------------------------------------------------------------------
diff --git a/exec/bytecode/context.go b/exec/bytecode/context.go
index e19fa3a4..c837b10e 100644
--- a/exec/bytecode/context.go
+++ b/exec/bytecode/context.go
@@ -239,6 +239,7 @@ var _execTable = [...]func(i Instr, p *Context){
 	opWrapIfErr:     execWrapIfErr,
 	opDefer:         execDefer,
 	opGo:            execGo,
+	opStruct:        execStruct,
 }
 
 var execTable []func(i Instr, p *Context)
diff --git a/exec/bytecode/interface.go b/exec/bytecode/interface.go
index f0acf5fb..d43333ba 100644
--- a/exec/bytecode/interface.go
+++ b/exec/bytecode/interface.go
@@ -384,6 +384,12 @@ func (p *iBuilder) SetIndex(idx int) exec.Builder {
 	return p
 }
 
+// Struct instr
+func (p *iBuilder) Struct(typ reflect.Type, arity int) exec.Builder {
+	((*Builder)(p)).Struct(typ, arity)
+	return p
+}
+
 // Slice instr
 func (p *iBuilder) Slice(i, j int) exec.Builder {
 	((*Builder)(p)).Slice(i, j)
diff --git a/exec/bytecode/struct.go b/exec/bytecode/struct.go
index e13f55e6..c3b32de0 100644
--- a/exec/bytecode/struct.go
+++ b/exec/bytecode/struct.go
@@ -143,3 +143,46 @@ func getRetOf(v interface{}, fun *FuncInfo, i int) reflect.Value {
 }
 
 // -----------------------------------------------------------------------------
+
+// Struct instr
+func (p *Builder) Struct(typ reflect.Type, arity int) *Builder {
+	if arity < 0 {
+		log.Panicln("Struct failed: can't be variadic.")
+	} else if arity >= bitsFuncvArityMax {
+		p.Push(arity - bitsFuncvArityMax)
+		arity = bitsFuncvArityMax
+	}
+	i := (opStruct << bitsOpShift) | (uint32(arity) << bitsOpCallFuncvShift) | p.newType(typ)
+	p.code.data = append(p.code.data, i)
+	return p
+}
+
+func execStruct(i Instr, p *Context) {
+	typStruct := getType(i&bitsOpCallFuncvOperand, p)
+	arity := int((i >> bitsOpCallFuncvShift) & bitsFuncvArityOperand)
+	if arity == bitsFuncvArityMax {
+		arity = p.Pop().(int) + bitsFuncvArityMax
+	}
+	makeStruct(typStruct, arity, p)
+}
+
+func makeStruct(typStruct reflect.Type, arity int, p *Context) {
+	n := arity << 1
+	args := p.GetArgs(n)
+
+	var ptr bool
+	if typStruct.Kind() == reflect.Ptr {
+		ptr = true
+		typStruct = typStruct.Elem()
+	}
+	v := reflect.New(typStruct).Elem()
+	for i := 0; i < n; i += 2 {
+		fieldName := args[i].(string)
+		v.FieldByName(fieldName).Set(reflect.ValueOf(args[i+1]))
+	}
+	if ptr {
+		p.Ret(n, v.Addr().Interface())
+	} else {
+		p.Ret(n, v.Interface())
+	}
+}
diff --git a/exec/golang/builder.go b/exec/golang/builder.go
index 1fb379d8..3ca9a3e4 100644
--- a/exec/golang/builder.go
+++ b/exec/golang/builder.go
@@ -96,7 +96,6 @@ type Builder struct {
 	importPaths map[string]string // aliasName => pkgPath
 	gblScope    scopeCtx          // global scope
 	gblDecls    []ast.Decl        // global declarations
-	labels      []*Label          // labels of current statement
 	fset        *token.FileSet    // fileset of Go+ code
 	cfun        *FuncInfo         // current function
 	cstmt       interface{}       // current statement
diff --git a/exec/golang/expr.go b/exec/golang/expr.go
index 39ed22be..aa2e8fcb 100644
--- a/exec/golang/expr.go
+++ b/exec/golang/expr.go
@@ -631,3 +631,45 @@ var goBuiltinArities = [...]int{
 }
 
 // -----------------------------------------------------------------------------
+
+// Struct instr
+func (p *Builder) Struct(typ reflect.Type, arity int) *Builder {
+	var ptr bool
+	if typ.Kind() == reflect.Ptr {
+		ptr = true
+		typ = typ.Elem()
+	}
+	typExpr := Type(p, typ)
+	elts := make([]ast.Expr, arity)
+	args := p.rhs.GetArgs(arity << 1)
+	for i := 0; i < arity; i++ {
+		elts[i] = &ast.KeyValueExpr{
+			Key:   toField(args[i<<1].(ast.Expr)),
+			Value: args[(i<<1)+1].(ast.Expr),
+		}
+	}
+
+	var ret ast.Expr
+
+	ret = &ast.CompositeLit{
+		Type: typExpr,
+		Elts: elts,
+	}
+	if ptr {
+		ret = &ast.UnaryExpr{
+			Op: token.AND,
+			X:  ret,
+		}
+	}
+	p.rhs.Ret(arity<<1, ret)
+	return p
+}
+
+func toField(expr ast.Expr) *ast.Ident {
+	if ident, ok := expr.(*ast.Ident); ok {
+		return ident
+	}
+	lit := expr.(*ast.BasicLit)
+	field, _ := strconv.Unquote(lit.Value)
+	return Ident(field)
+}
diff --git a/exec/golang/interface.go b/exec/golang/interface.go
index 293faf36..bd919146 100644
--- a/exec/golang/interface.go
+++ b/exec/golang/interface.go
@@ -400,6 +400,12 @@ func (p *iBuilder) SetIndex(idx int) exec.Builder {
 	return p
 }
 
+// Struct instr
+func (p *iBuilder) Struct(typ reflect.Type, arity int) exec.Builder {
+	((*Builder)(p)).Struct(typ, arity)
+	return p
+}
+
 // Slice instr
 func (p *iBuilder) Slice(i, j int) exec.Builder {
 	((*Builder)(p)).Slice(i, j)
diff --git a/exec/golang/stmt.go b/exec/golang/stmt.go
index e8918536..6874b11c 100644
--- a/exec/golang/stmt.go
+++ b/exec/golang/stmt.go
@@ -59,6 +59,8 @@ func (p *Builder) Label(l *Label) *Builder {
 		reservedExpr.Expr = defval
 		return p
 	}
+	// make sure all labels in golang code  will be used
+	p.Jmp(l)
 	p.labels = append(p.labels, l)
 	return p
 }
@@ -415,34 +417,10 @@ func (p *Builder) DefineBlock() *Builder {
 // EndBlock ends a block.
 func (p *Builder) EndBlock() *Builder {
 	p.endBlockStmt(0)
-	blockStmt := getBlockStmts(p)
-	if p.parentCtx == nil {
-		p.rhs.Push(blockStmt)
-	} else {
-		p.parentCtx.stmts = append(p.parentCtx.stmts, blockStmt)
-		p.scopeCtx = p.parentCtx
-	}
+	blockStmt := &ast.BlockStmt{List: p.getStmts(p)}
+	p.scopeCtx = p.parentCtx
+	p.stmts = append(p.stmts, p.labeled(blockStmt, 0))
 	return p
 }
 
-// getBlockStmts will check whether the first stmt in block stmts is labeledStmt.
-// if true ,the whole block should be labeled
-func getBlockStmts(p *Builder) ast.Stmt {
-	body := &ast.BlockStmt{List: p.getStmts(p)}
-	if len(body.List) > 0 {
-		for i := 0; i < len(body.List); i++ {
-			if _, ok := body.List[i].(*ast.DeclStmt); ok {
-				continue
-			}
-			if v, ok := body.List[i].(*ast.LabeledStmt); ok {
-				body.List[i] = v.Stmt
-				v.Stmt = body
-				return v
-			}
-			break
-		}
-	}
-	return body
-}
-
 // ----------------------------------------------------------------------------
diff --git a/exec/golang/type.go b/exec/golang/type.go
index 75fe9356..c6f9738d 100644
--- a/exec/golang/type.go
+++ b/exec/golang/type.go
@@ -26,6 +26,24 @@ import (
 
 // -----------------------------------------------------------------------------
 
+// StructType instr
+func StructType(p *Builder, typ reflect.Type) ast.Expr {
+	var fields = &ast.FieldList{}
+	for i := 0; i < typ.NumField(); i++ {
+		fields.List = append(fields.List, toStructField(p, typ.Field(i)))
+	}
+	return &ast.StructType{Fields: fields}
+}
+
+func toStructField(p *Builder, f reflect.StructField) *ast.Field {
+	var field = &ast.Field{}
+	field.Names = []*ast.Ident{
+		Ident(f.Name),
+	}
+	field.Type = Type(p, f.Type)
+	return field
+}
+
 // MapType instr
 func MapType(p *Builder, typ reflect.Type) *ast.MapType {
 	key := Type(p, typ.Key())
@@ -140,6 +158,7 @@ func Type(p *Builder, typ reflect.Type) ast.Expr {
 		return InterfaceType(p, typ)
 	case reflect.Chan:
 	case reflect.Struct:
+		return StructType(p, typ)
 	}
 	log.Panicln("Type: unknown type -", typ)
 	return nil
diff --git a/exec/golang/var.go b/exec/golang/var.go
index 7dc0c940..a4b7e31c 100644
--- a/exec/golang/var.go
+++ b/exec/golang/var.go
@@ -72,6 +72,7 @@ type scopeCtx struct {
 	parentCtx *scopeCtx
 	vlist     []exec.Var
 	stmts     []ast.Stmt
+	labels    []*Label // labels of current statement
 }
 
 func (p *scopeCtx) addVar(vars ...exec.Var) {
diff --git a/tutorial/25-struct/struct.gop b/tutorial/25-struct/struct.gop
new file mode 100644
index 00000000..4bd5a4c8
--- /dev/null
+++ b/tutorial/25-struct/struct.gop
@@ -0,0 +1,9 @@
+println(struct {
+	A int
+	B string
+}{1, "Hello"})
+
+println(&struct {
+	A int
+	B string
+}{1, "Hello"})


Test patch:
diff --git a/cl/compile_test.go b/cl/compile_test.go
index 66760722..c4961385 100644
--- a/cl/compile_test.go
+++ b/cl/compile_test.go
@@ -252,3 +252,45 @@ func TestPkg2(t *testing.T) {
 }
 
 // -----------------------------------------------------------------------------
+
+var fsTestType = asttest.NewSingleFileFS("/foo", "bar.gop", `
+println(struct {
+	A int
+	B string
+}{1, "Hello"})
+println(&struct {
+	A int
+	B string
+}{1, "Hello"})
+`)
+
+func TestStruct(t *testing.T) {
+	fset := token.NewFileSet()
+	pkgs, err := parser.ParseFSDir(fset, fsTestType, "/foo", nil, 0)
+	if err != nil || len(pkgs) != 1 {
+		t.Fatal("ParseFSDir failed:", err, len(pkgs))
+	}
+
+	bar := pkgs["main"]
+	b := exec.NewBuilder(nil)
+	_, err = NewPackage(b.Interface(), bar, fset, PkgActClMain)
+	if err != nil {
+		t.Fatal("Compile failed:", err)
+	}
+	code := b.Resolve()
+
+	ctx := exec.NewContext(code)
+	ctx.Exec(0, code.Len())
+	if v := ctx.Get(-1); v != nil {
+		t.Fatal("error:", v)
+	}
+	if v := ctx.Get(-2); v != int(11) {
+		t.Fatal("n:", v)
+	}
+	if v := ctx.Get(-3); v != nil {
+		t.Fatal("error:", v)
+	}
+	if v := ctx.Get(-4); v != int(10) {
+		t.Fatal("n:", v)
+	}
+}
diff --git a/cl/expr_test.go b/cl/expr_test.go
index 5e4c7a18..c4cb2632 100644
--- a/cl/expr_test.go
+++ b/cl/expr_test.go
@@ -666,6 +666,37 @@ func TestCopy(t *testing.T) {
 	testScripts(t, "TestCopy", testCopyClauses)
 }
 
+var testStructClauses = map[string]testData{
+	"struct": {`
+			println(struct {
+				A int
+				B string
+			}{1, "Hello"})	
+					`, "{1 Hello}\n", false},
+	"struct_key_value": {`
+			println(struct {
+				A int
+				B string
+			}{A:1,B: "Hello"})	
+					`, "{1 Hello}\n", false},
+	"struct_ptr": {`
+			println(&struct {
+				A int
+				B string
+			}{1, "Hello"})
+					`, "&{1 Hello}\n", false},
+	"struct_key_value_ptr": {`
+			println(&struct {
+				A int  ` + "`json:\"a\"`" + `
+				B string
+			}{A: 1,B: "Hello"})
+					`, "&{1 Hello}\n", false},
+}
+
+func TestStruct2(t *testing.T) {
+	testScripts(t, "TestStruct", testStructClauses)
+}
+
 func testScripts(t *testing.T, testName string, scripts map[string]testData) {
 	for name, script := range scripts {
 		t.Log("Run " + testName + "---" + name)
diff --git a/exec/bytecode/struct_test.go b/exec/bytecode/struct_test.go
new file mode 100644
index 00000000..9c442584
--- /dev/null
+++ b/exec/bytecode/struct_test.go
@@ -0,0 +1,92 @@
+/*
+ Copyright 2020 The GoPlus Authors (goplus.org)
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+     http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+package bytecode
+
+import (
+	"os"
+	"reflect"
+	"testing"
+)
+
+// -----------------------------------------------------------------------------
+
+type Person struct {
+	Name string
+	Age  int
+}
+
+func TestStruct(t *testing.T) {
+	println, ok := I.FindFuncv("Println")
+	if !ok {
+		t.Fatal("FindFuncv failed: Println")
+	}
+
+	b := newBuilder()
+	p := Person{
+		Name: "bar",
+		Age:  30,
+	}
+
+	v := NewVar(reflect.TypeOf(p), "p")
+	expect(t,
+		func() {
+			b.DefineVar(v)
+			b.Push("Name")
+			b.Push("bar")
+			b.Push("Age")
+			b.Push(30)
+			b.Struct(reflect.TypeOf(p), 2)
+			b.StoreVar(v)
+			b.LoadVar(v)
+			b.CallGoFuncv(println, 1, 1)
+			code := b.Resolve()
+			code.(*Code).Dump(os.Stderr)
+			ctx := NewContext(code)
+			ctx.Exec(0, code.Len())
+		},
+		"{bar 30}\n",
+	)
+}
+
+func TestStruct2(t *testing.T) {
+	println, ok := I.FindFuncv("Println")
+	if !ok {
+		t.Fatal("FindFuncv failed: Println")
+	}
+
+	b := newBuilder()
+	p := &Person{
+		Name: "bar",
+		Age:  30,
+	}
+
+	v := NewVar(reflect.TypeOf(p), "p")
+	expect(t,
+		func() {
+			b.DefineVar(v)
+			b.Push("Name")
+			b.Push("bar")
+			b.Push("Age")
+			b.Push(30)
+			b.Struct(reflect.TypeOf(p), 2)
+			b.StoreVar(v)
+			b.LoadVar(v)
+			b.CallGoFuncv(println, 1, 1)
+			code := b.Resolve()
+			code.(*Code).Dump(os.Stderr)
+			ctx := NewContext(code)
+			ctx.Exec(0, code.Len())
+		},
+		"&{bar 30}\n",
+	)
+}
diff --git a/exec/golang/builder_test.go b/exec/golang/builder_test.go
index e5cf3e66..2d488725 100644
--- a/exec/golang/builder_test.go
+++ b/exec/golang/builder_test.go
@@ -171,6 +171,94 @@ func main() {
 
 // -----------------------------------------------------------------------------
 
+func TestStruct(t *testing.T) {
+	println, _ := I.FindFuncv("println")
+
+	codeExp := `package main
+
+import fmt "fmt"
+
+func main() {
+	fmt.Println(struct {
+		Name string
+		Age  int
+	}{Name: "bar", Age: 30})
+}
+`
+	fields := []reflect.StructField{
+		{
+			Name: "Name",
+			Type: reflect.TypeOf(""),
+		},
+		{
+			Name: "Age",
+			Type: reflect.TypeOf(0),
+		},
+	}
+	typ := reflect.StructOf(fields)
+
+	code := NewBuilder("main", nil, nil).Interface().
+		Push("Name").
+		Push("bar").
+		Push("Age").
+		Push(30).
+		Struct(typ, 2).
+		CallGoFuncv(println, 1, 1).
+		EndStmt(nil, &stmtState{rhsBase: 0}).
+		Resolve()
+
+	codeGen := code.(*Code).String()
+	if codeGen != codeExp {
+		fmt.Println(codeGen)
+		fmt.Println(codeExp)
+		t.Fatal("TestStruct failed: codeGen != codeExp")
+	}
+}
+
+func TestStruct2(t *testing.T) {
+	println, _ := I.FindFuncv("println")
+
+	codeExp := `package main
+
+import fmt "fmt"
+
+func main() {
+	fmt.Println(&struct {
+		Name string
+		Age  int
+	}{Name: "bar", Age: 30})
+}
+`
+	fields := []reflect.StructField{
+		{
+			Name: "Name",
+			Type: reflect.TypeOf(""),
+		},
+		{
+			Name: "Age",
+			Type: reflect.TypeOf(0),
+		},
+	}
+	typ := reflect.StructOf(fields)
+
+	code := NewBuilder("main", nil, nil).Interface().
+		Push("Name").
+		Push("bar").
+		Push("Age").
+		Push(30).
+		Struct(reflect.PtrTo(typ), 2).
+		CallGoFuncv(println, 1, 1).
+		EndStmt(nil, &stmtState{rhsBase: 0}).
+		Resolve()
+
+	codeGen := code.(*Code).String()
+	if codeGen != codeExp {
+		fmt.Println(codeGen)
+		fmt.Println(codeExp)
+		t.Fatal("TestStruct failed: codeGen != codeExp")
+	}
+}
+
 func TestReserved(t *testing.T) {
 	code := NewBuilder("main", nil, nil)
 	off := code.Reserve()
diff --git a/exec/golang/testdata/12.flow/flow.gop b/exec/golang/testdata/12.flow/flow.gop
index 20408d1d..8e6c2709 100644
--- a/exec/golang/testdata/12.flow/flow.gop
+++ b/exec/golang/testdata/12.flow/flow.gop
@@ -1,3 +1,10 @@
+func foo() bool {
+	return true
+}
+func bar() bool {
+	return true
+}
+
 x := 0
 if t := false; t {
 	x = 3
@@ -150,3 +157,10 @@ L3:
 	}
 	println(forFoo1())
 	fooFoo2()
+
+	// bugs #533
+	if foo() {
+		println("foo")
+	} else {
+		println("bar")
+	}
diff --git a/exec/golang/testdata/26.struct/struct.gop b/exec/golang/testdata/26.struct/struct.gop
new file mode 100644
index 00000000..4bd5a4c8
--- /dev/null
+++ b/exec/golang/testdata/26.struct/struct.gop
@@ -0,0 +1,9 @@
+println(struct {
+	A int
+	B string
+}{1, "Hello"})
+
+println(&struct {
+	A int
+	B string
+}{1, "Hello"})