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
10 changes: 10 additions & 0 deletions gnovm/pkg/gnolang/machine.go
Original file line number Diff line number Diff line change
Expand Up @@ -2247,13 +2247,23 @@ func (m *Machine) IsReadonly(tv *TypedValue) bool {
// and the lx isn't a name (base is a block),
// and the lx isn't a composite lit expr.
func (m *Machine) PopAsPointer2(lx Expr) (pv PointerValue, ro bool) {
fmt.Println("---PopAsPointer2, lx: ", lx)
switch lx := lx.(type) {
case *NameExpr:
switch lx.Type {
case NameExprTypeNormal:
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()
fmt.Println("------lb: ", lb)
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
119 changes: 119 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_REWRITTEN GnoAttribute = "ATTR_REWRITTEN"
)

// 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 @@ -1765,6 +1774,7 @@ func (sb *StaticBlock) GetPathForName(store Store, n Name) ValuePath {
// Check local.
gen := 1
if idx, ok := sb.GetLocalIndex(n); ok {
fmt.Printf("---gen: %d, idx: %d \n", gen, idx)
return NewValuePathBlock(uint8(gen), idx, n)
}
sn := sb.GetSource(store)
Expand Down Expand Up @@ -1942,6 +1952,114 @@ 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)
fmt.Println("---last: ", last)
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 Expand Up @@ -2221,6 +2339,7 @@ func (sb *StaticBlock) Define(n Name, tv TypedValue) {

// Set type to nil, only reserving the name.
func (sb *StaticBlock) Reserve(isConst bool, nx *NameExpr, origin Node, nstype NSType, index int) {
fmt.Println("======Reserve, nx: ", nx)
_, exists := sb.GetLocalIndex(nx.Name)
if !exists {
sb.Define2(isConst, nx.Name, nil, anyValue(nil), NameSource{nx, origin, nstype, index})
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
5 changes: 5 additions & 0 deletions gnovm/pkg/gnolang/op_assign.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package gnolang

import "fmt"

func (m *Machine) doOpDefine() {
s := m.PopStmt().(*AssignStmt)
fmt.Println("---doOpDefine, s: ", s)
// Define each value evaluated for Lhs.
// NOTE: PopValues() returns a slice in
// forward order, not the usual reverse.
Expand All @@ -10,6 +13,8 @@ func (m *Machine) doOpDefine() {
for i := range s.Lhs {
// Get name and value of i'th term.
nx := s.Lhs[i].(*NameExpr)
fmt.Println("---nx: ", nx)
fmt.Println("---rvs[i]: ", rvs[i])
// Finally, define (or assign if loop block).
ptr := lb.GetPointerToMaybeHeapDefine(m.Store, nx)
if m.Stage != StagePre && isUntyped(rvs[i].T) && rvs[i].T.Kind() != BoolKind {
Expand Down
3 changes: 3 additions & 0 deletions gnovm/pkg/gnolang/op_call.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ func (m *Machine) doOpCall() {
pb := fr.Func.GetParent(m.Store)
b := m.Alloc.NewBlock(fs, pb)

fmt.Println("======doOpCall, fv: ", fv)
fmt.Println("======doOpCall, fv.Captures: ", fv.Captures)

// Copy *FuncValue.Captures into block
// NOTE: addHeapCapture in preprocess ensures order.
if len(fv.Captures) != 0 {
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