Skip to content

Commit 6fad501

Browse files
committed
Use pointer parameter for name-binding.
The change prevents unintended ignored return value, and also update the return value to return error instead.
1 parent e684704 commit 6fad501

File tree

8 files changed

+130
-80
lines changed

8 files changed

+130
-80
lines changed

bind.go

+37-38
Original file line numberDiff line numberDiff line change
@@ -3,85 +3,84 @@ package asyncpi
33
// Binding.
44
// This file contains functions for name binding.
55

6-
import (
7-
"log"
8-
)
9-
106
// Bind takes a parsed process p and returned a process with valid binding.
11-
func Bind(p Process) Process {
12-
return bind(p, []Name{})
7+
func Bind(p *Process) error {
8+
var err error
9+
*p, err = bind(*p, []Name{})
10+
if err != nil {
11+
return err
12+
}
13+
return nil
1314
}
1415

15-
func bind(p Process, boundNames []Name) Process {
16-
switch proc := p.(type) {
16+
// bind is a depth-first recursive traversal of a Process p
17+
// with boundNames to bind Names with the same Ident.
18+
func bind(p Process, boundNames []Name) (_ Process, err error) {
19+
switch p := p.(type) {
1720
case *NilProcess:
18-
return proc
21+
return p, nil
1922
case *Repeat:
20-
proc.Proc = bind(proc.Proc, boundNames)
21-
return proc
23+
p.Proc, err = bind(p.Proc, boundNames)
24+
return p, err
2225
case *Par:
23-
for i := range proc.Procs {
24-
bind(proc.Procs[i], boundNames)
26+
for i := range p.Procs {
27+
p.Procs[i], err = bind(p.Procs[i], boundNames)
2528
}
26-
return proc
29+
return p, err
2730
case *Recv:
2831
names := make([]Name, len(boundNames))
2932
for i := range boundNames {
3033
names[i] = boundNames[i]
3134
}
32-
names = append(names, proc.Vars...)
33-
for _, v := range proc.Vars {
34-
for j := 0; j < len(names)-len(proc.Vars); j++ {
35+
names = append(names, p.Vars...)
36+
for _, v := range p.Vars {
37+
for j := 0; j < len(names)-len(p.Vars); j++ {
3538
if IsSameName(v, names[j]) {
36-
log.Println("Warning: rebinding name", v.Ident(), "in recv")
39+
// Rebinding existing bound name.
3740
names = append(names[:j], names[j+1:]...)
3841
}
3942
}
4043
}
4144
var chanBound bool
4245
for i, bn := range names {
43-
if IsSameName(proc.Chan, bn) { // Found bound Chan
44-
proc.Chan = names[i]
46+
if IsSameName(p.Chan, bn) { // Found bound Chan
47+
p.Chan = names[i]
4548
chanBound = true
4649
}
4750
}
4851
if !chanBound {
49-
names = append(names, proc.Chan)
52+
names = append(names, p.Chan)
5053
}
51-
proc.Cont = bind(proc.Cont, names)
52-
return proc
54+
p.Cont, err = bind(p.Cont, names)
55+
return p, err
5356
case *Send:
5457
count := 0
5558
for i, bn := range boundNames {
56-
for j, v := range proc.Vals {
59+
for j, v := range p.Vals {
5760
if IsSameName(v, bn) { // Found bound name.
58-
proc.Vals[j] = boundNames[i]
61+
p.Vals[j] = boundNames[i]
5962
count++
6063
}
6164
}
6265
}
6366
for i, bn := range boundNames {
64-
if IsSameName(proc.Chan, bn) { // Found bound Chan.
65-
proc.Chan = boundNames[i]
67+
if IsSameName(p.Chan, bn) { // Found bound Chan.
68+
p.Chan = boundNames[i]
6669
count++
6770
}
6871
}
69-
if count < len(proc.Vals)+1 {
70-
log.Println("Warning:", len(proc.Vals)+1-count, "names are left unbound")
71-
}
72-
return proc
72+
return p, err
7373
case *Restrict:
74-
names := append(boundNames, proc.Name)
74+
names := append(boundNames, p.Name)
7575
for i := 0; i < len(names)-1; i++ {
76-
if IsSameName(proc.Name, names[i]) {
77-
log.Println("Warning: rebinding name", proc.Name.Ident(), "in restrict")
76+
if IsSameName(p.Name, names[i]) {
77+
// Rebinding existing bound name.
7878
names = append(names[:i], names[i+1:]...)
7979
}
8080
}
81-
proc.Proc = bind(proc.Proc, names)
82-
return proc
81+
p.Proc, err = bind(p.Proc, names)
82+
return p, err
8383
default:
84-
log.Fatal(UnknownProcessTypeError{Caller: "Bind", Proc: p})
84+
return nil, UnknownProcessTypeError{Caller: "bind", Proc: p}
8585
}
86-
return proc
8786
}

bind_test.go

+31-4
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,41 @@ func TestBindIdempotent(t *testing.T) {
1212
t.Fatal(err)
1313
}
1414
p0 := p.Calculi()
15-
bp0 := Bind(p)
16-
p1 := bp0.Calculi()
17-
bp1 := Bind(bp0)
18-
p2 := bp1.Calculi()
15+
if err := Bind(&p); err != nil {
16+
t.Fatal(err)
17+
}
18+
p1 := p.Calculi()
19+
if err := Bind(&p); err != nil {
20+
t.Fatal(err)
21+
}
22+
p2 := p.Calculi()
1923
if p0 != p1 {
2024
t.Errorf("expect Bind to be idempotent but got: \nBefore:\t%s\nAfter:\t%s", p0, p1)
2125
}
2226
if p1 != p2 {
2327
t.Errorf("expect Bind to be idempotent but got: \nBefore:\t%s\nAfter:\t%s", p1, p2)
2428
}
2529
}
30+
31+
func TestBindRebind(t *testing.T) {
32+
const proc = `(new a)(a<> | a().(new a)a().0)`
33+
p, err := Parse(strings.NewReader(proc))
34+
if err != nil {
35+
t.Fatal(err)
36+
}
37+
if err := Bind(&p); err != nil {
38+
t.Fatalf("cannot bind: %v", err)
39+
}
40+
type setter interface {
41+
SetName(string)
42+
}
43+
if s, ok := p.(*Restrict).Name.(setter); ok {
44+
s.SetName("b")
45+
}
46+
if want, got := "b", p.(*Restrict).Proc.(*Par).Procs[1].(*Recv).Chan.Ident(); want != got {
47+
t.Fatalf("expects %s but got %s for %s", want, got, p.(*Restrict).Proc.(*Par).Procs[1].(*Recv).Calculi())
48+
}
49+
if want, got := "a", p.(*Restrict).Proc.(*Par).Procs[1].(*Recv).Cont.(*Restrict).Name.Ident(); want != got {
50+
t.Fatalf("expects %s but got %s for %s", want, got, p.(*Restrict).Proc.(*Par).Procs[1].(*Recv).Cont.(*Restrict).Calculi())
51+
}
52+
}

codegen/golang/gen.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ import (
2626

2727
// Generate writes Go code of the Process to w.
2828
func Generate(p asyncpi.Process, w io.Writer) error {
29-
asyncpi.Bind(p)
29+
if err := asyncpi.Bind(&p); err != nil {
30+
return err
31+
}
3032
types.Infer(p)
3133
if err := types.Unify(p); err != nil {
3234
return err

codegen/golang/gen_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ func ExampleGenerate() {
1616
if err != nil {
1717
fmt.Println(err) // Parse failed
1818
}
19-
p = asyncpi.Bind(p)
19+
if err := asyncpi.Bind(&p); err != nil {
20+
fmt.Println(err)
21+
}
2022
types.Infer(p)
2123
err = types.Unify(p)
2224
if err != nil {

name/uniq_test.go

+17-13
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,19 @@ func TestUpdateName(t *testing.T) {
2727
if err != nil {
2828
t.Fatal(err)
2929
}
30-
bproc := asyncpi.Bind(proc)
31-
if err := MakeNamesUnique(bproc); err != nil {
30+
if err := asyncpi.Bind(&proc); err != nil {
31+
t.Fatal(err)
32+
}
33+
if err := MakeNamesUnique(proc); err != nil {
3234
t.Fatalf("cannot update name: %v", err)
3335
}
34-
if expect, got := 2, len(bproc.FreeNames()); expect != got {
35-
t.Fatalf("Expecting %d unique free names, but got %d: %s", expect, got, bproc.Calculi())
36+
if expect, got := 2, len(proc.FreeNames()); expect != got {
37+
t.Fatalf("Expecting %d unique free names, but got %d: %s", expect, got, proc.Calculi())
3638
}
37-
if expect, got := 0, len(bproc.FreeVars()); expect != got {
38-
t.Fatalf("Expecting %d unique free vars, but got %d: %s", expect, got, bproc.Calculi())
39+
if expect, got := 0, len(proc.FreeVars()); expect != got {
40+
t.Fatalf("Expecting %d unique free vars, but got %d: %s", expect, got, proc.Calculi())
3941
}
40-
t.Logf("%s has unique names %q", bproc.Calculi(), bproc.FreeNames())
42+
t.Logf("%s has unique names %q", proc.Calculi(), proc.FreeNames())
4143
}
4244

4345
func TestUpdateNamePar(t *testing.T) {
@@ -46,14 +48,16 @@ func TestUpdateNamePar(t *testing.T) {
4648
if err != nil {
4749
t.Fatal(err)
4850
}
49-
bproc := asyncpi.Bind(proc)
50-
if err := MakeNamesUnique(bproc); err != nil {
51+
if err := asyncpi.Bind(&proc); err != nil {
52+
t.Fatal(err)
53+
}
54+
if err := MakeNamesUnique(proc); err != nil {
5155
t.Fatalf("cannot update name: %v", err)
5256
}
53-
if expect, got := 6, len(bproc.FreeNames()); expect != got {
54-
t.Fatalf("Expecting %d unique free names, but got %d: %s", expect, got, bproc.Calculi())
57+
if expect, got := 6, len(proc.FreeNames()); expect != got {
58+
t.Fatalf("Expecting %d unique free names, but got %d: %s", expect, got, proc.Calculi())
5559
}
56-
if expect, got := 0, len(bproc.FreeVars()); expect != got {
57-
t.Fatalf("Expecting %d unique free vars, but got %d: %s", expect, got, bproc.Calculi())
60+
if expect, got := 0, len(proc.FreeVars()); expect != got {
61+
t.Fatalf("Expecting %d unique free vars, but got %d: %s", expect, got, proc.Calculi())
5862
}
5963
}

reduce.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,9 @@ func SimplifyBySC(p Process) (Process, error) {
154154
// Such that the unused Names and the Restrict that
155155
// introduced them can be removed.
156156
func findUnusedRestrict(p Process) (unused []Name, err error) {
157-
p = Bind(p)
157+
if err := Bind(&p); err != nil {
158+
return nil, err
159+
}
158160
type rescount struct {
159161
ResName Name
160162
Count int

types/infer.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ func processAttachType(p asyncpi.Process) {
5656

5757
func Infer(p asyncpi.Process) error {
5858
processAttachType(p)
59-
asyncpi.Bind(p)
59+
if err := asyncpi.Bind(&p); err != nil {
60+
return err
61+
}
6062
return processInferType(p)
6163
}
6264

0 commit comments

Comments
 (0)