Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: named and unnamed type assignment 3 of 3 #2367

Merged
merged 19 commits into from
Jul 19, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
28 changes: 28 additions & 0 deletions gnovm/pkg/gnolang/nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,10 @@
return ss
}

func (ss *Body) SetBody(nb Body) {
*ss = nb

Check warning on line 673 in gnovm/pkg/gnolang/nodes.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/nodes.go#L672-L673

Added lines #L672 - L673 were not covered by tests
}

func (ss Body) GetLabeledStmt(label Name) (stmt Stmt, idx int) {
for idx, stmt = range ss {
if label == stmt.GetLabel() {
Expand Down Expand Up @@ -1363,6 +1367,13 @@
panic("PackageNode.PrepareNewValues() package mismatch")
}
}
// the FuncValue Body maybe be altered during the preprocessing.
piux2 marked this conversation as resolved.
Show resolved Hide resolved
// We need to update body field from the source in the FuncValue accordingly.
for _, tv := range x.Values {
if fv, ok := tv.V.(*FuncValue); ok {
fv.UpdateBodyFromSource()
deelawn marked this conversation as resolved.
Show resolved Hide resolved
piux2 marked this conversation as resolved.
Show resolved Hide resolved
}
}
pvl := len(block.Values)
pnl := len(x.Values)
// copy new top-level defined values/types.
Expand Down Expand Up @@ -1468,6 +1479,7 @@
Define(Name, TypedValue)
Define2(bool, Name, Type, TypedValue)
GetBody() Body
SetBody(Body)
}

// ----------------------------------------
Expand Down Expand Up @@ -1857,18 +1869,34 @@
panic("IfStmt has no body (but .Then and .Else do)")
}

func (x *IfStmt) SetBody(b Body) {
panic("IfStmt has no body (but .Then and .Else do)")

Check warning on line 1873 in gnovm/pkg/gnolang/nodes.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/nodes.go#L1872-L1873

Added lines #L1872 - L1873 were not covered by tests
}

func (x *SwitchStmt) GetBody() Body {
panic("SwitchStmt has no body (but its cases do)")
}

func (x *SwitchStmt) SetBody(b Body) {
panic("SwitchStmt has no body (but its cases do)")

Check warning on line 1881 in gnovm/pkg/gnolang/nodes.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/nodes.go#L1880-L1881

Added lines #L1880 - L1881 were not covered by tests
}

func (x *FileNode) GetBody() Body {
panic("FileNode has no body (but it does have .Decls)")
}

func (x *FileNode) SetBody(b Body) {
panic("FileNode has no body (but it does have .Decls)")

Check warning on line 1889 in gnovm/pkg/gnolang/nodes.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/nodes.go#L1888-L1889

Added lines #L1888 - L1889 were not covered by tests
}

func (x *PackageNode) GetBody() Body {
panic("PackageNode has no body")
}

func (x *PackageNode) SetBody(b Body) {
panic("PackageNode has no body")

Check warning on line 1897 in gnovm/pkg/gnolang/nodes.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/nodes.go#L1896-L1897

Added lines #L1896 - L1897 were not covered by tests
}

// ----------------------------------------
// Value Path

Expand Down
73 changes: 73 additions & 0 deletions gnovm/pkg/gnolang/preprocess.go
Original file line number Diff line number Diff line change
Expand Up @@ -1678,6 +1678,79 @@
"%d variables but %s returns %d values",
len(n.Lhs), cx.Func.String(), len(cft.Results)))
}

// check if we we need to decompose for named typed conversion in the function return results
decompose := false
piux2 marked this conversation as resolved.
Show resolved Hide resolved

