Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions gnovm/pkg/gnolang/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -2254,6 +2254,14 @@ func (m *Machine) PopAsPointer2(lx Expr) (pv PointerValue, ro bool) {
lb := m.LastBlock()
pv = lb.GetPointerTo(m.Store, lx.Path)
ro = false // always mutable
case NameExprTypeLoopVarDefine:
lb := m.LastBlock()
pv = lb.GetPointerTo(m.Store, lx.Path)
ro = false // always mutable
case NameExprTypeLoopVarUse:
lb := m.LastBlock()
pv = lb.GetPointerTo(m.Store, lx.Path)
ro = false // always mutable
case NameExprTypeHeapUse:
lb := m.LastBlock()
pv = lb.GetPointerTo(m.Store, lx.Path)
Expand Down
116 changes: 116 additions & 0 deletions gnovm/pkg/gnolang/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ const (
ATTR_PACKAGE_DECL GnoAttribute = "ATTR_PACKAGE_DECL"
ATTR_PACKAGE_PATH GnoAttribute = "ATTR_PACKAGE_PATH" // if name expr refers to package.
ATTR_FIX_FROM GnoAttribute = "ATTR_FIX_FROM" // gno fix this version.
ATTR_REDEFINE_NAME GnoAttribute = "ATTR_REDEFINE_NAME"
)

// Embedded in each Node.
Expand Down Expand Up @@ -380,6 +381,12 @@ const (
NameExprTypeHeapDefine // when defining escaped name in loop
NameExprTypeHeapUse // when above used in non-define lhs/rhs
NameExprTypeHeapClosure // when closure captures name

NameExprTypeLoopVarDefine // when defining a loopvar
NameExprTypeLoopVarUse

NameExprTypeLoopVarHeapDefine // when loopvar is captured
NameExprTypeLoopVarHeapUse
)

type NameExpr struct {
Expand Down Expand Up @@ -1556,6 +1563,8 @@ type BlockNode interface {
GetBody() Body
SetBody(Body)

FindNameMaybeLoopvar(Store, Name) (bool, bool)

// Utility methods for gno fix etc.
// Unlike GetType[Decl|Expr]For[Path|Expr] which are determined
// statically, functions may be variable, so GetFuncNodeFor[Path|Expr]
Expand Down Expand Up @@ -1942,6 +1951,113 @@ func (sb *StaticBlock) GetLocalIndex(n Name) (uint16, bool) {
return 0, false
}

func (sb *StaticBlock) FindNameMaybeLoopvar(store Store, n Name) (loopvar, found bool) {
// fmt.Println("FindNameSkipPredefined, n: ", n)
if n == blankIdentifier {
return false, false
}
// Check local.
gen := 1
// also search with .loopvar_, this make sure `i` also
// get a correct path.
if _, loopvar, found = sb.GetLocalIndexMaybeLoopvar(n); found {
// fmt.Println("===loopVar: ", loopvar)
// found a NameExpr with type NameExprTypeLoopVarDefine
return
}
// Check ancestors.
gen++
bp := sb.GetParentNode(store)
for bp != nil {
if _, loopvar, found = bp.GetStaticBlock().GetLocalIndexMaybeLoopvar(n); found {
// found a NameExpr with type NameExprTypeLoopVarDefine
return loopvar, found
} else {
bp = bp.GetParentNode(store)
gen++
if 0xff < gen {
panic("value path depth overflow")
}
}
}
return
}

func (sb *StaticBlock) GetLocalIndexMaybeLoopvar(n Name) (uint16, bool, bool) {
// fmt.Println("===GetLocalIndexSkipPredefined, sb: ", sb.Block)
// fmt.Println("===GetLocalIndexSkipPredefined, n: ", n)
// if loopvar is found.
var loopvar bool

// firstly search general TypeDefine names,
// it potentially overrides the loopvar.
for i, name := range sb.Names {
if name == n {
if debug {
nt := reflect.TypeOf(sb.Source).String()
debug.Printf("StaticBlock(%p %v).GetLocalIndex(%s) = %v, %v\n",
sb, nt, n, i, name)
}
// skip predefined name
t := sb.Types[i]
if t != nil {
return uint16(i), loopvar, true
}
// else going on search loopvar
}
}

// if not found above, looking for loopvar.
n2 := Name(fmt.Sprintf(".loopvar_%s", n))
// fmt.Println("===n2: ", n2)
for i, name := range sb.Names {
// println("===search loopvar")
if name == n2 {
if debug {
nt := reflect.TypeOf(sb.Source).String()
debug.Printf("StaticBlock(%p %v).GetLocalIndex(%s) = %v, %v\n",
sb, nt, n, i, name)
}

loopvar = true

// XXX, skip predefine name, why?
t := sb.Types[i]
if t == nil {
return 0, loopvar, false
}
return uint16(i), loopvar, true
}
}
if debug {
nt := reflect.TypeOf(sb.Source).String()
debug.Printf("StaticBlock(%p %v).GetLocalIndex(%s) = undefined\n",
sb, nt, n)
}
return 0, loopvar, false
}

func processLoopVar(last BlockNode, nx *NameExpr) {
// fmt.Println("===renameLoopVar, nx: ", nx, nx.Type)
if nx.Name == blankIdentifier {
return
}

if nx.Type == NameExprTypeNormal {
// handle loopvar stuff
loopvar, found := last.FindNameMaybeLoopvar(nil, nx.Name)
if found && loopvar {
// fmt.Println("---found loopvar use, nx: ", nx)
nx.Type = NameExprTypeLoopVarUse
// XXX, necessary?
nx.Name = Name(fmt.Sprintf(".loopvar_%s", nx.Name))
// fmt.Println("===after rename, nx: ", nx)
} else {
// fmt.Println("Not loopvar, nx: ", nx, nx.Type)
}
}
}

// Implemented BlockNode.
// This method is too slow for runtime, but it is used during preprocessing to
// compute types. If ignoreReserved, skips over names that are only reserved
Expand Down
8 changes: 8 additions & 0 deletions gnovm/pkg/gnolang/nodes_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,18 @@ func (x NameExpr) String() string {
return fmt.Sprintf("%s<%s>", x.Name, x.Path.String())
case NameExprTypeDefine:
return fmt.Sprintf("%s<!%s>", x.Name, x.Path.String())
case NameExprTypeLoopVarDefine:
return fmt.Sprintf("%s<!@%s>", x.Name, x.Path.String())
case NameExprTypeHeapDefine:
return fmt.Sprintf("%s<!~%s>", x.Name, x.Path.String())
case NameExprTypeLoopVarHeapDefine:
return fmt.Sprintf("%s<@!~%s>", x.Name, x.Path.String())
case NameExprTypeHeapUse:
return fmt.Sprintf("%s<~%s>", x.Name, x.Path.String())
case NameExprTypeLoopVarUse:
return fmt.Sprintf("%s<*%s>", x.Name, x.Path.String())
case NameExprTypeLoopVarHeapUse:
return fmt.Sprintf("%s<*~%s>", x.Name, x.Path.String())
case NameExprTypeHeapClosure:
return fmt.Sprintf("%s<()~%s>", x.Name, x.Path.String())
default:
Expand Down
1 change: 1 addition & 0 deletions gnovm/pkg/gnolang/op_eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ func (m *Machine) doOpEval() {
// TODO: understand this better.
if nx, ok := x.(*NameExpr); ok {
m.PopExpr()
// fmt.Println("---OpEval, nx: ", nx)
if nx.Path.Depth == 0 {
// Name is in uverse (global).
gv := Uverse().GetBlock(nil).GetPointerTo(nil, nx.Path)
Expand Down
2 changes: 2 additions & 0 deletions gnovm/pkg/gnolang/op_exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ EXEC_SWITCH:
if debug {
debug.Printf("EXEC: %v\n", s)
}
// fmt.Printf("==========================EXEC: %v\n", s)

switch cs := s.(type) {
case *AssignStmt:
switch cs.Op {
Expand Down
Loading
Loading