Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d494f9e420 | ||
|
|
6da1107c39 |
17
_test/fun26.go
Normal file
17
_test/fun26.go
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type F func() (int, error)
|
||||||
|
|
||||||
|
func f1() (int, error) { return 3, nil }
|
||||||
|
|
||||||
|
func f2(a string, f F) {
|
||||||
|
c, _ := f()
|
||||||
|
println(a, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
f2("hello", F(f1))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// hello 3
|
||||||
12
_test/goto1.go
Normal file
12
_test/goto1.go
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
if true {
|
||||||
|
goto here
|
||||||
|
}
|
||||||
|
here:
|
||||||
|
println("ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// ok
|
||||||
@@ -194,7 +194,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
|||||||
|
|
||||||
case breakStmt, continueStmt, gotoStmt:
|
case breakStmt, continueStmt, gotoStmt:
|
||||||
if len(n.child) > 0 {
|
if len(n.child) > 0 {
|
||||||
// Handle labeled statements
|
// Handle labeled statements.
|
||||||
label := n.child[0].ident
|
label := n.child[0].ident
|
||||||
if sym, _, ok := sc.lookup(label); ok {
|
if sym, _, ok := sc.lookup(label); ok {
|
||||||
if sym.kind != labelSym {
|
if sym.kind != labelSym {
|
||||||
@@ -211,25 +211,23 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
|||||||
|
|
||||||
case labeledStmt:
|
case labeledStmt:
|
||||||
label := n.child[0].ident
|
label := n.child[0].ident
|
||||||
if sym, _, ok := sc.lookup(label); ok {
|
// TODO(marc): labels must be stored outside of symbols to avoid collisions
|
||||||
if sym.kind != labelSym {
|
// Used labels are searched in current and sub scopes, not upper ones.
|
||||||
err = n.child[0].cfgErrorf("label %s not defined", label)
|
if sym, ok := sc.lookdown(label); ok {
|
||||||
break
|
|
||||||
}
|
|
||||||
sym.node = n
|
sym.node = n
|
||||||
n.sym = sym
|
n.sym = sym
|
||||||
} else {
|
} else {
|
||||||
n.sym = &symbol{kind: labelSym, node: n, index: -1}
|
n.sym = &symbol{kind: labelSym, node: n, index: -1}
|
||||||
sc.sym[label] = n.sym
|
|
||||||
}
|
}
|
||||||
|
sc.sym[label] = n.sym
|
||||||
|
|
||||||
case caseClause:
|
case caseClause:
|
||||||
sc = sc.pushBloc()
|
sc = sc.pushBloc()
|
||||||
if sn := n.anc.anc; sn.kind == typeSwitch && sn.child[1].action == aAssign {
|
if sn := n.anc.anc; sn.kind == typeSwitch && sn.child[1].action == aAssign {
|
||||||
// Type switch clause with a var defined in switch guard
|
// Type switch clause with a var defined in switch guard.
|
||||||
var typ *itype
|
var typ *itype
|
||||||
if len(n.child) == 2 {
|
if len(n.child) == 2 {
|
||||||
// 1 type in clause: define the var with this type in the case clause scope
|
// 1 type in clause: define the var with this type in the case clause scope.
|
||||||
switch {
|
switch {
|
||||||
case n.child[0].ident == nilIdent:
|
case n.child[0].ident == nilIdent:
|
||||||
typ = sc.getType("interface{}")
|
typ = sc.getType("interface{}")
|
||||||
@@ -239,7 +237,7 @@ func (interp *Interpreter) cfg(root *node, importPath string) ([]*node, error) {
|
|||||||
typ, err = nodeType(interp, sc, n.child[0])
|
typ, err = nodeType(interp, sc, n.child[0])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// define the var with the type in the switch guard expression
|
// Define the var with the type in the switch guard expression.
|
||||||
typ = sn.child[1].child[1].child[0].typ
|
typ = sn.child[1].child[1].child[0].typ
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -2333,7 +2331,7 @@ func isCall(n *node) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isBinCall(n *node) bool {
|
func isBinCall(n *node) bool {
|
||||||
return n.kind == callExpr && n.child[0].typ.cat == valueT && n.child[0].typ.rtype.Kind() == reflect.Func
|
return isCall(n) && n.child[0].typ.cat == valueT && n.child[0].typ.rtype.Kind() == reflect.Func
|
||||||
}
|
}
|
||||||
|
|
||||||
func mustReturnValue(n *node) bool {
|
func mustReturnValue(n *node) bool {
|
||||||
@@ -2349,7 +2347,7 @@ func mustReturnValue(n *node) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func isRegularCall(n *node) bool {
|
func isRegularCall(n *node) bool {
|
||||||
return n.kind == callExpr && n.child[0].typ.cat == funcT
|
return isCall(n) && n.child[0].typ.cat == funcT
|
||||||
}
|
}
|
||||||
|
|
||||||
func variadicPos(n *node) int {
|
func variadicPos(n *node) int {
|
||||||
|
|||||||
@@ -72,26 +72,28 @@ type symbol struct {
|
|||||||
// execution to the index in frame, created exactly from the types layout.
|
// execution to the index in frame, created exactly from the types layout.
|
||||||
//
|
//
|
||||||
type scope struct {
|
type scope struct {
|
||||||
anc *scope // Ancestor upper scope
|
anc *scope // ancestor upper scope
|
||||||
|
child []*scope // included scopes
|
||||||
def *node // function definition node this scope belongs to, or nil
|
def *node // function definition node this scope belongs to, or nil
|
||||||
loop *node // loop exit node for break statement
|
loop *node // loop exit node for break statement
|
||||||
loopRestart *node // loop restart node for continue statement
|
loopRestart *node // loop restart node for continue statement
|
||||||
pkgID string // unique id of package in which scope is defined
|
pkgID string // unique id of package in which scope is defined
|
||||||
types []reflect.Type // Frame layout, may be shared by same level scopes
|
types []reflect.Type // frame layout, may be shared by same level scopes
|
||||||
level int // Frame level: number of frame indirections to access var during execution
|
level int // frame level: number of frame indirections to access var during execution
|
||||||
sym map[string]*symbol // Map of symbols defined in this current scope
|
sym map[string]*symbol // map of symbols defined in this current scope
|
||||||
global bool // true if scope refers to global space (single frame for universe and package level scopes)
|
global bool // true if scope refers to global space (single frame for universe and package level scopes)
|
||||||
iota int // iota value in this scope
|
iota int // iota value in this scope
|
||||||
}
|
}
|
||||||
|
|
||||||
// push creates a new scope and chain it to the current one.
|
// push creates a new child scope and chain it to the current one.
|
||||||
func (s *scope) push(indirect bool) *scope {
|
func (s *scope) push(indirect bool) *scope {
|
||||||
sc := scope{anc: s, level: s.level, sym: map[string]*symbol{}}
|
sc := &scope{anc: s, level: s.level, sym: map[string]*symbol{}}
|
||||||
|
s.child = append(s.child, sc)
|
||||||
if indirect {
|
if indirect {
|
||||||
sc.types = []reflect.Type{}
|
sc.types = []reflect.Type{}
|
||||||
sc.level = s.level + 1
|
sc.level = s.level + 1
|
||||||
} else {
|
} else {
|
||||||
// propagate size, types, def and global as scopes at same level share the same frame
|
// Propagate size, types, def and global as scopes at same level share the same frame.
|
||||||
sc.types = s.types
|
sc.types = s.types
|
||||||
sc.def = s.def
|
sc.def = s.def
|
||||||
sc.global = s.global
|
sc.global = s.global
|
||||||
@@ -99,7 +101,7 @@ func (s *scope) push(indirect bool) *scope {
|
|||||||
}
|
}
|
||||||
// inherit loop state and pkgID from ancestor
|
// inherit loop state and pkgID from ancestor
|
||||||
sc.loop, sc.loopRestart, sc.pkgID = s.loop, s.loopRestart, s.pkgID
|
sc.loop, sc.loopRestart, sc.pkgID = s.loop, s.loopRestart, s.pkgID
|
||||||
return &sc
|
return sc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *scope) pushBloc() *scope { return s.push(false) }
|
func (s *scope) pushBloc() *scope { return s.push(false) }
|
||||||
@@ -107,7 +109,7 @@ func (s *scope) pushFunc() *scope { return s.push(true) }
|
|||||||
|
|
||||||
func (s *scope) pop() *scope {
|
func (s *scope) pop() *scope {
|
||||||
if s.level == s.anc.level {
|
if s.level == s.anc.level {
|
||||||
// propagate size and types, as scopes at same level share the same frame
|
// Propagate size and types, as scopes at same level share the same frame.
|
||||||
s.anc.types = s.types
|
s.anc.types = s.types
|
||||||
}
|
}
|
||||||
return s.anc
|
return s.anc
|
||||||
@@ -138,6 +140,20 @@ func (s *scope) lookup(ident string) (*symbol, int, bool) {
|
|||||||
return nil, 0, false
|
return nil, 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lookdown searches for a symbol in the current scope and included ones, recursively.
|
||||||
|
// It returns the first found symbol and true, or nil and false.
|
||||||
|
func (s *scope) lookdown(ident string) (*symbol, bool) {
|
||||||
|
if sym, ok := s.sym[ident]; ok {
|
||||||
|
return sym, true
|
||||||
|
}
|
||||||
|
for _, c := range s.child {
|
||||||
|
if sym, ok := c.lookdown(ident); ok {
|
||||||
|
return sym, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
func (s *scope) rangeChanType(n *node) *itype {
|
func (s *scope) rangeChanType(n *node) *itype {
|
||||||
if sym, _, found := s.lookup(n.child[1].ident); found {
|
if sym, _, found := s.lookup(n.child[1].ident); found {
|
||||||
if t := sym.typ; len(n.child) == 3 && t != nil && (t.cat == chanT || t.cat == chanRecvT) {
|
if t := sym.typ; len(n.child) == 3 && t != nil && (t.cat == chanT || t.cat == chanRecvT) {
|
||||||
|
|||||||
Reference in New Issue
Block a user