for i, rhsType := range cft.Results {
lt := evalStaticTypeOf(store, last, n.Lhs[i])
if lt != nil && isNamedConversion(rhsType.Type, lt) {
decompose = true
break

Check warning on line 1689 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1688-L1689

Added lines #L1688 - L1689 were not covered by tests
}
}
if decompose == true {
piux2 marked this conversation as resolved.
Show resolved Hide resolved
// only enter this section if cft.Results to be converted to Lhs type for named type conversion.
// decompose a,b = x()
// .tmp1, .tmp2 := x() assignment statemet expression (Op=DEFINE)
piux2 marked this conversation as resolved.
Show resolved Hide resolved
// a,b = .tmp1, .tmp2 assignment statemet expression ( Op=ASSIGN )
piux2 marked this conversation as resolved.
Show resolved Hide resolved
// add the new statement to last.Body

// step1:
// create a hidden var with leading . (dot) the curBodyLen increase every time when there is an decompostion
piux2 marked this conversation as resolved.
Show resolved Hide resolved
// because there could be multiple decomposition happens
// we use both stmt index and resturn result number to differentiate the .tmp variables created in each assignment decompostion
piux2 marked this conversation as resolved.
Show resolved Hide resolved
// ex. .tmp_3_2: this variabl is created as the 3rd statement in the block, the 2nd parameter returned from x(),
piux2 marked this conversation as resolved.
Show resolved Hide resolved
// create .tmp_1_1, .tmp_1_2 .... based on number of result from x()
var tmpExprs Exprs
piux2 marked this conversation as resolved.
Show resolved Hide resolved
for i := range cft.Results {
rn := fmt.Sprintf(".tmp_%d_%d", index, i)
tmpExprs = append(tmpExprs, Nx(rn))

Check warning on line 1708 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1705-L1708

Added lines #L1705 - L1708 were not covered by tests
}
// step2:
// .tmp1, .tmp2 := x()
dsx := &AssignStmt{
Lhs: tmpExprs,
Op: DEFINE,
Rhs: n.Rhs,

Check warning on line 1715 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1712-L1715

Added lines #L1712 - L1715 were not covered by tests
}
dsx.SetLine(n.Line)
dsx = Preprocess(store, last, dsx).(*AssignStmt)

Check warning on line 1718 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1717-L1718

Added lines #L1717 - L1718 were not covered by tests

// step3:

// a,b = .tmp1, .tmp2
// assign stmt expression
// the right hand side will be converted to call expr for nameed/unnamed covnerstion
piux2 marked this conversation as resolved.
Show resolved Hide resolved
// we make a copy of tmpExrs to prevent dsx.Lhs in the preview statement changing by the side effect
piux2 marked this conversation as resolved.
Show resolved Hide resolved
// when asx.Rhs is converted to const call expr during the preprocess of the next statement

asx := &AssignStmt{
Lhs: n.Lhs,
Op: ASSIGN,
Rhs: copyExprs(tmpExprs),

Check warning on line 1731 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1728-L1731

Added lines #L1728 - L1731 were not covered by tests
}
asx.SetLine(n.Line)
asx = Preprocess(store, last, asx).(*AssignStmt)

Check warning on line 1734 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1733-L1734

Added lines #L1733 - L1734 were not covered by tests

// step4:
// replace the orignal stmt with two new stmts
piux2 marked this conversation as resolved.
Show resolved Hide resolved
body := last.GetBody()

Check warning on line 1738 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1738

Added line #L1738 was not covered by tests
// we need to do an in-place replacement while leaving the current node
n.Attributes = dsx.Attributes
n.Lhs = dsx.Lhs
n.Op = dsx.Op
n.Rhs = dsx.Rhs

Check warning on line 1743 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1740-L1743

Added lines #L1740 - L1743 were not covered by tests

// insert a assignment statement a,b = .tmp1,.tmp2 AFTER the current statement in the last.Body.
body = append(body[:index+1], append(Body{asx}, body[index+1:]...)...)
last.SetBody(body)

Check warning on line 1747 in gnovm/pkg/gnolang/preprocess.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/preprocess.go#L1746-L1747

Added lines #L1746 - L1747 were not covered by tests
} // end of the decomposition

// Last step: we need to insert the statements to FuncValue.body of PackageNopde.Values[i].V
// updating FuncValue.body=FuncValue.Source.Body in updates := pn.PrepareNewValues(pv) during preprocess.
// we updated FuncValue from source.

case *TypeAssertExpr:
// Type-assert case: a, ok := x.(type)
if len(n.Lhs) != 2 {
Expand Down
27 changes: 18 additions & 9 deletions gnovm/pkg/gnolang/transcribe.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@
} else {
cnn = cnn2.(*FuncLitExpr)
}
for idx := range cnn.Body {
// iterate over Body; its length can change if a statement is decomposed.
for idx := 0; idx < len(cnn.Body); idx++ {
cnn.Body[idx] = transcribe(t, nns, TRANS_FUNCLIT_BODY, idx, cnn.Body[idx], &c).(Stmt)
if isBreak(c) {
break
Expand Down Expand Up @@ -383,7 +384,8 @@
} else {
cnn = cnn2.(*BlockStmt)
}
for idx := range cnn.Body {
// iterate over Body; its length can change if a statement is decomposed.
for idx := 0; idx < len(cnn.Body); idx++ {
cnn.Body[idx] = transcribe(t, nns, TRANS_BLOCK_BODY, idx, cnn.Body[idx], &c).(Stmt)
if isBreak(c) {
break
Expand All @@ -393,7 +395,8 @@
}
case *BranchStmt:
case *DeclStmt:
for idx := range cnn.Body {
// iterate over Body; its length can change if a statement is decomposed.
for idx := 0; idx < len(cnn.Body); idx++ {
cnn.Body[idx] = transcribe(t, nns, TRANS_DECL_BODY, idx, cnn.Body[idx], &c).(SimpleDeclStmt)
if isBreak(c) {
break
Expand Down Expand Up @@ -438,7 +441,8 @@
return
}
}
for idx := range cnn.Body {
// iterate over Body; its length can change if a statement is decomposed.
for idx := 0; idx < len(cnn.Body); idx++ {
cnn.Body[idx] = transcribe(t, nns, TRANS_FOR_BODY, idx, cnn.Body[idx], &c).(Stmt)
if isBreak(c) {
break
Expand Down Expand Up @@ -488,7 +492,8 @@
} else {
cnn = cnn2.(*IfCaseStmt)
}
for idx := range cnn.Body {
// iterate over Body; its length can change if a statement is decomposed.
for idx := 0; idx < len(cnn.Body); idx++ {
cnn.Body[idx] = transcribe(t, nns, TRANS_IF_CASE_BODY, idx, cnn.Body[idx], &c).(Stmt)
if isBreak(c) {
break
Expand Down Expand Up @@ -525,7 +530,8 @@
return
}
}
for idx := range cnn.Body {
// iterate over Body; its length can change if a statement is decomposed.
for idx := 0; idx < len(cnn.Body); idx++ {
cnn.Body[idx] = transcribe(t, nns, TRANS_RANGE_BODY, idx, cnn.Body[idx], &c).(Stmt)
if isBreak(c) {
break
Expand Down Expand Up @@ -565,7 +571,8 @@
if isStopOrSkip(nc, c) {
return
}
for idx := range cnn.Body {
// iterate over Body; its length can change if a statement is decomposed.
for idx := 0; idx < len(cnn.Body); idx++ {

Check warning on line 575 in gnovm/pkg/gnolang/transcribe.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/transcribe.go#L575

Added line #L575 was not covered by tests
cnn.Body[idx] = transcribe(t, nns, TRANS_SELECTCASE_BODY, idx, cnn.Body[idx], &c).(Stmt)
if isBreak(c) {
break
Expand Down Expand Up @@ -640,7 +647,8 @@
return
}
}
for idx := range cnn.Body {
// iterate over Body; its length can change if a statement is decomposed.
for idx := 0; idx < len(cnn.Body); idx++ {
cnn.Body[idx] = transcribe(t, nns, TRANS_SWITCHCASE_BODY, idx, cnn.Body[idx], &c).(Stmt)
if isBreak(c) {
break
Expand All @@ -666,7 +674,8 @@
} else {
cnn = cnn2.(*FuncDecl)
}
for idx := range cnn.Body {
// iterate over Body; its length can change if a statement is decomposed.
for idx := 0; idx < len(cnn.Body); idx++ {
cnn.Body[idx] = transcribe(t, nns, TRANS_FUNC_BODY, idx, cnn.Body[idx], &c).(Stmt)
if isBreak(c) {
break
Expand Down
9 changes: 9 additions & 0 deletions gnovm/pkg/gnolang/values.go
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,15 @@
return fv.body
}

func (fv *FuncValue) UpdateBodyFromSource() {
if fv.Source == nil {
panic(fmt.Sprintf(
"Source is missing for FuncValue %s",
piux2 marked this conversation as resolved.
Show resolved Hide resolved
fv.Name))

Check warning on line 602 in gnovm/pkg/gnolang/values.go

View check run for this annotation

Codecov / codecov/patch

gnovm/pkg/gnolang/values.go#L600-L602

Added lines #L600 - L602 were not covered by tests
}
fv.body = fv.Source.GetBody()
}

func (fv *FuncValue) GetSource(store Store) BlockNode {
if rn, ok := fv.Source.(RefNode); ok {
source := store.GetBlockNode(rn.GetLocation())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

type nat []int

func x() (nat, []int) {
a := nat{1}
b := []int{2}
return a, b
}

func main() {
var u1 []int
var n2 nat

_, n2 = x()
// .tmp1, .tmp_2 := x()
// _, u2 = .tmp1, .tmp_2

println(u1)
println(n2)

}

// Output:
// (nil []int)
// (slice[(2 int)] main.nat)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

type nat []int

func x() (nat, []int) {
a := nat{1}
b := []int{2}
return a, b
}

func main() {
var u1 []int
var n2 nat

u1, _ = x()
// .tmp1, .tmp_2 := x()
// u1, _ = .tmp1, .tmp_2

println(u1)
println(n2)

}

// Output:
// slice[(1 int)]
// (nil main.nat)
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package main

type nat []int

func x() (nat, []int) {
a := nat{1}
b := []int{2}
return a, b
}

func main() {
var u1 []int
var n2 nat
// BlockStmt
{ u1, n2 = x()
// .tmp_1, .tmp_2 := x()
// u1, n2 = .tmp_1, .tmp_2

println(u1)
println(n2)
println(u1)
println(n2)
}
}

// Output:
// slice[(1 int)]
// (slice[(2 int)] main.nat)
// slice[(1 int)]
// (slice[(2 int)] main.nat)
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

type nat []int

func x() (nat, []int) {
a := nat{1}
b := []int{2}
return a, b
}

func main() {
var u1 []int
var n2 nat

u1, n2 = x()
// .tmp_1, .tmp_2 := x()
// u1, n2 = .tmp_1, .tmp_2

println(u1)
println(n2)

}

// Output:
// slice[(1 int)]
// (slice[(2 int)] main.nat)
Loading