├── algorithm ├── pair.go ├── util.go ├── cache │ ├── fsClock.go │ └── fsPLRU.go ├── set.go ├── bitmap.go ├── queue.go ├── stack.go └── concurrent │ ├── hasharray.go │ ├── stack.go │ └── hashmap.go ├── TyPiCal samples ├── selFixed.pi ├── fanin-select-by-if.pi ├── sel.pi ├── philo.pi ├── deadlock.pi ├── primesieve.pi └── threadOrder.pi ├── example ├── ex1 │ └── main.go ├── forIf │ └── main.go ├── if2 │ └── main.go ├── closeSample │ └── main.go ├── selectEx │ └── main.go ├── simple │ └── main.go ├── simple3 │ └── main.go ├── strangeloop │ └── main.go ├── loopex │ └── main.go ├── ifex │ └── main.go ├── foobar │ └── footest.go ├── mail2 │ └── main.go ├── simple2 │ └── main.go ├── newsreader │ └── main.go └── phil │ └── main.go ├── test ├── 2 │ └── test2.go ├── test.go_ ├── test1.go ├── simple.go └── simple.go_ ├── .gitignore ├── benchmarks ├── selFixed │ └── main.go ├── philo │ └── main.go ├── primesieveSingle │ └── main.go ├── deadlock │ └── main.go ├── FanIn │ └── main.go ├── sel │ └── main.go ├── primesieve │ └── main.go └── results.txt ├── main.go ├── README.md ├── oracleAPI └── oracler.go ├── FEBuilder └── febuilder.go ├── types └── types.go ├── simplifier └── simplifiy.go └── validation └── validation.go /algorithm/pair.go: -------------------------------------------------------------------------------- 1 | package algorithm 2 | 3 | type Pair struct { 4 | First interface{} 5 | Second interface{} 6 | } 7 | 8 | -------------------------------------------------------------------------------- /TyPiCal samples/selFixed.pi: -------------------------------------------------------------------------------- 1 | /*** TyPiCal: unsafe sends, but indirect modeling of select ***/ 2 | new x in 3 | new y in 4 | x!true | y!false | 5 | (if true then x?z else y?z ) 6 | -------------------------------------------------------------------------------- /example/ex1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func foo(x chan int) { 4 | x <- 42 5 | <-x 6 | } 7 | 8 | func main() { 9 | x := make(chan int) 10 | go foo(x) 11 | 12 | x <- 42 13 | <-x 14 | } 15 | -------------------------------------------------------------------------------- /example/forIf/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | x := make(chan int) 5 | 6 | for { 7 | if true { 8 | x <- 42 9 | } else { 10 | <-x 11 | } 12 | 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /example/if2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | func foo(x chan int) { 5 | x <- 42 6 | } 7 | 8 | func main() { 9 | x := make(chan int) 10 | 11 | go foo(x) 12 | 13 | if 5 < 0 { 14 | <-x 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /example/closeSample/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func foo(x chan int) { 4 | <-x 5 | <-x 6 | } 7 | 8 | func main() { 9 | x := make(chan int) 10 | go foo(x) 11 | x <- 42 12 | if 5 > 8 { 13 | close(x) 14 | } 15 | 16 | //x <- 42 17 | } 18 | -------------------------------------------------------------------------------- /test/test.go_: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func foo(a, b chan int) { 4 | b <- 42 5 | <-a 6 | } 7 | 8 | func main() { 9 | a := make(chan int) 10 | b := make(chan int) 11 | 12 | go foo(a,b) 13 | 14 | a <- 42 15 | <-b 16 | } 17 | -------------------------------------------------------------------------------- /TyPiCal samples/fanin-select-by-if.pi: -------------------------------------------------------------------------------- 1 | /*** TyPiCal: unsafe send operation, if select is modeled by if ***/ 2 | new input1 in 3 | new input2 in 4 | new out in 5 | * (input1!42) 6 | | * (input2!42) 7 | | * (if true then input1?z.out!z else input2?z.out!z) 8 | | * (out?drop) 9 | -------------------------------------------------------------------------------- /example/selectEx/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func foo(x,y chan int) { 4 | select { 5 | case <-x: 6 | case <-y: 7 | } 8 | } 9 | 10 | func main() { 11 | x := make(chan int) 12 | y := make(chan int) 13 | 14 | go foo(x,y) 15 | 16 | x <- 42 17 | 18 | } 19 | -------------------------------------------------------------------------------- /example/simple/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | func first(x chan int) { 5 | x <- 43 6 | } 7 | 8 | func main() { 9 | x := make(chan int) 10 | go first(x) 11 | 12 | if 5 > 0 { 13 | <-x 14 | } else { 15 | x <- 42 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/simple3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func bar(y chan int) { 4 | y <- 42 5 | } 6 | 7 | func foo() { 8 | y:= make(chan int) 9 | go bar(y) 10 | <-y 11 | } 12 | 13 | func main() { 14 | x := make(chan int) 15 | go foo() 16 | x <- 42 17 | <-x 18 | } 19 | -------------------------------------------------------------------------------- /example/strangeloop/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func a(x,y chan int) { 4 | for { 5 | x <- 42 6 | <-y 7 | } 8 | } 9 | 10 | func main() { 11 | x := make(chan int) 12 | y := make(chan int) 13 | go a(x,y) 14 | <-x 15 | <-x 16 | <-x 17 | y <- 42 18 | } 19 | -------------------------------------------------------------------------------- /TyPiCal samples/sel.pi: -------------------------------------------------------------------------------- 1 | /*** TyPiCal: unsafe ***/ 2 | new x in 3 | new y in 4 | x!true /*** provide1 ***/ 5 | | y!false /*** provide2 ***/ 6 | | new z1 in 7 | x?v.z1!v /*** collect1 ***/ 8 | | y?v.z1!v /*** collect2 ***/ 9 | | z1?dummy. 10 | new z2 in 11 | x?v.z2!v | y?v.x2!v | z2?dummy 12 | -------------------------------------------------------------------------------- /TyPiCal samples/philo.pi: -------------------------------------------------------------------------------- 1 | /*** TyPiCal: unsafe, but this is a very crude model of the dining philosophers ***/ 2 | new forks in 3 | forks!1 /*** Give1 ***/ 4 | | forks!1 /*** Give2 ***/ 5 | | * (forks?f1. forks?f2. forks!f1. forks!f2) /*** phil ***/ 6 | | * (forks?f1. forks?f2. forks!f1. forks!f2) /*** main ***/ 7 | -------------------------------------------------------------------------------- /example/loopex/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func loop(x,y chan int) { 4 | for i := 0; i < 3; i++ { 5 | x <- 42 6 | } 7 | <-y 8 | } 9 | 10 | func main() { 11 | x := make(chan int) 12 | y := make(chan int) 13 | go loop(x,y) 14 | 15 | <-x 16 | <-x 17 | <-x 18 | y <- 42 19 | } 20 | -------------------------------------------------------------------------------- /TyPiCal samples/deadlock.pi: -------------------------------------------------------------------------------- 1 | /*** TyPiCal: unsafe, but doesn't figure out that the first done?x1 is successful ***/ 2 | new ch in 3 | new done in 4 | ch!42 /*** Send ***/ 5 | | ch?val.done!val /*** Recv1 ***/ 6 | | ch?val.done!val /*** Recv2 ***/ 7 | | *(new junk in junk!1 | junk?one) /*** Work ***/ 8 | | done?x1.done?x2 /*** Main ***/ 9 | 10 | -------------------------------------------------------------------------------- /example/ifex/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func A(x,y chan int) { 4 | for { 5 | x <- 42 6 | <-y 7 | } 8 | } 9 | 10 | func main() { 11 | x := make(chan int) 12 | y := make(chan int) 13 | 14 | go A(x,y) 15 | 16 | for { 17 | <-x 18 | if true { 19 | y <- 42 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /example/foobar/footest.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func foo(x, y chan int) { 4 | <-x 5 | y <- 42 6 | } 7 | 8 | func main() { 9 | x := make(chan int) 10 | y := make(chan int) 11 | 12 | go foo(x,y) 13 | 14 | if true { 15 | x <- 42 16 | } else { 17 | <-y 18 | } 19 | 20 | for { 21 | x <- 42 22 | } 23 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /example/mail2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | func sel(x, y chan bool) { 5 | z := make(chan bool) 6 | go func() { z<- (<-x) }() 7 | go func() { z<- (<-y) }() 8 | <-z 9 | } 10 | 11 | 12 | func main() { 13 | x := make(chan bool) 14 | y := make(chan bool) 15 | go func() { x <- true }() 16 | go func() { y <- false }() 17 | sel(x,y) 18 | sel(x,y) 19 | } -------------------------------------------------------------------------------- /test/2/test2.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func A(x,y chan int) { 4 | for { 5 | x <- 4 6 | <-y 7 | } 8 | } 9 | 10 | func B(x,y chan int) { 11 | for { 12 | k := <-x 13 | if k > 5 { 14 | y <- 4 15 | } 16 | } 17 | } 18 | 19 | func main() { 20 | a := make(chan int) 21 | b := make(chan int) 22 | 23 | go A(a,b) 24 | 25 | B(a,b) 26 | } -------------------------------------------------------------------------------- /example/simple2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func a(x,y chan int) { 4 | y <- 42 5 | <-x 6 | } 7 | 8 | func b(x,y chan int) { 9 | <-y 10 | x <- 42 11 | } 12 | 13 | func c(x chan int) { 14 | x <- 42 15 | } 16 | 17 | func d(x chan int) { 18 | <-x 19 | } 20 | 21 | func main() { 22 | x := make(chan int) 23 | y := make(chan int) 24 | 25 | go a(x,y) 26 | go b(x,y) 27 | go c(x) 28 | go d(x) 29 | 30 | x <- 42 31 | <-x 32 | } 33 | -------------------------------------------------------------------------------- /algorithm/util.go: -------------------------------------------------------------------------------- 1 | package algorithm 2 | 3 | func Contains(x interface{}, slice interface{}) bool { 4 | switch x.(type) { 5 | case uint64: 6 | return containsuint64(x.(uint64), slice.([]uint64)) 7 | } 8 | return false 9 | } 10 | 11 | func containsuint64(x uint64, slice []uint64) bool { 12 | for i := range slice { 13 | if x == slice[i] { 14 | return true 15 | } 16 | } 17 | return false 18 | } -------------------------------------------------------------------------------- /TyPiCal samples/primesieve.pi: -------------------------------------------------------------------------------- 1 | /*** TyPiCal: cannot analyze within resource limit ***/ 2 | /*** incomplete model, less than primesieveSingle ***/ 3 | new ch in 4 | (new generate in generate!2 | *(generate?i.ch!i.generate!(i+1))) 5 | | 6 | new filter1 in new filter2 in new filter3 in 7 | filter1?inp. filter2?out. filter3?prime. 8 | inp?i. if i % prime != 0 then out!i else (new dev0 in dev0!i | dev0?x) 9 | | ch?prime. new ch1 in filter1!ch. filter2!ch1. filter3!prime 10 | -------------------------------------------------------------------------------- /TyPiCal samples/threadOrder.pi: -------------------------------------------------------------------------------- 1 | /*** TyPiCal: unsafe 2 | 3 | Unlike Ng/Yoshida, the approach by KN properly takes care of 4 | the order among threads. 5 | 6 | Like some of the other examples we have seen, 7 | the debug information provided (by KN) 8 | can be improved. 9 | 10 | For example, KN reports 11 | 12 | new x in 13 | new y in 14 | x!!42. (x?v | y!!3 | y??vv) 15 | 16 | which seems a bit confusing. 17 | 18 | ***/ 19 | 20 | 21 | new x in 22 | new y in 23 | x!42. (x?v | y!3 | y?vv) -------------------------------------------------------------------------------- /benchmarks/selFixed/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func provide1(x chan bool) { 8 | x <- true 9 | } 10 | func provide2(y chan bool) { 11 | y <- false 12 | } 13 | 14 | func main() { 15 | x := make(chan bool) 16 | y := make(chan bool) 17 | go provide1(x) 18 | go provide2(y) 19 | 20 | 21 | select { 22 | case z := <-x: 23 | fmt.Println(z) 24 | case z := <-y: 25 | fmt.Println(z) 26 | } 27 | } -------------------------------------------------------------------------------- /test/test1.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func A(x, z chan int) { 4 | x <- 4 5 | <-z 6 | x <- 5 7 | } 8 | 9 | func B(x, y chan int) { 10 | <-x 11 | <-y 12 | } 13 | 14 | func C(x,y,z chan int) { 15 | <-x 16 | C1(z) 17 | y <-3 18 | } 19 | 20 | func C1(z chan int) { 21 | z <- 4 22 | } 23 | 24 | func main() { 25 | x := make(chan int) 26 | y := make(chan int) 27 | z := make(chan int) 28 | 29 | go A(x,z) 30 | go B(x,y) 31 | C(x,y,z) 32 | } 33 | -------------------------------------------------------------------------------- /benchmarks/philo/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func phil(forks chan int) { 4 | for { 5 | <-forks 6 | <-forks 7 | 8 | forks <- 1 9 | forks <- 1 10 | } 11 | } 12 | 13 | func give1(forks chan int) { 14 | forks <- 1 15 | } 16 | func give2(forks chan int) { 17 | forks <- 1 18 | } 19 | 20 | func main() { 21 | forks := make(chan int) 22 | 23 | go give1(forks) 24 | go give2(forks) 25 | go phil(forks) 26 | 27 | for { 28 | <-forks 29 | <-forks 30 | 31 | forks <- 1 32 | forks <- 1 33 | } 34 | } -------------------------------------------------------------------------------- /benchmarks/primesieveSingle/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func generate(ch chan int) { 4 | for i := 2;;i++ { 5 | ch <- i 6 | } 7 | } 8 | 9 | func filter(in chan int, out chan int, prime int) { 10 | for { 11 | i := <-in 12 | if i % prime != 0 { 13 | out <- i 14 | } 15 | } 16 | } 17 | 18 | func main() { 19 | ch := make(chan int) 20 | 21 | go generate(ch) 22 | 23 | //------ 1 ------ 24 | prime := <-ch 25 | //fmt.Println(prime) 26 | ch1 := make(chan int) 27 | go filter(ch, ch1, prime) 28 | 29 | } 30 | -------------------------------------------------------------------------------- /benchmarks/deadlock/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func Send(ch chan int) { 4 | ch <- 42 5 | } 6 | 7 | func Recv1(ch chan int, done chan int) { 8 | val := <-ch 9 | done <- val 10 | } 11 | 12 | func Recv2(ch chan int, done chan int) { 13 | val := <-ch 14 | done <- val 15 | } 16 | 17 | func Work() { 18 | for { 19 | 20 | } 21 | } 22 | 23 | func main() { 24 | ch := make(chan int) 25 | done := make(chan int) 26 | 27 | go Send(ch) 28 | go Recv1(ch, done) 29 | go Recv2(ch, done) 30 | go Work() 31 | 32 | <-done 33 | <-done 34 | } 35 | -------------------------------------------------------------------------------- /benchmarks/FanIn/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | 5 | func work1(out chan int) { 6 | for { 7 | out <- 42 8 | } 9 | } 10 | func work2(out chan int) { 11 | for { 12 | out <- 42 13 | } 14 | } 15 | 16 | func fanin(input1, input2, out chan int) { 17 | for { 18 | select { 19 | case s := <-input1: 20 | out <- s 21 | case s := <-input2: 22 | out <- s 23 | } 24 | } 25 | } 26 | 27 | func main() { 28 | input1 := make(chan int) 29 | input2 := make(chan int) 30 | out := make(chan int) 31 | go work1(input1) 32 | go work2(input2) 33 | go fanin(input1, input2, out) 34 | for { 35 | <-out 36 | } 37 | } -------------------------------------------------------------------------------- /benchmarks/sel/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func provide1(x chan bool) { 4 | x <- true 5 | } 6 | func provide2(y chan bool) { 7 | y <- false 8 | } 9 | 10 | func collect1(in, out chan bool) { 11 | out <- <-in 12 | } 13 | func collect2(in, out chan bool) { 14 | out <- <-in 15 | } 16 | 17 | func main() { 18 | x := make(chan bool) 19 | y := make(chan bool) 20 | go provide1(x) 21 | go provide2(y) 22 | 23 | 24 | z1 := make(chan bool) 25 | go collect1(x,z1) 26 | go collect2(y,z1) 27 | <-z1 28 | 29 | z2 := make(chan bool) 30 | go collect1(x,z2) 31 | go collect2(y,z2) 32 | <-z2 33 | } -------------------------------------------------------------------------------- /algorithm/cache/fsClock.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | type FsClock struct { 4 | s uint32 5 | c []uint32 6 | p uint32 7 | } 8 | 9 | func NewFsClock(size uint32) *FsClock { 10 | return &FsClock{size, make([]uint32, size), 0} 11 | } 12 | 13 | func (fc * FsClock) Update(idx uint32) { 14 | fc.c[idx]++ 15 | } 16 | 17 | func (fc *FsClock) GetIndex() uint32 { 18 | for { 19 | if fc.c[fc.p] == 0 { 20 | tmp := fc.p 21 | fc.p = (fc.p+1) % uint32(len(fc.c)) 22 | return tmp 23 | } 24 | fc.c[fc.p]-- 25 | fc.p = (fc.p+1) % uint32(len(fc.c)) 26 | } 27 | } -------------------------------------------------------------------------------- /example/newsreader/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func news1(ch chan string) { 4 | ch <- "1" 5 | } 6 | 7 | func news2(ch chan string) { 8 | ch <- "2" 9 | } 10 | 11 | func collecter(a chan string, b chan string) { 12 | a <- <-b 13 | } 14 | 15 | func collecter2(a chan string, b chan string) { 16 | a <- <-b 17 | } 18 | 19 | func collect(n1,n2 chan string) { 20 | ch := make(chan string) 21 | 22 | go collecter(ch, n1) 23 | go collecter2(ch, n2) 24 | 25 | <-ch 26 | //fmt.Println(x) 27 | } 28 | 29 | func main() { 30 | n1 := make(chan string) 31 | n2 := make(chan string) 32 | 33 | go news1(n1) 34 | go news2(n2) 35 | 36 | collect(n1,n2) 37 | // collect(n1,n2) 38 | } 39 | -------------------------------------------------------------------------------- /test/simple.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var a chan int 4 | 5 | func foobar() { 6 | bar() 7 | select { 8 | case <-a: 9 | 10 | case a <- 42: 11 | } 12 | } 13 | 14 | func main() { 15 | a = make(chan int) 16 | go foobar() 17 | foo() 18 | // 19 | b := make(chan int) 20 | // z := <-b 21 | // z++ 22 | <-a 23 | // a <- <-b 24 | // go baz(a) 25 | // baz(b) 26 | if 3 > 5 { 27 | <-b 28 | a <- 42 29 | } else { 30 | <-a 31 | } 32 | } 33 | 34 | 35 | func bar() { 36 | x := <-a 37 | x++ 38 | foo() 39 | } 40 | 41 | func foo() { 42 | b := make(chan int) 43 | <-b 44 | go foo() 45 | } 46 | 47 | func baz(x chan int) { 48 | <-x 49 | } 50 | -------------------------------------------------------------------------------- /test/simple.go_: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | var a chan int 4 | 5 | func foobar() { 6 | bar() 7 | select { 8 | case <-a: 9 | 10 | case a <- 42: 11 | } 12 | } 13 | 14 | func main() { 15 | a = make(chan int) 16 | go foobar() 17 | foo() 18 | // 19 | b := make(chan int) 20 | // z := <-b 21 | // z++ 22 | <-a 23 | // a <- <-b 24 | // go baz(a) 25 | // baz(b) 26 | if 3 > 5 { 27 | <-b 28 | a <- 42 29 | } else { 30 | <-a 31 | } 32 | } 33 | 34 | 35 | func bar() { 36 | x := <-a 37 | x++ 38 | foo() 39 | } 40 | 41 | func foo() { 42 | b := make(chan int) 43 | <-b 44 | go foo() 45 | } 46 | 47 | func baz(x chan int) { 48 | <-x 49 | } 50 | -------------------------------------------------------------------------------- /algorithm/set.go: -------------------------------------------------------------------------------- 1 | package algorithm 2 | 3 | type HashSet struct { 4 | data map[interface{}]struct{} 5 | size uint64 6 | } 7 | 8 | func NewHashSet() *HashSet { 9 | return &HashSet{data: make(map[interface{}]struct{})} 10 | } 11 | 12 | func (s *HashSet) Insert(el interface{}) { 13 | _, ok := s.data[el] 14 | if !ok { 15 | s.data[el] = struct{}{} 16 | } 17 | } 18 | 19 | func (s *HashSet) Clear() { 20 | s.data = make(map[interface{}]struct{}) 21 | } 22 | 23 | func (s *HashSet) Size() uint64 { 24 | return uint64(len(s.data)) 25 | } 26 | 27 | func (s *HashSet) Empty() bool { 28 | return s.size == 0 29 | } 30 | 31 | func (s *HashSet) Iterate() chan interface{} { 32 | ch := make(chan interface{}, len(s.data)) 33 | go func() { 34 | for k := range s.data { 35 | ch <- k 36 | } 37 | close(ch) 38 | }() 39 | return ch 40 | } 41 | -------------------------------------------------------------------------------- /algorithm/bitmap.go: -------------------------------------------------------------------------------- 1 | package algorithm 2 | 3 | type Bitmap struct { 4 | m []uint32 5 | s uint32 6 | } 7 | 8 | func NewBitmap(s uint32) *Bitmap { 9 | return &Bitmap{make([]uint32, s), s} 10 | } 11 | 12 | func (b *Bitmap) Set(idx uint32) { 13 | b.m[idx >> 0x5] |= 1 << (idx & 0x1F) 14 | } 15 | 16 | func (b *Bitmap) Unset(idx uint32) { 17 | b.m[idx >> 0x5] &= ^(1 << (idx & 0x1F)) 18 | } 19 | 20 | func (b *Bitmap) Toggle(idx uint32) { 21 | b.m[idx >> 0x5] %= 1 << (idx & 0x1F) 22 | } 23 | 24 | func (b *Bitmap) Get(idx uint32) bool { 25 | return (b.m[idx >> 0x5] & (1 << (idx & 0x1F))) > 0 26 | } 27 | 28 | func (b *Bitmap) Clear() { 29 | for i := range b.m { 30 | b.m[i] = 0 31 | } 32 | } 33 | 34 | func (b *Bitmap) String() (s string) { 35 | for i := uint32(0); i < b.s*32; i++ { 36 | if b.Get(i) { 37 | s += "1" 38 | } else { 39 | s += "0" 40 | } 41 | } 42 | 43 | return 44 | } -------------------------------------------------------------------------------- /example/phil/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | 4 | 5 | func philo1(forks chan int) { 6 | for { 7 | <-forks 8 | <-forks 9 | forks <- 1 10 | forks <- 1 11 | } 12 | } 13 | // 14 | // func philo2(forks chan int) { 15 | // // for { 16 | // <-forks 17 | // <-forks 18 | // forks <- 1 19 | // forks <- 1 20 | // // } 21 | // } 22 | 23 | func fork1(forks chan int) { 24 | forks <- 1 25 | } 26 | func fork2(forks chan int) { 27 | forks <- 1 28 | } 29 | // func fork3(forks chan int) { 30 | // forks <- 1 31 | // } 32 | 33 | func main() { 34 | forks := make(chan int) 35 | 36 | go fork1(forks) 37 | go fork2(forks) 38 | // go fork3(forks) 39 | 40 | go philo1(forks) 41 | //go philo2(forks) 42 | 43 | for { 44 | <-forks 45 | <-forks 46 | forks <- 1 47 | forks <- 1 48 | } 49 | } -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | 7 | "./simplifier" 8 | //"./types" 9 | "time" 10 | 11 | "./FEBuilder" 12 | "./validation" 13 | ) 14 | 15 | func main() { 16 | 17 | path := flag.String("p", "", "path to code file") 18 | flag.Parse() 19 | 20 | start := time.Now() 21 | s := simplify.New() 22 | parseGraph := s.Parse(*path) 23 | //fmt.Println(parseGraph["main"].AllOps) 24 | //fmt.Println("Parse time:", time.Since(start)) 25 | //start = time.Now() 26 | _, pmap, threads, cmap, rmap := febuilder.BuildExpression(parseGraph) 27 | fmt.Println("CloserMap", cmap) 28 | fmt.Println("ReaderMap", rmap) 29 | // fmt.Println("Expression Build time:", time.Since(start)) 30 | fmt.Println("Threads:", threads) 31 | // fmt.Println(r) 32 | fmt.Println("PartnerMap", pmap) 33 | // start = time.Now() 34 | validation.Run2(threads, pmap, cmap, rmap) 35 | // fmt.Println("Validation time:", time.Since(start)) 36 | 37 | fmt.Println("Complete:", time.Since(start)) 38 | } 39 | -------------------------------------------------------------------------------- /benchmarks/primesieve/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func generate(ch chan int) { 4 | for i := 2;;i++ { 5 | ch <- i 6 | } 7 | } 8 | 9 | func filter(in chan int, out chan int, prime int) { 10 | for { 11 | i := <-in 12 | if i % prime != 0 { 13 | out <- i 14 | } 15 | } 16 | } 17 | func filter2(in chan int, out chan int, prime int) { 18 | for { 19 | i := <-in 20 | if i % prime != 0 { 21 | out <- i 22 | } 23 | } 24 | } 25 | func filter3(in chan int, out chan int, prime int) { 26 | for { 27 | i := <-in 28 | if i % prime != 0 { 29 | out <- i 30 | } 31 | } 32 | } 33 | 34 | func main() { 35 | ch := make(chan int) 36 | 37 | go generate(ch) 38 | 39 | //------ 1 ------ 40 | prime := <-ch 41 | //fmt.Println(prime) 42 | ch1 := make(chan int) 43 | go filter(ch, ch1, prime) 44 | 45 | //------ 2 ------ 46 | prime = <-ch1 47 | //fmt.Println(prime) 48 | ch2 := make(chan int) 49 | go filter2(ch1, ch2, prime) 50 | 51 | //------ 3 ------ 52 | prime = <-ch2 53 | //fmt.Println(prime) 54 | ch3 := make(chan int) 55 | go filter3(ch2, ch3, prime) 56 | 57 | } -------------------------------------------------------------------------------- /algorithm/queue.go: -------------------------------------------------------------------------------- 1 | package algorithm 2 | 3 | import ( 4 | "container/list" 5 | ) 6 | 7 | type Queue struct { 8 | list *list.List 9 | } 10 | 11 | func NewQueue() *Queue { 12 | return &Queue{list:list.New()} 13 | } 14 | 15 | func (q *Queue) Empty() bool { 16 | return q.Size() == 0 17 | } 18 | 19 | func (q *Queue) Size() uint64 { 20 | return (uint64)(q.list.Len()) 21 | } 22 | 23 | func (q *Queue) Front() interface{} { 24 | return q.list.Front().Value 25 | } 26 | 27 | func (q *Queue) Back() interface{} { 28 | return q.list.Back().Value 29 | } 30 | 31 | func (q *Queue) Push_back(e interface{}) { 32 | q.list.PushBack(e) 33 | } 34 | 35 | func (q *Queue) Pop_front() { 36 | q.list.Remove(q.list.Front()) 37 | } 38 | 39 | func (q *Queue) Clear() { 40 | q.list.Init() 41 | } 42 | 43 | func (q *Queue) Iterate() chan interface{} { 44 | ch := make(chan interface{}, q.Size()) 45 | 46 | go func() { 47 | for e:= q.list.Front(); e != nil; e = e.Next() { 48 | ch <- e.Value 49 | } 50 | close(ch) 51 | }() 52 | 53 | return ch 54 | } -------------------------------------------------------------------------------- /algorithm/stack.go: -------------------------------------------------------------------------------- 1 | package algorithm 2 | 3 | type Stack struct { 4 | data []interface{} 5 | currTop int 6 | } 7 | 8 | func NewStack() *Stack { 9 | return &Stack{currTop: -1, data: make([]interface{}, 0)} 10 | } 11 | 12 | func (s *Stack) Peek() interface{} { 13 | if s.currTop > -1 { 14 | return s.data[s.currTop] 15 | } 16 | return nil 17 | } 18 | 19 | func (s *Stack) Pop() { 20 | if s.currTop > -1 { 21 | s.currTop-- 22 | } 23 | } 24 | 25 | func (s *Stack) Push(v interface{}) { 26 | if len(s.data) > s.currTop+1 { 27 | s.currTop++ 28 | s.data[s.currTop] = v 29 | return 30 | } 31 | s.data = append(s.data, v) 32 | s.currTop++ 33 | } 34 | 35 | func (s *Stack) Count() int { 36 | if s.currTop == -1 { 37 | return 0 38 | } 39 | return s.currTop+1 40 | } 41 | 42 | func (s *Stack) Empty() bool { 43 | return s.currTop == -1 44 | } 45 | 46 | func (s *Stack) Iterate() chan interface{} { 47 | ch := make(chan interface{}, s.Count()) 48 | 49 | go func() { 50 | if s.Empty() { 51 | close(ch) 52 | } else { 53 | for i := 0; i < s.Count(); i++ { 54 | ch <- s.data[i] 55 | } 56 | close(ch) 57 | } 58 | }() 59 | return ch 60 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gopherlyzer 2 | 3 | ## Beta Release 4 | 5 | It's the first beta implementation of our analysis described in [Static Trace-Based Deadlock Analysis for 6 | Synchronous Mini-Go](http://www.home.hs-karlsruhe.de/~suma0002/publications/TraceBasedDeadlockAnalysisMiniGo.pdf). 7 | 8 | The current prototype only covers a subset of the Go language. See our examples. 9 | We plan to add support for full recursion, anonymous functions, labels, close for channels etc. in the near future. 10 | 11 | ## Description 12 | 13 | We consider the problem of static deadlock detection for 14 | programs in the Go programming language which make use of synchronous 15 | channel communications. In our analysis, regular expressions extended 16 | with a fork operator capture the communication behavior of a program. 17 | Starting from a simple criterion that characterizes traces of deadlock-free 18 | programs, we develop automata-based methods to check for deadlock- 19 | freedom. The approach is implemented and evaluated with a series of 20 | examples. 21 | 22 | ## How to use 23 | 24 | Configure the Go environment: 25 | 26 | export GOROOT=/usr/local/go 27 | 28 | export GOPATH=`*path_to_workspace*`/bin 29 | 30 | export PATH=$GOROOT/bin:$GOPATH/bin:$PATH 31 | 32 | Install Go Guru: 33 | 34 | go get golang.org/x/tools/cmd/guru 35 | 36 | Running gopherlyzer: 37 | 38 | go run main.go -p benchmarks/philo/main.go 39 | -------------------------------------------------------------------------------- /algorithm/cache/fsPLRU.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | type FsPLRU struct { 4 | treeNodeCount uint32 5 | treeNodeQW uint32 6 | lruTree []uint32 7 | size uint32 8 | } 9 | 10 | func (fsp *FsPLRU) set(index uint32) { 11 | fsp.lruTree[index >> 0x5] |= 1 << (index & 0x1F) 12 | } 13 | 14 | func (fsp *FsPLRU) clear(index uint32) { 15 | fsp.lruTree[index >> 0x5] &= ^(1 << (index & 0x1F)) 16 | } 17 | 18 | func (fsp *FsPLRU) isSet(index uint32) bool { 19 | return (fsp.lruTree[index >> 0x5] & (1 << (index & 0x1F))) > 0 20 | } 21 | 22 | func isPowerOfTwo(n uint32) bool { 23 | return ((n!=0) && !((n & (n-1))>0)) 24 | } 25 | 26 | func NewPLRU(size uint32) *FsPLRU { 27 | if !isPowerOfTwo(size) { 28 | panic("PLRU intialized with wrong size. Must be n^2") 29 | } 30 | 31 | fsp := &FsPLRU{treeNodeCount: (size-1), size:size} 32 | fsp.treeNodeQW = (fsp.treeNodeCount + 31)/ 32 33 | fsp.lruTree = make([]uint32, fsp.treeNodeQW) 34 | return fsp 35 | } 36 | 37 | func (fsp *FsPLRU) Update(index uint32) { 38 | currNode := uint32(0) 39 | currStep := uint32(fsp.size/2) 40 | 41 | for currStep > 0 { 42 | if index < currStep { 43 | //left 44 | fsp.set(currNode) 45 | currNode = 2 * currNode + 1 46 | } else { 47 | fsp.clear(currNode) 48 | currNode = 2 * currNode + 2 49 | index -= currStep 50 | } 51 | currStep /= 2 52 | } 53 | } 54 | 55 | func (fsp *FsPLRU) GetIndex() uint32 { 56 | currNode := uint32(0) 57 | currVictim := uint32(0) 58 | currStep := uint32(fsp.size / 2) 59 | 60 | for currStep > 0 { 61 | if fsp.isSet(currNode) { 62 | //right 63 | currVictim += currStep 64 | currNode = 2 * currNode + 2 65 | } else { 66 | //left 67 | currNode = 2 * currNode + 1 68 | } 69 | currStep /= 2 70 | } 71 | 72 | return currVictim 73 | } -------------------------------------------------------------------------------- /algorithm/concurrent/hasharray.go: -------------------------------------------------------------------------------- 1 | package concurrent 2 | 3 | import ( 4 | "sync/atomic" 5 | ) 6 | 7 | type haelement struct { 8 | Key uint32 9 | Value interface{} 10 | } 11 | 12 | type Hasharray struct { 13 | Elements []haelement 14 | Size uint32 15 | } 16 | 17 | const ( 18 | FNV_prime = 16777619 19 | FNV_offset = 2166136261 20 | ) 21 | func hash(n string) uint32 { 22 | hash := uint32(FNV_offset) 23 | for _, c := range n { 24 | hash = hash ^ uint32(c) 25 | hash = hash * FNV_prime 26 | } 27 | return hash + 1 28 | } 29 | 30 | func NewHasharray(size uint32) Hasharray { 31 | return Hasharray{Elements:make([]haelement, size), Size:size} 32 | } 33 | 34 | func (h *Hasharray) Insert(k string, v interface{}) { 35 | key := hash(k) 36 | var rounds uint32 = 0 37 | 38 | for idx := key;; idx++ { 39 | idx = idx % h.Size 40 | swapped := atomic.CompareAndSwapUint32(&h.Elements[idx].Key, 0, key) 41 | if swapped { //new key? 42 | h.Elements[idx].Value = v 43 | return 44 | } else if atomic.LoadUint32(&h.Elements[idx].Key) == key { //already stored key 45 | panic("tried to change existing key") 46 | h.Elements[idx].Value = v 47 | return 48 | } 49 | 50 | rounds += 1 51 | if rounds >= h.Size { 52 | panic("Hasharray is overfilled") 53 | } 54 | } 55 | } 56 | 57 | func (h *Hasharray) Get(k string) (interface{}, bool) { 58 | key := hash(k) 59 | var rounds uint32 = 0 60 | 61 | for idx := key;; idx++ { 62 | idx = idx % h.Size 63 | probedKey := atomic.LoadUint32(&h.Elements[idx].Key) 64 | 65 | if probedKey == key { 66 | return h.Elements[idx].Value, true 67 | } else if probedKey == 0 { 68 | return 0, false 69 | } 70 | 71 | rounds += 1 72 | if rounds >= h.Size { 73 | return 0, false 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /algorithm/concurrent/stack.go: -------------------------------------------------------------------------------- 1 | package concurrent 2 | 3 | import ( 4 | "sync/atomic" 5 | "unsafe" 6 | ) 7 | 8 | type AtomicStack struct { 9 | head unsafe.Pointer 10 | count uint64 11 | } 12 | 13 | type stackElement struct { 14 | value interface{} 15 | next unsafe.Pointer 16 | } 17 | 18 | func NewAtomicStack() *AtomicStack { 19 | return &AtomicStack{head:nil} 20 | } 21 | 22 | func (s *AtomicStack) Empty() bool { 23 | return (*stackElement)(atomic.LoadPointer(&s.head)) == nil 24 | } 25 | 26 | func (s *AtomicStack) Peek() interface{} { 27 | el := (*stackElement)(atomic.LoadPointer(&s.head)) 28 | if el != nil { 29 | return el.value 30 | } 31 | return nil 32 | } 33 | 34 | func (s *AtomicStack) Pop() { 35 | for { 36 | head := atomic.LoadPointer(&s.head) 37 | 38 | if (*stackElement)(head) != nil { 39 | newHead := (*stackElement)(head).next 40 | if atomic.CompareAndSwapPointer(&s.head, head, newHead) { 41 | atomic.AddUint64(&s.count, ^uint64(0)) 42 | break 43 | } 44 | } else { 45 | return 46 | } 47 | } 48 | } 49 | 50 | func (s *AtomicStack) Push(v interface{}) { 51 | se := &stackElement{value:v} 52 | for { 53 | se.next = atomic.LoadPointer(&s.head) 54 | 55 | if atomic.CompareAndSwapPointer(&s.head, se.next, unsafe.Pointer(se)) { 56 | atomic.AddUint64(&s.count, 1) 57 | break 58 | } 59 | } 60 | } 61 | 62 | func (s *AtomicStack) Count() uint64 { 63 | return atomic.LoadUint64(&s.count) 64 | } 65 | 66 | func (s *AtomicStack) Iterate() chan interface{} { 67 | ch := make(chan interface{}, s.Count()) 68 | 69 | go func() { 70 | if s.Empty() { 71 | close(ch) 72 | } else { 73 | curr := (*stackElement)(atomic.LoadPointer(&s.head)) 74 | for curr != nil { 75 | ch <- curr.value 76 | curr = (*stackElement)(atomic.LoadPointer(&curr.next)) 77 | } 78 | close(ch) 79 | } 80 | }() 81 | return ch 82 | } 83 | -------------------------------------------------------------------------------- /benchmarks/results.txt: -------------------------------------------------------------------------------- 1 | Our tool: 2 | 3 | Deadlock 4 | Threads: [a (b.c) (b.c) (d.d)] 5 | (((Fork(a).Fork((b.c))).(Fork((b.c)).Fork(ε))).(d.d)) 6 | map[b:a a:b d:c c:d] 7 | 7 8 | false d [a (b.c) (b.c) (d.d)] 9 | false abb [ε c (b.c) (d.d)] 10 | false abcdd [ε (b.c) ε d] 11 | false abcdb [ε (b.c) ε d] 12 | Succs: 0 13 | Abort: 0 14 | Stopped: 7 15 | 16 | 20.876427ms 17 | 18 | 19 | FanIn 20 | Threads: [(a)* (b)* (((c.d)+(e.d)))* (f)*] 21 | ((Fork((a)*).Fork((b)*)).(Fork((((c.d)+(e.d)))*).(f)*)) 22 | map[c:a a:c e:b b:e f:d d:f] 23 | 3 24 | false f [(a)* (b)* (((c.d)+(e.d)))* (f)*] 25 | true acdf [(a)* (b)* (((c.d)+(e.d)))* (f)*] 26 | true bedf [(a)* (b)* (((c.d)+(e.d)))* (f)*] 27 | Succs: 2 28 | Abort: 0 29 | Stopped: 1 30 | 31 | 28.812885ms 32 | 33 | 34 | Philo 35 | Threads: [(((a.a).(b.b)))* b b (((a.a).(b.b)))*] 36 | ((Fork((((a.a).(b.b)))*).Fork(b)).(Fork(b).(((a.a).(b.b)))*)) 37 | map[b:a a:b] 38 | 12 39 | false babaabab [((b.b).(((a.a).(b.b)))*) ε ε (((a.a).(b.b)))*] 40 | false abbaa [((a.(b.b)).(((a.a).(b.b)))*) ε ε ((a.(b.b)).(((a.a).(b.b)))*)] 41 | false baaba [((a.(b.b)).(((a.a).(b.b)))*) ε ε ((a.(b.b)).(((a.a).(b.b)))*)] 42 | false ababbaba [(((a.a).(b.b)))* ε ε ((b.b).(((a.a).(b.b)))*)] 43 | Succs: 0 44 | Abort: 0 45 | Stopped: 12 46 | 47 | 30.878619ms 48 | 49 | PrimeSieve 50 | Threads: [((a.c).e) (g)* ((a.(b+ε)))* ((c.(d+ε)))* ((e.(f+ε)))*] 51 | (((Fork(((c.(d+ε)))*).Fork(((e.(f+ε)))*)).(Fork(((a.(b+ε)))*).Fork((g)*))).((a.c).e)) 52 | map[a:g c:b b:c e:d d:e g:a] 53 | 6 54 | false e [((a.c).e) (g)* ((a.(b+ε)))* ((c.(d+ε)))* ((e.(f+ε)))*] 55 | false agga [(c.e) (g)* ((b+ε).((a.(b+ε)))*) ((c.(d+ε)))* ((e.(f+ε)))*] 56 | false gae [((a.c).e) (g)* ((b+ε).((a.(b+ε)))*) ((c.(d+ε)))* ((e.(f+ε)))*] 57 | false c [((a.c).e) (g)* ((a.(b+ε)))* ((c.(d+ε)))* ((e.(f+ε)))*] 58 | false gabcc [((a.c).e) (g)* (ε.((a.(b+ε)))*) ((d+ε).((c.(d+ε)))*) ((e.(f+ε)))*] 59 | false gabcdeag [(c.e) (g)* (ε.((a.(b+ε)))*) (ε.((c.(d+ε)))*) ((f+ε).((e.(f+ε)))*)] 60 | Succs: 0 61 | Abort: 0 62 | Stopped: 6 63 | 64 | 34.292022ms 65 | 66 | PrimeSieveSingle 67 | 2 68 | true ac [((a.(b+ε)))* ε (c)*] 69 | false acac [((b+ε).((a.(b+ε)))*) a (c)*] 70 | Succs: 1 71 | Abort: 0 72 | Stopped: 1 73 | Complete: 13.552372ms 74 | 75 | 76 | Dingo: 77 | 78 | Deadlock 79 | Machine 4: False 80 | Machine 1: False 81 | Machine 3: True //Work 82 | Machine 0: False 83 | Machine 5: False 84 | Machine 2: False 85 | 86 | 155ms 87 | 88 | 89 | FanIn 90 | Machine 3: True 91 | Machine 4: True 92 | Machine 5: True 93 | Machine 2: True 94 | Machine 1: True 95 | Machine 0: True 96 | Machine 6: True 97 | 98 | 107ms 99 | 100 | 101 | Machine 3: True //forkgivers 102 | Machine 2: True 103 | Machine 0: False //chan 104 | Machine 4: False //philo 105 | Machine 1: False //philo 106 | 107 | 480ms 108 | 109 | 110 | Primesieve 111 | Machine 0: False 112 | Machine 8: True // prime <-ch2 113 | Machine 5: False 114 | Machine 6: False 115 | Machine 4: False 116 | Machine 1: False 117 | Machine 2: False 118 | Machine 7: False 119 | Machine 3: False 120 | 121 | 8.339s 122 | 123 | PrimeSieveSingle 124 | 125 | Machine 4: False 126 | Machine 3: False 127 | Machine 2: True // main thread weil er einmal von generate mit sicherheit empfang kann 128 | Machine 0: False 129 | Machine 1: False 130 | 131 | 88ms 132 | -------------------------------------------------------------------------------- /oracleAPI/oracler.go: -------------------------------------------------------------------------------- 1 | package oracler 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | "os/exec" 9 | "strconv" 10 | "strings" 11 | ) 12 | 13 | type OracleAPI struct { 14 | FilePath string 15 | Src string 16 | OraclePath string 17 | RootPath string 18 | } 19 | type PeersMode struct { 20 | Mode string `json:"mode"` 21 | PeerEntries Peers `json:"peers"` 22 | } 23 | type DefinitionMode struct { 24 | Mode string `json:"mode"` 25 | Definition Definition `json:"definition"` 26 | } 27 | 28 | type Definition struct { 29 | ObjPos string `json:"objpos"` 30 | Desc string `json:"desc"` 31 | } 32 | type Peers struct { 33 | Pos string `json:"pos"` 34 | Type string `json:"type"` 35 | Allocs []string `json:"allocs"` 36 | Sends []string `json:"sends"` 37 | Receives []string `json:"receives"` 38 | } 39 | 40 | func New(oraclepath, filepath, rootpath string) *OracleAPI { 41 | data, err := ioutil.ReadFile(filepath) 42 | if err != nil { 43 | panic(err) 44 | } 45 | 46 | return &OracleAPI{filepath, string(data), oraclepath, rootpath} 47 | } 48 | 49 | func (o *OracleAPI) GetPeers(format string, charpos int) PeersMode { 50 | cmd := exec.Command(o.OraclePath, 51 | fmt.Sprintf("-%v", format), fmt.Sprintf("-scope=%s", o.RootPath), 52 | "peers", 53 | fmt.Sprintf("%v:#%v", o.FilePath, charpos)) 54 | 55 | cmd.Stderr = os.Stdout 56 | 57 | out, err := cmd.Output() 58 | 59 | if err != nil { 60 | panic(err) 61 | } 62 | 63 | r := strings.NewReader(string(out)) 64 | 65 | var peers PeersMode 66 | if err := json.NewDecoder(r).Decode(&peers.PeerEntries); err != nil { 67 | panic(err) 68 | } 69 | 70 | return peers 71 | } 72 | 73 | func (o *OracleAPI) LineNColumn(text string) (line, column int64) { 74 | split := strings.Split(text, ":") 75 | correction := 0 76 | 77 | _, err := strconv.ParseInt(split[1], 10, 32) 78 | 79 | if err != nil { 80 | correction++ 81 | } 82 | 83 | l, err := strconv.ParseInt(split[1+correction], 10, 32) 84 | if err != nil { 85 | panic(err) 86 | } 87 | c, err := strconv.ParseInt(split[2+correction], 10, 32) 88 | if err != nil { 89 | panic(err) 90 | } 91 | 92 | return l, c 93 | } 94 | 95 | func (o *OracleAPI) GetOffset(line, column int64) int64 { 96 | currLine := 0 97 | currCol := 0 98 | for i, c := range o.Src { 99 | if int64(currLine) == line-1 && int64(currCol) == column { 100 | return int64(i) 101 | } 102 | 103 | if c == '\n' { 104 | currLine++ 105 | currCol = 0 106 | } else { 107 | currCol++ 108 | } 109 | } 110 | return -1 111 | } 112 | 113 | func (o *OracleAPI) FindDefinition(line int64) int64 { 114 | currLine := 0 115 | currCol := 0 116 | for i, c := range o.Src { 117 | if int64(currLine) == line-1 { 118 | for j := i; j < len(o.Src); j++ { 119 | if o.Src[j] == '=' || o.Src[j] == ':' { 120 | return int64(j) 121 | } 122 | } 123 | return -1 124 | } 125 | 126 | if c == '\n' { 127 | currLine++ 128 | currCol = 0 129 | } else { 130 | currCol++ 131 | } 132 | } 133 | return -1 134 | } 135 | 136 | func (o *OracleAPI) FindVariableName(line int64) string { 137 | 138 | i := o.GetOffset(line, 0) 139 | j := o.FindDefinition(line) 140 | 141 | cmd := exec.Command(o.OraclePath, 142 | "-json", fmt.Sprintf("-scope=%v", o.RootPath), 143 | "definition", 144 | fmt.Sprintf("%v:#%v,#%v", o.FilePath, i, j)) 145 | 146 | cmd.Stderr = os.Stdout 147 | out, err := cmd.Output() 148 | 149 | if err != nil { 150 | panic(err) 151 | } 152 | 153 | r := strings.NewReader(string(out)) 154 | 155 | var def DefinitionMode 156 | if err := json.NewDecoder(r).Decode(&def); err != nil { 157 | panic(err) 158 | } 159 | 160 | return def.Definition.Desc 161 | } 162 | 163 | func (o *OracleAPI) SimplifiedVarDesc(line string) string { 164 | 165 | if strings.Contains(line, ".") { 166 | s1 := strings.Split(line, ".") 167 | s2 := strings.Split(s1[1], " ") 168 | return s2[0] 169 | } 170 | s1 := strings.Split(line, " ") 171 | return s1[1] 172 | 173 | } 174 | -------------------------------------------------------------------------------- /algorithm/concurrent/hashmap.go: -------------------------------------------------------------------------------- 1 | package concurrent 2 | 3 | import ( 4 | "fmt" 5 | "sync" 6 | "sync/atomic" 7 | ) 8 | 9 | type Hashfunction func(interface{}) uint32 10 | 11 | type Hashvector struct { 12 | elements []element 13 | size uint32 14 | count uint32 15 | hashfunc Hashfunction 16 | mtx sync.RWMutex 17 | } 18 | 19 | type element struct { 20 | Key uint32 21 | OuterK interface{} 22 | Value interface{} 23 | } 24 | 25 | func NewHashVector(f Hashfunction) *Hashvector { 26 | return &Hashvector{elements: make([]element, 32), size: 32, hashfunc: f, count: 0} 27 | } 28 | 29 | func (hv *Hashvector) Insert(k interface{}, v interface{}) { 30 | hv.mtx.RLock() 31 | 32 | key := hv.hashfunc(k) 33 | var rounds uint32 = 0 34 | 35 | for idx := key; ; idx++ { 36 | idx = idx % atomic.LoadUint32(&hv.size) 37 | 38 | swapped := atomic.CompareAndSwapUint32(&hv.elements[idx].Key, 0, key) 39 | if swapped { //new key? 40 | hv.elements[idx].Value = v 41 | hv.elements[idx].OuterK = k 42 | atomic.AddUint32(&hv.count, 1) 43 | break 44 | } else if atomic.LoadUint32(&hv.elements[idx].Key) == key { //already stored key 45 | panic("tried to change existing key") 46 | hv.elements[idx].Value = v 47 | break 48 | } 49 | 50 | rounds += 1 51 | if rounds >= atomic.LoadUint32(&hv.size) { 52 | hv.mtx.RUnlock() 53 | hv.resize(atomic.LoadUint32(&hv.size)) 54 | hv.Insert(k, v) 55 | return 56 | } 57 | } 58 | 59 | hv.mtx.RUnlock() 60 | } 61 | 62 | func (hv *Hashvector) resize(oldSize uint32) { 63 | hv.mtx.Lock() 64 | 65 | if atomic.LoadUint32(&hv.size) > oldSize { 66 | hv.mtx.Unlock() 67 | return 68 | } 69 | 70 | nsize := atomic.LoadUint32(&hv.size) * 2 71 | tmp := make([]element, nsize) 72 | 73 | for _, v := range hv.elements { 74 | if v.OuterK != nil { 75 | key := hv.hashfunc(v.OuterK) 76 | var rounds uint32 = 0 77 | 78 | for idx := key; ; idx++ { 79 | idx = idx % nsize 80 | if tmp[idx].Key == 0 { 81 | tmp[idx].Key = key 82 | tmp[idx].Value = v.Value 83 | tmp[idx].OuterK = v.OuterK 84 | break 85 | } 86 | 87 | rounds += 1 88 | if rounds >= nsize { 89 | fmt.Println("rz", rounds, nsize) 90 | panic("Hasharray is overfilled") 91 | } 92 | } 93 | } else { 94 | panic("nil element?") 95 | } 96 | } 97 | hv.elements = tmp 98 | atomic.StoreUint32(&hv.size, nsize) 99 | 100 | hv.mtx.Unlock() 101 | } 102 | 103 | func (hv *Hashvector) Get(k interface{}) (interface{}, bool) { 104 | hv.mtx.RLock() 105 | defer hv.mtx.RUnlock() 106 | 107 | key := hv.hashfunc(k) 108 | var rounds uint32 = 0 109 | 110 | for idx := key; ; idx++ { 111 | idx = idx % hv.size 112 | probedKey := atomic.LoadUint32(&hv.elements[idx].Key) 113 | 114 | if probedKey == key { 115 | if hv.elements[idx].OuterK != nil && hv.elements[idx].Value != nil { 116 | return hv.elements[idx].Value, true 117 | } else { 118 | return nil, false 119 | } 120 | } else if probedKey == 0 { 121 | return nil, false 122 | } 123 | 124 | rounds += 1 125 | if rounds >= hv.size { 126 | return nil, false 127 | } 128 | } 129 | } 130 | 131 | 132 | func (hv *Hashvector) PrintState() { 133 | fmt.Println("size=", hv.size, "count=", hv.count) 134 | 135 | c := 0 136 | for _, v := range hv.elements { 137 | if v.OuterK == nil { 138 | c++ 139 | } 140 | //fmt.Println(v) 141 | } 142 | 143 | fmt.Println("free=", c) 144 | } 145 | 146 | 147 | // func (hv *hashvector) PrintState() { 148 | // fmt.Println("size=", hv.size, "count=", hv.count) 149 | // vptr := (*[]element)(hv.vals) 150 | // c := 0 151 | // for i := uint32(0); i < hv.size; i++ { 152 | // if (*vptr)[i].OuterK == nil { 153 | // c++ 154 | // } 155 | // } 156 | // fmt.Println("free=", c) 157 | // } 158 | // 159 | // func (hv *hashvector) resize() { 160 | // atomic.AddUint32(&hv.cWriter, ^uint32(0)) 161 | // 162 | // if atomic.CompareAndSwapUint32(&hv.resizeV, 0, 1) { 163 | // for atomic.LoadUint32(&hv.cWriter) > 0 { 164 | // } 165 | // 166 | // nsize := atomic.LoadUint32(&hv.size) * 2 167 | // tmp := make([]element, nsize) 168 | // vptr := (*[]element)(hv.vals) 169 | // 170 | // for i := uint32(0); i < hv.size; i++ { 171 | // if (*vptr)[i].OuterK != nil { 172 | // key := hv.hashfunc((*vptr)[i].OuterK) 173 | // var rounds uint32 = 0 174 | // 175 | // for idx := key; ; idx++ { 176 | // idx = idx % nsize 177 | // if tmp[idx].Key == 0 { 178 | // tmp[idx].Key = key 179 | // tmp[idx].Value = (*vptr)[i].Value 180 | // tmp[idx].OuterK = (*vptr)[i].OuterK 181 | // break 182 | // } 183 | // 184 | // rounds += 1 185 | // if rounds >= nsize { 186 | // fmt.Println("rz", rounds, nsize) 187 | // panic("Hasharray is overfilled") 188 | // } 189 | // } 190 | // } 191 | // } 192 | // atomic.StorePointer(&hv.vals, unsafe.Pointer(&tmp)) 193 | // atomic.StoreUint32(&hv.size, nsize) 194 | // atomic.StoreUint32(&hv.resizeV, 0) 195 | // } else { 196 | // for atomic.LoadUint32(&hv.resizeV) == 1 { 197 | // } 198 | // } 199 | // } 200 | // 201 | // func (hv *hashvector) Insert(k interface{}, v interface{}) { 202 | // atomic.AddUint32(&hv.cWriter, 1) 203 | // 204 | // key := hv.hashfunc(k) 205 | // var rounds uint32 = 0 206 | // 207 | // for idx := key; ; idx++ { 208 | // if atomic.LoadUint32(&hv.resizeV) > 0 { 209 | // atomic.AddUint32(&hv.cWriter, ^uint32(0)) 210 | // for atomic.LoadUint32(&hv.resizeV) == 1 { 211 | // } 212 | // hv.Insert(k, v) 213 | // return 214 | // } 215 | // 216 | // idx = idx % atomic.LoadUint32(&hv.size) 217 | // swapped := atomic.CompareAndSwapUint32(&(*(*[]element)(atomic.LoadPointer(&hv.vals)))[idx].Key, 0, key) 218 | // if swapped { //new key? 219 | // (*(*[]element)(atomic.LoadPointer(&hv.vals)))[idx].Value = v 220 | // (*(*[]element)(atomic.LoadPointer(&hv.vals)))[idx].OuterK = k 221 | // atomic.AddUint32(&hv.count, 1) 222 | // break 223 | // } else if atomic.LoadUint32(&(*(*[]element)(atomic.LoadPointer(&hv.vals)))[idx].Key) == key { //already stored key 224 | // panic("tried to change existing key") 225 | // (*(*[]element)(atomic.LoadPointer(&hv.vals)))[idx].Value = v 226 | // break 227 | // } 228 | // 229 | // rounds += 1 230 | // if rounds >= atomic.LoadUint32(&hv.size) { 231 | // hv.resize() 232 | // hv.Insert(k, v) 233 | // return 234 | // } 235 | // } 236 | // 237 | // atomic.AddUint32(&hv.cWriter, ^uint32(0)) 238 | // } 239 | -------------------------------------------------------------------------------- /FEBuilder/febuilder.go: -------------------------------------------------------------------------------- 1 | package febuilder 2 | 3 | import ( 4 | "fmt" 5 | 6 | "../algorithm" 7 | "../simplifier" 8 | "../types" 9 | ) 10 | 11 | type state struct { 12 | alpha rune 13 | signMap map[string]rune 14 | partnerMap map[int]*algorithm.HashSet 15 | closerMap map[types.R][]types.R 16 | ReaderMap map[types.R]int 17 | expressionMap map[string]types.R 18 | parseGraph map[string]simplify.Callgraph2 19 | } 20 | 21 | func BuildExpression(parseGraph map[string]simplify.Callgraph2) (types.R, map[types.R]types.R, []types.R, map[types.R][]types.R, map[types.R]int) { 22 | status := state{'a', make(map[string]rune), make(map[int]*algorithm.HashSet), make(map[types.R][]types.R), 23 | make(map[types.R]int), make(map[string]types.R), parseGraph} 24 | 25 | threads := make([]types.R, 0) 26 | 27 | for k, v := range status.parseGraph { 28 | rs := make([]types.R, 0) 29 | 30 | for _, x := range v.ChanOps { 31 | innerRs := make([]types.R, 0) 32 | 33 | for _, y := range x.Ops { 34 | if y.Type == "If" { 35 | innerRs = append(innerRs, status.handleIf2(y)) 36 | } else if y.Type == "Select" { 37 | //fmt.Println("FEBUILDERINSEL", y) 38 | innerRs = append(innerRs, status.handleSelect(y)) 39 | } else { 40 | innerRs = append(innerRs, status.handleOp(y)...) 41 | } 42 | } 43 | 44 | if x.Type == "If" { 45 | ifBody := status.makeSeqs(innerRs) 46 | if x.Else != nil { 47 | elseRs := make([]types.R, 0) 48 | for _, y := range x.Else { 49 | elseRs = append(elseRs, status.handleOp(y)...) 50 | } 51 | elseBody := status.makeSeqs(elseRs) 52 | innerRs = []types.R{types.Alt{ifBody, elseBody}} 53 | } else { 54 | innerRs = []types.R{types.Alt{ifBody, types.Eps(1)}} 55 | } 56 | } else if x.Type == "For" { 57 | innerRs = []types.R{types.Star{status.makeSeqs(innerRs)}} 58 | } else if x.Type == "Select" { 59 | innerRs = []types.R{status.handleSelect(x)} 60 | } 61 | rs = append(rs, innerRs...) 62 | } 63 | status.expressionMap[k] = status.makeSeqs(rs) 64 | } 65 | 66 | for k, _ := range status.expressionMap { 67 | // if tmp := status.parseGraph[k]; tmp.NrRoots > 0 || k == "main" { 68 | if status.expressionMap[k] != types.Eps(1) { 69 | threads = append(threads, status.expressionMap[k]) 70 | } 71 | 72 | // } 73 | } 74 | 75 | complete := make([]types.R, 0) 76 | for k, v := range status.expressionMap { 77 | if tmp := status.parseGraph[k]; tmp.NrRoots > 0 && k != "main" { 78 | v = types.Fork{v} 79 | status.expressionMap[k] = v 80 | } 81 | if status.expressionMap[k] != types.Eps(1) { 82 | complete = append(complete, status.expressionMap[k]) 83 | } 84 | } 85 | 86 | //sort the expression list so main is the last expression 87 | for i := range complete { 88 | switch complete[i].(type) { 89 | case types.Fork: 90 | default: 91 | if complete[i] != types.Eps(1) { 92 | tmp := complete[i] 93 | complete[i] = complete[len(complete)-1] 94 | complete[len(complete)-1] = tmp 95 | } 96 | } 97 | } 98 | completeFE := status.makeSeqs(complete) 99 | 100 | //build partnermap 101 | pMap := make(map[types.R]types.R) 102 | for _, v := range status.partnerMap { 103 | for j := range v.Iterate() { 104 | for k := range v.Iterate() { 105 | if k.(rune) != j.(rune) { 106 | pMap[types.Sym(k.(rune))] = types.Sym(j.(rune)) 107 | pMap[types.Sym(j.(rune))] = types.Sym(k.(rune)) 108 | } 109 | } 110 | } 111 | } 112 | return completeFE, pMap, threads, status.closerMap, status.ReaderMap 113 | } 114 | 115 | func (s *state) makeSeqs(rs []types.R) types.R { 116 | if len(rs) == 1 { 117 | return rs[0] 118 | } else if len(rs) > 0 { 119 | seqs1 := rs 120 | curr := rs 121 | for len(seqs1) != 1 { 122 | curr = seqs1 123 | seqs1 = make([]types.R, 0) 124 | for i := 0; i < len(curr); i += 2 { 125 | if i+1 < len(curr) { 126 | seqs1 = append(seqs1, types.Seq{curr[i], curr[i+1]}) 127 | } else { 128 | seqs1 = append(seqs1, curr[i]) 129 | } 130 | } 131 | } 132 | 133 | return seqs1[0] 134 | } 135 | return types.Eps(1) 136 | } 137 | 138 | func (s *state) makeAlts(rs []types.R) types.R { 139 | if len(rs) == 1 { 140 | return rs[0] 141 | } else if len(rs) > 0 { 142 | seqs1 := rs 143 | curr := rs 144 | for len(seqs1) != 1 { 145 | curr = seqs1 146 | seqs1 = make([]types.R, 0) 147 | for i := 0; i < len(curr); i += 2 { 148 | if i+1 < len(curr) { 149 | seqs1 = append(seqs1, types.Alt{curr[i], curr[i+1]}) 150 | } else { 151 | seqs1 = append(seqs1, curr[i]) 152 | } 153 | } 154 | } 155 | 156 | return seqs1[0] 157 | } 158 | return types.Eps(1) 159 | } 160 | 161 | func (s *state) makeAlts2(rs []types.R) types.R { 162 | if len(rs) == 1 { 163 | return rs[0] 164 | } else if len(rs) > 0 { 165 | seqs1 := rs 166 | curr := rs 167 | for len(seqs1) != 1 { 168 | curr = seqs1 169 | seqs1 = make([]types.R, 0) 170 | for i := 0; i < len(curr); i += 2 { 171 | if i+1 < len(curr) { 172 | seqs1 = append(seqs1, types.Alt2{curr[i], curr[i+1]}) 173 | } else { 174 | seqs1 = append(seqs1, curr[i]) 175 | } 176 | } 177 | } 178 | 179 | return seqs1[0] 180 | } 181 | return types.Eps(1) 182 | } 183 | 184 | func (st *state) handleOp(op simplify.Operation) (innerRs []types.R) { 185 | s := fmt.Sprintf("%v%v", op.Pos, op.Op) 186 | 187 | z, ok := st.signMap[s] 188 | if ok { 189 | innerRs = append(innerRs, types.Sym(z)) 190 | tmp := st.partnerMap[op.Pos] 191 | tmp.Insert(z) 192 | st.partnerMap[op.Pos] = tmp 193 | } else { 194 | //fmt.Println(s, string(st.alpha), op) 195 | st.signMap[s] = st.alpha 196 | innerRs = append(innerRs, types.Sym(st.alpha)) 197 | tmp, ok := st.partnerMap[op.Pos] 198 | if op.Op != "#" { 199 | if !ok { 200 | tmp = algorithm.NewHashSet() 201 | } 202 | tmp.Insert(st.alpha) 203 | st.partnerMap[op.Pos] = tmp 204 | 205 | if op.Op == "?" { 206 | st.ReaderMap[types.Sym(st.alpha)] = 1 207 | } 208 | } else { 209 | if ok { 210 | localAlpha := types.Sym(st.alpha) 211 | xtmp, ok2 := st.closerMap[localAlpha] 212 | if !ok2 { 213 | st.closerMap[localAlpha] = make([]types.R, 0) 214 | } 215 | for q := range tmp.Iterate() { 216 | xtmp = append(xtmp, types.Sym(q.(rune))) 217 | } 218 | st.closerMap[localAlpha] = xtmp 219 | } 220 | } 221 | 222 | st.alpha = st.alpha + 1 223 | } 224 | return 225 | } 226 | 227 | func (st *state) handleIf2(op simplify.Operation) types.R { 228 | ifrs := make([]types.R, 0) 229 | for _, z := range op.Ops { 230 | ifrs = append(ifrs, st.handleOp(z)...) 231 | } 232 | ifBody := st.makeSeqs(ifrs) 233 | 234 | elsers := make([]types.R, 0) 235 | for _, z := range op.Else { 236 | elsers = append(elsers, st.handleOp(z)...) 237 | } 238 | elseBody := st.makeSeqs(elsers) 239 | 240 | return types.Alt{ifBody, elseBody} 241 | } 242 | 243 | func (st *state) handleSelect(op simplify.Operation) types.R { 244 | selectCases := make([]types.R, 0) 245 | for _, y := range op.Ops { 246 | //fmt.Println("!Y!", y) 247 | if len(y.Ops) > 0 { 248 | if len(y.Ops) == 1 { 249 | tmp := st.handleOp(y) 250 | 251 | //fmt.Println(tmp, y.Ops[0]) 252 | for i := range tmp { 253 | tmp[i] = types.Seq{tmp[i], st.handleOp(y.Ops[0])[0]} 254 | } 255 | 256 | selectCases = append(selectCases, tmp...) 257 | } else { 258 | rs := make([]types.R, 0) 259 | for i := range y.Ops { 260 | rs = append(rs, st.handleOp(y.Ops[i])...) 261 | } 262 | selectCases = append(selectCases, st.makeSeqs(rs)) 263 | } 264 | 265 | } else { 266 | selectCases = append(selectCases, st.handleOp(y)...) 267 | } 268 | 269 | } 270 | return st.makeAlts2(selectCases) 271 | } 272 | 273 | func (st *state) handleIf(op simplify.Operation) types.R { 274 | ifrs := make([]types.R, 0) 275 | for _, z := range op.Ops { 276 | s := fmt.Sprintf("%v%v", z.Pos, z.Op) 277 | h, ok := st.signMap[s] 278 | if ok { 279 | ifrs = append(ifrs, types.Sym(h)) 280 | tmp := st.partnerMap[z.Pos] 281 | tmp.Insert(h) 282 | st.partnerMap[z.Pos] = tmp 283 | } else { 284 | st.signMap[s] = st.alpha 285 | ifrs = append(ifrs, types.Sym(st.alpha)) 286 | tmp, ok := st.partnerMap[z.Pos] 287 | if !ok { 288 | tmp = algorithm.NewHashSet() 289 | } 290 | tmp.Insert(st.alpha) 291 | st.partnerMap[z.Pos] = tmp 292 | st.alpha = st.alpha + 1 293 | } 294 | } 295 | ifBody := st.makeSeqs(ifrs) 296 | 297 | elsers := make([]types.R, 0) 298 | for _, z := range op.Else { 299 | s := fmt.Sprintf("%v%v", z.Pos, z.Op) 300 | h, ok := st.signMap[s] 301 | if ok { 302 | elsers = append(elsers, types.Sym(h)) 303 | tmp := st.partnerMap[z.Pos] 304 | tmp.Insert(h) 305 | st.partnerMap[z.Pos] = tmp 306 | } else { 307 | st.signMap[s] = st.alpha 308 | // fmt.Println(s, "==", string(st.alpha)) 309 | elsers = append(elsers, types.Sym(st.alpha)) 310 | tmp, ok := st.partnerMap[z.Pos] 311 | if !ok { 312 | tmp = algorithm.NewHashSet() 313 | } 314 | tmp.Insert(st.alpha) 315 | st.partnerMap[z.Pos] = tmp 316 | st.alpha = st.alpha + 1 317 | } 318 | } 319 | elseBody := st.makeSeqs(elsers) 320 | return types.Alt{ifBody, elseBody} 321 | } 322 | -------------------------------------------------------------------------------- /types/types.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | var loopCounter map[R]int 8 | 9 | type R interface { 10 | String() string 11 | Nullable() bool 12 | IsPhi() bool 13 | ConcPart() R 14 | SeqPart() R 15 | Deriv(r R) R 16 | PDeriv(r R) []R 17 | NextSym() []R 18 | Reduce() R 19 | ContainsPhi() bool 20 | Contains(r R) bool 21 | } 22 | 23 | type Sym rune 24 | type Star [1]R 25 | type Alt [2]R 26 | type Alt2 [2]R 27 | type SELECTGROUP []R 28 | type Seq [2]R 29 | type Eps int 30 | type Phi int 31 | type Fork [1]R 32 | type Skip []R 33 | 34 | func init() { 35 | loopCounter = make(map[R]int) 36 | } 37 | 38 | func (s Sym) Nullable() bool { return false } 39 | func (s Star) Nullable() bool { return true } 40 | func (a Alt) Nullable() bool { return a[0].Nullable() || a[1].Nullable() } 41 | func (a Alt2) Nullable() bool { return a[0].Nullable() || a[1].Nullable() } 42 | func (s Seq) Nullable() bool { return s[0].Nullable() && s[1].Nullable() } 43 | func (e Eps) Nullable() bool { return true } 44 | func (p Phi) Nullable() bool { return false } 45 | func (f Fork) Nullable() bool { return f[0].Nullable() } 46 | func (f Skip) Nullable() bool { return true } 47 | func (f SELECTGROUP) Nullable() bool { return true } 48 | 49 | func (s Sym) IsPhi() bool { return false } 50 | func (s Star) IsPhi() bool { return false } 51 | func (a Alt) IsPhi() bool { return a[0].IsPhi() && a[1].IsPhi() } 52 | func (a Alt2) IsPhi() bool { return a[0].IsPhi() && a[1].IsPhi() } 53 | func (s Seq) IsPhi() bool { return s[0].IsPhi() || s[1].IsPhi() } 54 | func (e Eps) IsPhi() bool { return false } 55 | func (p Phi) IsPhi() bool { return true } 56 | func (f Fork) IsPhi() bool { return f[0].IsPhi() } 57 | func (f Skip) IsPhi() bool { return false } 58 | func (f SELECTGROUP) IsPhi() bool { return false } 59 | 60 | func (s Sym) ContainsPhi() bool { return false } 61 | func (s Star) ContainsPhi() bool { return s[0].ContainsPhi() } 62 | func (a Alt) ContainsPhi() bool { return a[0].ContainsPhi() || a[1].ContainsPhi() } 63 | func (a Alt2) ContainsPhi() bool { return a[0].ContainsPhi() || a[1].ContainsPhi() } 64 | func (s Seq) ContainsPhi() bool { return s[0].ContainsPhi() || s[1].ContainsPhi() } 65 | func (e Eps) ContainsPhi() bool { return false } 66 | func (p Phi) ContainsPhi() bool { return true } 67 | func (f Fork) ContainsPhi() bool { return f[0].ContainsPhi() } 68 | func (f Skip) ContainsPhi() bool { return false } 69 | func (f SELECTGROUP) ContainsPhi() bool { return false } 70 | 71 | func (s Sym) ConcPart() R { return Phi(1) } 72 | func (s Star) ConcPart() R { return Star{s[0].ConcPart()} } 73 | func (a Alt) ConcPart() R { return Alt{a[0].ConcPart(), a[1].ConcPart()} } 74 | func (a Alt2) ConcPart() R { return Alt2{a[0].ConcPart(), a[1].ConcPart()} } 75 | func (s Seq) ConcPart() R { return Seq{s[0].ConcPart(), s[1].ConcPart()} } 76 | func (e Eps) ConcPart() R { return e } 77 | func (p Phi) ConcPart() R { return p } 78 | func (f Fork) ConcPart() R { return f } 79 | func (f Skip) ConcPart() R { return f } 80 | func (f SELECTGROUP) ConcPart() R { return f } 81 | 82 | func (s Sym) SeqPart() R { return s } 83 | func (s Star) SeqPart() R { return Seq{Star{s[0].ConcPart()}, Seq{s[0].SeqPart(), s}} } 84 | func (a Alt) SeqPart() R { return Alt{a[0].SeqPart(), a[1].SeqPart()} } 85 | func (a Alt2) SeqPart() R { return Alt{a[0].SeqPart(), a[1].SeqPart()} } 86 | func (s Seq) SeqPart() R { 87 | return Alt{Seq{s[0].SeqPart(), s[1]}, 88 | Seq{s[0].ConcPart(), s[1].SeqPart()}} 89 | } 90 | func (e Eps) SeqPart() R { return Phi(1) } 91 | func (p Phi) SeqPart() R { return p } 92 | func (f Fork) SeqPart() R { return Phi(1) } 93 | func (f Skip) SeqPart() R { return f } 94 | func (f SELECTGROUP) SeqPart() R { return f } 95 | 96 | func (s Skip) Deriv(r R) R { 97 | return s 98 | } 99 | func (s SELECTGROUP) Deriv(r R) R { 100 | return Phi(1) 101 | } 102 | func (s Sym) Deriv(r R) R { 103 | if r == s { 104 | return Eps(1) 105 | } 106 | return Phi(1) 107 | } 108 | func (s Star) Deriv(r R) R { 109 | tmp := s[0].Deriv(r) 110 | if tmp == Eps(1) { 111 | return s 112 | } 113 | return Seq{tmp, s} 114 | } 115 | func (a Alt) Deriv(r R) R { 116 | if a[0].Contains(r) && a[1].Contains(r) { 117 | return Alt{a[0].Deriv(r), a[1].Deriv(r)} 118 | } else if a[0].Contains(r) { 119 | return a[0].Deriv(r) 120 | } else if a[1].Contains(r) { 121 | return a[1].Deriv(r) 122 | } 123 | 124 | return Phi(1) 125 | } 126 | func (a Alt2) Deriv(r R) R { 127 | if a[0].Contains(r) && a[1].Contains(r) { 128 | return Alt2{a[0].Deriv(r), a[1].Deriv(r)} 129 | } else if a[0].Contains(r) { 130 | return a[0].Deriv(r) 131 | } else if a[1].Contains(r) { 132 | return a[1].Deriv(r) 133 | } 134 | 135 | return Phi(1) 136 | } 137 | func (s Seq) Deriv(r R) R { 138 | // fmt.Println(s, r) 139 | if s[0].Contains(r) { 140 | if s[0].Nullable() { 141 | if s[1].Contains(r) { 142 | return Alt{Seq{s[0].Deriv(r), s[1]}, s[1].Deriv(r)} 143 | } else { 144 | return Seq{s[0].Deriv(r), s[1]} 145 | } 146 | } 147 | sn := Seq{s[0].Deriv(r), s[1]} 148 | if sn[0] == Eps(1) { 149 | return s[1] 150 | } 151 | return sn 152 | } 153 | 154 | if s[0].Nullable() { 155 | rs := s[1].Deriv(r) 156 | return rs 157 | } else { 158 | return Seq{Phi(1), s[1].Deriv(r)} 159 | } 160 | 161 | //return Alt{Seq{s[0].Deriv(r), s[1]}, Seq{s[0].concPart(), s[1].Deriv(r)}} 162 | } 163 | func (e Eps) Deriv(r R) R { 164 | return Phi(1) 165 | } 166 | func (p Phi) Deriv(r R) R { 167 | return p 168 | } 169 | func (f Fork) Deriv(r R) R { 170 | tmp := f[0].Deriv(r) 171 | if tmp == Eps(1) { 172 | return Eps(1) 173 | } 174 | return Fork{tmp} 175 | } 176 | 177 | func (s Skip) PDeriv(r R) []R { 178 | return []R{s} 179 | } 180 | func (s SELECTGROUP) PDeriv(r R) []R { 181 | return []R{} 182 | } 183 | 184 | func (s Sym) PDeriv(r R) []R { 185 | if r == s { 186 | return []R{Eps(1)} 187 | } 188 | return []R{} 189 | } 190 | func (s Star) PDeriv(r R) (ret []R) { 191 | ret = append(ret, s[0].PDeriv(r)...) 192 | for i, el := range ret { 193 | ret[i] = Seq{el, s} 194 | } 195 | return 196 | } 197 | func (a Alt) PDeriv(r R) (ret []R) { 198 | ret = append(a[0].PDeriv(r), a[1].PDeriv(r)...) 199 | return 200 | } 201 | func (a Alt2) PDeriv(r R) (ret []R) { 202 | ret = append(a[0].PDeriv(r), a[1].PDeriv(r)...) 203 | return 204 | } 205 | func (s Seq) PDeriv(r R) (ret []R) { 206 | ret = append(ret, s[0].PDeriv(r)...) 207 | for i, el := range ret { 208 | ret[i] = Seq{el, s[1]} 209 | } 210 | 211 | for _, el := range s[1].PDeriv(r) { 212 | ret = append(ret, Seq{s[0].ConcPart(), el}) 213 | } 214 | return 215 | } 216 | func (e Eps) PDeriv(r R) []R { return []R{} } 217 | func (p Phi) PDeriv(r R) []R { return []R{} } 218 | func (f Fork) PDeriv(r R) (ret []R) { 219 | ret = append(ret, f[0].PDeriv(r)...) 220 | for i, el := range ret { 221 | ret[i] = Fork{el} 222 | } 223 | return 224 | } 225 | 226 | func (s Skip) NextSym() []R { 227 | return []R{s} 228 | } 229 | func (s SELECTGROUP) NextSym() []R { 230 | return []R{} 231 | } 232 | func (s Sym) NextSym() []R { return []R{s} } 233 | func (s Star) NextSym() []R { 234 | return s[0].NextSym() 235 | //return append(s[0].NextSym(), Skip(1)) 236 | } 237 | func (a Alt) NextSym() []R { return append(a[0].NextSym(), a[1].NextSym()...) } 238 | func (a Alt2) NextSym() []R { 239 | x := a[0].NextSym() 240 | y := a[1].NextSym() 241 | var tmp SELECTGROUP = x 242 | tmp = append(tmp, y...) 243 | y = append(y, tmp) 244 | return append(x, y...) 245 | // return append(a[0].NextSym(), a[1].NextSym()...) 246 | } 247 | func (s Seq) NextSym() []R { 248 | if s[0].ConcPart().IsPhi() { 249 | return s[0].NextSym() 250 | } 251 | return append(s[0].NextSym(), s[1].NextSym()...) 252 | } 253 | func (e Eps) NextSym() []R { return []R{} } 254 | func (p Phi) NextSym() []R { return []R{} } 255 | func (f Fork) NextSym() []R { return f[0].NextSym() } 256 | 257 | func (s Skip) Reduce() R { return s } 258 | func (s SELECTGROUP) Reduce() R { return s } 259 | func (s Sym) Reduce() R { return s } 260 | func (e Eps) Reduce() R { return e } 261 | func (p Phi) Reduce() R { return p } 262 | func (s Star) Reduce() R { 263 | x := s[0].Reduce() 264 | 265 | if x != Eps(1) { 266 | return Star{x} 267 | } 268 | return Eps(1) 269 | } 270 | func (a Alt) Reduce() R { 271 | l := a[0].Reduce() 272 | r := a[1].Reduce() 273 | if l == Eps(1) && r == Eps(1) { 274 | return Eps(1) 275 | } else if r == Eps(1) { 276 | return l 277 | } else if l == Eps(1) { 278 | return r 279 | } else { 280 | return Alt{l, r} 281 | } 282 | } 283 | func (a Alt2) Reduce() R { 284 | l := a[0].Reduce() 285 | r := a[1].Reduce() 286 | if l == Eps(1) && r == Eps(1) { 287 | return Eps(1) 288 | } else if r == Eps(1) { 289 | return l 290 | } else if l == Eps(1) { 291 | return r 292 | } else { 293 | return Alt2{l, r} 294 | } 295 | } 296 | func (s Seq) Reduce() R { 297 | l := s[0].Reduce() 298 | r := s[1].Reduce() 299 | 300 | if l == Eps(1) && r == Eps(1) { 301 | return Eps(1) 302 | } else if r == Eps(1) { 303 | return l 304 | } else if l == Eps(1) { 305 | return r 306 | } else { 307 | return Alt{l, r} 308 | } 309 | } 310 | func (f Fork) Reduce() R { 311 | x := f[0].Reduce() 312 | if x != Eps(1) { 313 | return Fork{x} 314 | } 315 | return Eps(1) 316 | } 317 | 318 | func (s Skip) Contains(e R) bool { 319 | return false 320 | } 321 | func (s SELECTGROUP) Contains(e R) bool { 322 | return false 323 | } 324 | 325 | func (s Sym) Contains(e R) bool { 326 | switch x := e.(type) { 327 | case Sym: 328 | return x == s 329 | default: 330 | return x.Contains(s) 331 | } 332 | } 333 | func (s Star) Contains(e R) bool { 334 | return s[0].Contains(e) 335 | } 336 | func (a Alt) Contains(e R) bool { 337 | return a[0].Contains(e) || a[1].Contains(e) 338 | } 339 | func (a Alt2) Contains(e R) bool { 340 | return a[0].Contains(e) || a[1].Contains(e) 341 | } 342 | func (s Seq) Contains(e R) bool { 343 | if s[0].Nullable() { 344 | return s[0].Contains(e) || s[1].Contains(e) 345 | } 346 | return s[0].Contains(e) 347 | } 348 | func (a Eps) Contains(e R) bool { 349 | switch e.(type) { 350 | case Eps: 351 | return true 352 | default: 353 | return false 354 | } 355 | } 356 | func (p Phi) Contains(e R) bool { 357 | return false 358 | } 359 | func (f Fork) Contains(e R) bool { 360 | return f[0].Contains(e) 361 | } 362 | 363 | func (s Skip) String() string { 364 | return "$SKIP$" 365 | } 366 | func (s SELECTGROUP) String() string { 367 | return "$SELECTGROUP$" 368 | } 369 | func (s Sym) String() string { 370 | return (string)(s) 371 | } 372 | func (s Star) String() string { 373 | return "(" + s[0].String() + ")*" 374 | } 375 | func (a Alt) String() string { 376 | return "(" + a[0].String() + "+" + a[1].String() + ")" 377 | } 378 | func (a Alt2) String() string { 379 | return "(" + a[0].String() + "XOR" + a[1].String() + ")" 380 | } 381 | func (e Eps) String() string { 382 | return "\u03B5" 383 | } 384 | func (s Seq) String() string { 385 | return "(" + s[0].String() + "." + s[1].String() + ")" 386 | } 387 | func (p Phi) String() string { 388 | return "\u03C6" 389 | } 390 | func (f Fork) String() string { 391 | return fmt.Sprintf("Fork(%v)", f[0].String()) 392 | } 393 | 394 | func Derivs(r R, s string) R { 395 | for _, c := range s { 396 | r = r.Deriv(Sym(c)) 397 | } 398 | return r 399 | } 400 | -------------------------------------------------------------------------------- /simplifier/simplifiy.go: -------------------------------------------------------------------------------- 1 | package simplify 2 | 3 | import ( 4 | "fmt" 5 | "go/ast" 6 | "go/parser" 7 | "go/token" 8 | "path/filepath" 9 | "reflect" 10 | 11 | "../oracleAPI" 12 | ) 13 | 14 | type Simplifier struct { 15 | FSet *token.FileSet 16 | File *ast.File 17 | Src string 18 | Mapv2 map[string]Callgraph2 19 | Path string 20 | PackageName string 21 | } 22 | 23 | type Callgraph2 struct { 24 | Name string `json:"name"` 25 | NrRoots int `json:"rootCount"` 26 | Calls []string `json:"calls"` 27 | ChanOps []Operation `json:"ops"` 28 | AllOps []Operation `json:"allOps"` 29 | } 30 | type Operation struct { 31 | Type string 32 | Name string 33 | Pos int 34 | Op string 35 | Ops []Operation 36 | Else []Operation 37 | } 38 | 39 | func New() *Simplifier { 40 | return &Simplifier{FSet: token.NewFileSet()} 41 | } 42 | 43 | func (s *Simplifier) Parse(filePath string) map[string]Callgraph2 { 44 | s.Path = filePath 45 | f, err := parser.ParseFile(s.FSet, filePath, nil, parser.ParseComments) 46 | s.File = f 47 | if err != nil { 48 | panic(err) 49 | } 50 | s.Mapv2 = make(map[string]Callgraph2) 51 | 52 | ast.Inspect(f, func(n ast.Node) bool { 53 | switch x := n.(type) { 54 | case *ast.File: 55 | s.PackageName = x.Name.Name 56 | case *ast.FuncDecl: 57 | tmp2 := s.Mapv2[x.Name.Name] 58 | if x.Name.Name == "main" { 59 | tmp2.NrRoots++ 60 | } 61 | tmp2.Calls = make([]string, 0) 62 | 63 | for _, v := range x.Body.List { 64 | switch y := v.(type) { 65 | case *ast.ExprStmt: 66 | switch z := y.X.(type) { 67 | case *ast.CallExpr: 68 | n := s.getValue(z) 69 | if n == "close" { 70 | if r, o := s.handleClose(z); r { 71 | tmp2.ChanOps = append(tmp2.ChanOps, o) 72 | tmp2.AllOps = append(tmp2.AllOps, o) 73 | } 74 | } else { 75 | tmp2.Calls = append(tmp2.Calls, n) 76 | 77 | var o Operation 78 | o.Type = "Call" 79 | o.Name = fmt.Sprintf("%v.%v:%v", s.PackageName, n, 0) 80 | o.Op = "()" 81 | tmp2.AllOps = append(tmp2.AllOps, o) 82 | } 83 | 84 | case *ast.UnaryExpr: 85 | if r, o := s.handleUnaryExpr(z); r { 86 | tmp2.ChanOps = append(tmp2.ChanOps, o) 87 | tmp2.AllOps = append(tmp2.AllOps, o) 88 | } 89 | } 90 | case *ast.AssignStmt: 91 | switch a := y.Rhs[0].(type) { 92 | case *ast.UnaryExpr: 93 | if r, o := s.handleUnaryExpr(a); r { 94 | tmp2.ChanOps = append(tmp2.ChanOps, o) 95 | tmp2.AllOps = append(tmp2.AllOps, o) 96 | } 97 | } 98 | case *ast.SendStmt: 99 | //check if a value from another chan was send 100 | switch h := y.Value.(type) { 101 | case *ast.UnaryExpr: 102 | if r, o := s.handleUnaryExpr(h); r { 103 | tmp2.ChanOps = append(tmp2.ChanOps, o) 104 | tmp2.AllOps = append(tmp2.AllOps, o) 105 | } 106 | } 107 | if r, o := s.handleSend(y); r { 108 | tmp2.ChanOps = append(tmp2.ChanOps, o) 109 | tmp2.AllOps = append(tmp2.AllOps, o) 110 | } 111 | case *ast.SelectStmt: 112 | var opSelect Operation 113 | opSelect.Type = "Select" 114 | res := false 115 | for _, a := range y.Body.List { 116 | if r, o := s.handleCommClaus(a.(*ast.CommClause)); r { 117 | // fmt.Println("PARSER", o) 118 | res = true 119 | opSelect.Ops = append(opSelect.Ops, o) 120 | } 121 | } 122 | if res { 123 | tmp2.ChanOps = append(tmp2.ChanOps, opSelect) 124 | tmp2.AllOps = append(tmp2.AllOps, opSelect) 125 | } 126 | case *ast.IfStmt: 127 | if r, o := s.handleIfStmt(y); r { 128 | tmp2.ChanOps = append(tmp2.ChanOps, o) 129 | tmp2.AllOps = append(tmp2.AllOps, o) 130 | } 131 | case *ast.ForStmt: 132 | //fmt.Println("FOR") 133 | if r, o := s.handleForStmt(y); r { 134 | //fmt.Println(o) 135 | tmp2.ChanOps = append(tmp2.ChanOps, o) 136 | tmp2.AllOps = append(tmp2.AllOps, o) 137 | } 138 | //fmt.Println("ROF") 139 | case *ast.GoStmt: 140 | n := s.getValue(y.Call) 141 | 142 | if n == x.Name.Name { 143 | tmp2.NrRoots++ 144 | } else { 145 | tmpY := s.Mapv2[n] 146 | tmpY.NrRoots++ 147 | s.Mapv2[n] = tmpY 148 | } 149 | } 150 | } 151 | s.Mapv2[x.Name.Name] = tmp2 152 | } 153 | return true 154 | }) 155 | return s.Mapv2 156 | } 157 | 158 | func (s *Simplifier) handleUnaryExpr(n *ast.UnaryExpr) (bool, Operation) { 159 | var resOps Operation 160 | if n.Op == token.ARROW { 161 | pos := s.FSet.Position(n.OpPos).Offset 162 | oraclePath := "guru" 163 | 164 | oracle := oracler.New(oraclePath, s.Path, "./"+filepath.Dir(s.Path)) 165 | 166 | p := oracle.GetPeers("json", pos) 167 | 168 | res := false 169 | resOps.Type = "Op" 170 | for i := range p.PeerEntries.Allocs { 171 | l, _ := oracle.LineNColumn(p.PeerEntries.Allocs[i]) 172 | res = true 173 | resOps.Ops = append(resOps.Ops, Operation{Type: "Rcv", Pos: int(l), Name: fmt.Sprintf("%v.%v:%v", s.PackageName, "", l), Op: "?"}) 174 | } 175 | 176 | return res, resOps 177 | } 178 | 179 | return false, resOps 180 | } 181 | 182 | func (s *Simplifier) handleSend(n *ast.SendStmt) (bool, Operation) { 183 | pos := s.FSet.Position(n.Arrow).Offset 184 | oraclePath := "guru" 185 | 186 | oracle := oracler.New(oraclePath, s.Path, "./"+filepath.Dir(s.Path)) 187 | p := oracle.GetPeers("json", pos) 188 | // fmt.Println("SEND", pos, p.PeerEntries.Allocs) 189 | 190 | res := false 191 | var resOps Operation 192 | resOps.Type = "Op" 193 | 194 | for i := range p.PeerEntries.Allocs { 195 | l, _ := oracle.LineNColumn(p.PeerEntries.Allocs[i]) 196 | res = true 197 | resOps.Ops = append(resOps.Ops, Operation{Type: "Snd", Pos: int(l), Name: fmt.Sprintf("%v.%v:%v", s.PackageName, "", l), Op: "!"}) 198 | } 199 | return res, resOps 200 | } 201 | 202 | func (s *Simplifier) handleClose(n *ast.CallExpr) (bool, Operation) { 203 | pos := s.FSet.Position(n.Lparen).Offset 204 | oraclePath := "guru" 205 | 206 | oracle := oracler.New(oraclePath, s.Path, "./"+filepath.Dir(s.Path)) 207 | p := oracle.GetPeers("json", pos+1) 208 | 209 | // fmt.Println("CLOSE", pos, p.PeerEntries.Allocs) 210 | 211 | res := false 212 | var resOps Operation 213 | resOps.Type = "Op" 214 | 215 | for i := range p.PeerEntries.Allocs { 216 | l, _ := oracle.LineNColumn(p.PeerEntries.Allocs[i]) 217 | res = true 218 | resOps.Ops = append(resOps.Ops, Operation{Type: "Close", Pos: int(l), Name: fmt.Sprintf("%v.%v:%v", s.PackageName, "", l), Op: "#"}) 219 | } 220 | return res, resOps 221 | } 222 | 223 | func (s *Simplifier) handleCommClaus(n *ast.CommClause) (bool, Operation) { 224 | if n.Comm != nil { 225 | switch x := n.Comm.(type) { 226 | case *ast.ExprStmt: 227 | switch z := x.X.(type) { 228 | case *ast.UnaryExpr: 229 | tmp, r := s.handleUnaryExpr(z) 230 | //fmt.Println("SELECT1", r) 231 | for _, bel := range n.Body { 232 | switch valu := bel.(type) { 233 | case *ast.SendStmt: 234 | q, t := s.handleSend(valu) 235 | if q { 236 | r.Ops = append(r.Ops, t.Ops[0]) 237 | } 238 | } 239 | } 240 | // fmt.Println("SELECT2", r) 241 | // switch valu := n.Body[0].(type) { 242 | // case *ast.SendStmt: 243 | // q, t := s.handleSend(valu) 244 | // if q { 245 | // r.Ops = append(r.Ops, t) 246 | // } 247 | // } 248 | return tmp, r 249 | } 250 | case *ast.AssignStmt: 251 | switch a := x.Rhs[0].(type) { 252 | case *ast.UnaryExpr: 253 | r, o := s.handleUnaryExpr(a) 254 | if len(o.Ops) > 0 { 255 | switch valu := n.Body[0].(type) { 256 | case *ast.SendStmt: 257 | q, t := s.handleSend(valu) 258 | if q { 259 | o.Ops[0].Ops = append(o.Ops[0].Ops, t.Ops[0]) 260 | } 261 | } 262 | return r, o.Ops[0] 263 | } 264 | } 265 | case *ast.SendStmt: 266 | r, o := s.handleSend(x) 267 | return r, o.Ops[0] 268 | } 269 | } else { 270 | for _, bel := range n.Body { 271 | switch valu := bel.(type) { 272 | case *ast.SendStmt: 273 | q, t := s.handleSend(valu) 274 | if q { 275 | //fmt.Println("!DEFAULT!", t.Ops[0]) 276 | return true, t.Ops[0] 277 | //r.Ops = append(r.Ops, t.Ops[0]) 278 | } 279 | } 280 | } 281 | } 282 | 283 | return false, Operation{} 284 | } 285 | 286 | func (s *Simplifier) handleIfStmt(n *ast.IfStmt) (bool, Operation) { 287 | res := false 288 | var resOps Operation 289 | resOps.Type = "If" 290 | 291 | for _, a := range n.Body.List { 292 | switch stmt := a.(type) { 293 | case *ast.ExprStmt: 294 | switch xp := stmt.X.(type) { 295 | case *ast.UnaryExpr: 296 | r, o := s.handleUnaryExpr(xp) 297 | if r { 298 | res = true 299 | resOps.Ops = append(resOps.Ops, o.Ops[0]) 300 | } 301 | } 302 | case *ast.AssignStmt: 303 | switch xp := stmt.Rhs[0].(type) { 304 | case *ast.UnaryExpr: 305 | r, o := s.handleUnaryExpr(xp) 306 | if r { 307 | res = true 308 | resOps.Ops = append(resOps.Ops, o.Ops[0]) 309 | } 310 | } 311 | case *ast.SendStmt: 312 | r, o := s.handleSend(stmt) 313 | if r { 314 | res = true 315 | resOps.Ops = append(resOps.Ops, o.Ops[0]) 316 | } 317 | } 318 | } 319 | 320 | if n.Else != nil { 321 | res = true 322 | switch el := n.Else.(type) { 323 | case *ast.IfStmt: 324 | _, o := s.handleIfStmt(el) 325 | resOps.Else = append(resOps.Else, o) 326 | 327 | case *ast.BlockStmt: 328 | for _, a := range el.List { 329 | switch stmt := a.(type) { 330 | case *ast.ExprStmt: 331 | switch xp := stmt.X.(type) { 332 | case *ast.UnaryExpr: 333 | r, o := s.handleUnaryExpr(xp) 334 | 335 | if r { 336 | resOps.Else = append(resOps.Else, o.Ops[0]) 337 | } 338 | } 339 | case *ast.AssignStmt: 340 | switch xp := stmt.Rhs[0].(type) { 341 | case *ast.UnaryExpr: 342 | r, o := s.handleUnaryExpr(xp) 343 | if r { 344 | resOps.Else = append(resOps.Else, o.Ops[0]) 345 | } 346 | } 347 | case *ast.SendStmt: 348 | r, o := s.handleSend(stmt) 349 | if r { 350 | resOps.Else = append(resOps.Else, o.Ops[0]) 351 | } 352 | } 353 | } 354 | } 355 | } else { 356 | // else NIL bzw +eps fehlt hier noch !? 357 | } 358 | 359 | return res, resOps 360 | } 361 | 362 | func (s *Simplifier) handleForStmt(n *ast.ForStmt) (bool, Operation) { 363 | res := false 364 | var resOps Operation 365 | resOps.Type = "For" 366 | 367 | for _, a := range n.Body.List { 368 | switch stmt := a.(type) { 369 | case *ast.ExprStmt: 370 | switch xp := stmt.X.(type) { 371 | case *ast.UnaryExpr: 372 | if r, o := s.handleUnaryExpr(xp); r { 373 | res = true 374 | resOps.Ops = append(resOps.Ops, o.Ops[0]) 375 | } 376 | } 377 | case *ast.AssignStmt: 378 | switch xp := stmt.Rhs[0].(type) { 379 | case *ast.UnaryExpr: 380 | if r, o := s.handleUnaryExpr(xp); r { 381 | res = true 382 | resOps.Ops = append(resOps.Ops, o.Ops[0]) 383 | } 384 | } 385 | case *ast.SendStmt: 386 | if r, o := s.handleSend(stmt); r { 387 | res = true 388 | resOps.Ops = append(resOps.Ops, o.Ops[0]) 389 | } 390 | case *ast.IfStmt: 391 | if r, o := s.handleIfStmt(stmt); r { 392 | res = true 393 | resOps.Ops = append(resOps.Ops, o) 394 | } 395 | case *ast.SelectStmt: 396 | var opSelect Operation 397 | opSelect.Type = "Select" 398 | for _, a := range stmt.Body.List { 399 | if r, o := s.handleCommClaus(a.(*ast.CommClause)); r { 400 | res = true 401 | opSelect.Ops = append(opSelect.Ops, o) 402 | } 403 | } 404 | //fmt.Println("FORSEL", opSelect, len(opSelect.Ops)) 405 | 406 | if res { 407 | resOps.Ops = append(resOps.Ops, opSelect) 408 | } 409 | //fmt.Println("FOROPS", resOps) 410 | default: 411 | fmt.Println(reflect.TypeOf(stmt)) 412 | } 413 | } 414 | return res, resOps 415 | } 416 | 417 | func (si *Simplifier) getValue(n ast.Expr) (s string) { 418 | ast.Inspect(n, func(x ast.Node) bool { 419 | switch y := x.(type) { 420 | case *ast.Ident: 421 | if y != nil { 422 | s += y.Name 423 | } 424 | return false 425 | case *ast.BasicLit: 426 | s += y.Value 427 | return false 428 | case *ast.ChanType: 429 | s += "chan " 430 | case *ast.CallExpr: 431 | s = si.getValue(y.Fun) 432 | return false 433 | case *ast.CompositeLit: 434 | s += si.getValue(y.Type) + "{" 435 | for i, v := range y.Elts { 436 | switch p := v.(type) { 437 | case *ast.KeyValueExpr: 438 | s += si.getValue(p.Key) + ": " + si.getValue(p.Value) 439 | } 440 | if i < (len(y.Elts) - 1) { 441 | s += ", " 442 | } 443 | } 444 | s += "}" 445 | return false 446 | } 447 | 448 | return true 449 | }) 450 | return 451 | } 452 | -------------------------------------------------------------------------------- /validation/validation.go: -------------------------------------------------------------------------------- 1 | package validation 2 | 3 | import ( 4 | "../types" 5 | //"bufio" 6 | "fmt" 7 | //"os" 8 | ) 9 | 10 | type machine struct { 11 | Rs []types.R 12 | Trace string 13 | Succ bool 14 | Stop bool 15 | Abort bool 16 | } 17 | 18 | type nextStr struct { 19 | ThreadId int 20 | Rs []types.R 21 | } 22 | 23 | func Rscontains(c types.R, rs []types.R) bool { 24 | for _, r := range rs { 25 | if r == c { 26 | return true 27 | } 28 | } 29 | return false 30 | } 31 | 32 | type machine2 struct { 33 | Threads []types.R 34 | PMap map[types.R]types.R 35 | CMap map[types.R][]types.R 36 | RMap map[types.R]int 37 | ClosedChannels []types.R 38 | StateMap map[types.R]int 39 | Trace string 40 | Succ bool 41 | Stop bool 42 | Abort bool 43 | } 44 | 45 | type SyncPoint struct { 46 | T1Id int 47 | T2Id int 48 | Symbol types.R 49 | } 50 | 51 | func (m *machine2) clone() machine2 { 52 | new := machine2{PMap: m.PMap, Threads: make([]types.R, 0), Trace: m.Trace, StateMap: make(map[types.R]int)} 53 | for _, t := range m.Threads { 54 | new.Threads = append(new.Threads, t) 55 | } 56 | for k, v := range m.StateMap { 57 | new.StateMap[k] = v 58 | } 59 | return new 60 | } 61 | 62 | func (m *machine2) isSucc() bool { 63 | count := 0 64 | for _, t := range m.Threads { 65 | if t.Nullable() { 66 | count++ 67 | } 68 | } 69 | return count == len(m.Threads) 70 | } 71 | 72 | func (mach *machine2) syncAble() ([]SyncPoint, map[int][]types.R) { 73 | threadNext := make([]nextStr, 0) 74 | opsOnClosed := make([]nextStr, 0) 75 | SelectSp := make(map[int][]types.R) 76 | 77 | for i := range mach.Threads { 78 | tmp := mach.Threads[i].NextSym() 79 | cleanedNext := make([]types.R, 0) 80 | closedOps := make([]types.R, 0) 81 | nextEl := nextStr{ThreadId: i} 82 | nextClEl := nextStr{ThreadId: i} 83 | 84 | for _, x := range tmp { 85 | switch y := x.(type) { 86 | case types.SELECTGROUP: 87 | //fmt.Println("SELECTGROUP") 88 | xa := SelectSp[i] 89 | xa = append(xa, y...) 90 | SelectSp[i] = xa 91 | //fmt.Println(nextEl.SelectSp) 92 | case types.Sym: 93 | isClosed := false 94 | for _, c := range mach.ClosedChannels { 95 | if y == c.(types.Sym) { 96 | isClosed = true 97 | } 98 | } 99 | if !isClosed { 100 | cleanedNext = append(cleanedNext, x) 101 | } else { 102 | closedOps = append(closedOps, x) 103 | } 104 | default: 105 | cleanedNext = append(cleanedNext, x) 106 | } 107 | } 108 | nextEl.Rs = cleanedNext 109 | nextClEl.Rs = closedOps 110 | threadNext = append(threadNext, nextEl) 111 | opsOnClosed = append(opsOnClosed, nextClEl) 112 | //threadNext = append(threadNext, nextStr{i, mach.Threads[i].NextSym()}) 113 | } 114 | 115 | doubleDismiss := make(map[SyncPoint]int) 116 | loopstopper := make([]SyncPoint, 0) 117 | syncpoints := make([]SyncPoint, 0) 118 | for _, n := range threadNext { //for each thread 119 | for _, r := range n.Rs { //for each symbol that the thread can execute next 120 | skip := false 121 | q := r 122 | 123 | //check for closer 124 | isCloser := false 125 | switch vu := r.(type) { 126 | case types.Sym: 127 | _, ok := mach.CMap[vu] 128 | if ok { 129 | syncpoints = append(syncpoints, SyncPoint{n.ThreadId, -42, vu}) 130 | isCloser = true 131 | } 132 | } 133 | 134 | if !skip && !isCloser { 135 | p := mach.PMap[q] 136 | f := false 137 | for _, m := range threadNext { //find a partner thread 138 | if m.ThreadId != n.ThreadId { //shouldn't be itself 139 | if Rscontains(p, m.Rs) { //if 'next' from thread m contains the partner symbol of thread n 140 | tmp := SyncPoint{n.ThreadId, m.ThreadId, q} 141 | f = true 142 | if _, ok := doubleDismiss[tmp]; !ok { 143 | 144 | //check if it would transfer the thread in a new state: 145 | 146 | divtmp1 := mach.Threads[n.ThreadId].Deriv(q) 147 | divtmp2 := mach.Threads[m.ThreadId].Deriv(p) 148 | 149 | _, ok1 := mach.StateMap[types.Seq{types.Phi(n.ThreadId), divtmp1}] 150 | _, ok2 := mach.StateMap[types.Seq{types.Phi(m.ThreadId), divtmp2}] 151 | if !ok1 && !ok2 { 152 | syncpoints = append(syncpoints, tmp) 153 | doubleDismiss[tmp] = 1 154 | tmp2 := SyncPoint{m.ThreadId, n.ThreadId, p} 155 | doubleDismiss[tmp2] = 1 156 | } else { 157 | loopstopper = append(loopstopper, SyncPoint{n.ThreadId, m.ThreadId, q}) 158 | // // mach.Trace += q.String() + p.String() 159 | // mach.Threads[n.ThreadId] = divtmp1 160 | // mach.Threads[m.ThreadId] = divtmp2 161 | // mach.Succ = true 162 | // for _, xx := range mach.Threads { 163 | // if !xx.Nullable() { 164 | // mach.Succ = false 165 | // mach.Stop = true 166 | // } 167 | // } 168 | } 169 | 170 | } 171 | } 172 | } 173 | } 174 | if !f { 175 | syncpoints = append(syncpoints, SyncPoint{n.ThreadId, -1, r}) 176 | } 177 | } 178 | 179 | } 180 | } 181 | 182 | for _, co := range opsOnClosed { 183 | for _, c := range co.Rs { 184 | syncpoints = append(syncpoints, SyncPoint{co.ThreadId, -43, c}) 185 | } 186 | } 187 | 188 | count := 0 189 | for _, s := range syncpoints { 190 | if s.T2Id == -1 { 191 | count++ 192 | } 193 | } 194 | // nothing is executable anymore and there are loopstoppers, deriv the loopstoppers, check if the thread is nullable afterwards 195 | if count == len(syncpoints) && len(loopstopper) > 0 { 196 | mach.Threads[loopstopper[0].T1Id] = mach.Threads[loopstopper[0].T1Id].Deriv(loopstopper[0].Symbol) 197 | p := mach.PMap[loopstopper[0].Symbol] 198 | mach.Threads[loopstopper[0].T2Id] = mach.Threads[loopstopper[0].T2Id].Deriv(p) 199 | mach.Trace += loopstopper[0].Symbol.String() + p.String() 200 | 201 | count2 := 0 202 | for _, t := range mach.Threads { 203 | if t.Nullable() { 204 | count2++ 205 | } 206 | } 207 | if count2 == len(mach.Threads) { 208 | mach.Succ = true 209 | } else { 210 | mach.Stop = true 211 | } 212 | return []SyncPoint{}, SelectSp 213 | } 214 | 215 | return syncpoints, SelectSp 216 | } 217 | func (m *machine2) sync(sp SyncPoint, selectsp map[int][]types.R) { // syncpoint can contain something like Alt{a, SKIP}, first try what happens if SKIP is added, only if it fails add a 218 | if sp.T2Id > -1 { 219 | m.StateMap[types.Seq{types.Phi(sp.T1Id), m.Threads[sp.T1Id]}] = 1 220 | m.StateMap[types.Seq{types.Phi(sp.T2Id), m.Threads[sp.T2Id]}] = 1 221 | 222 | m.Threads[sp.T1Id] = m.Threads[sp.T1Id].Deriv(sp.Symbol) 223 | m.Trace += sp.Symbol.String() 224 | p := m.PMap[sp.Symbol] 225 | m.Threads[sp.T2Id] = m.Threads[sp.T2Id].Deriv(p) 226 | m.Trace += p.String() 227 | 228 | //SPECIAL CASE FOR SELECT 229 | 230 | if len(selectsp[sp.T1Id]) > 0 { 231 | tmp := selectsp[sp.T1Id] 232 | for _, xx := range tmp { 233 | if xx != sp.Symbol { 234 | pa := m.PMap[xx] 235 | 236 | for j := range m.Threads { 237 | nex := m.Threads[j].NextSym() 238 | if Rscontains(pa, nex) { 239 | m.Threads[j] = m.Threads[j].Deriv(pa) 240 | break 241 | } 242 | } 243 | } 244 | } 245 | } else if len(selectsp[sp.T2Id]) > 0 { 246 | tmp := selectsp[sp.T2Id] 247 | for _, xx := range tmp { 248 | if xx != p { 249 | pa := m.PMap[xx] 250 | 251 | for j := range m.Threads { 252 | nex := m.Threads[j].NextSym() 253 | if Rscontains(pa, nex) { 254 | m.Threads[j] = m.Threads[j].Deriv(pa) 255 | break 256 | } 257 | } 258 | } 259 | } 260 | } 261 | m.Succ = m.isSucc() 262 | } else if sp.T2Id == -42 { 263 | // fmt.Println("close case") 264 | m.Trace += sp.Symbol.String() 265 | 266 | m.Threads[sp.T1Id] = m.Threads[sp.T1Id].Deriv(sp.Symbol) 267 | m.ClosedChannels = append(m.ClosedChannels, m.CMap[sp.Symbol]...) 268 | m.Succ = m.isSucc() 269 | } else if sp.T2Id == -43 { 270 | // fmt.Println("op on closed channel") 271 | m.Trace += sp.Symbol.String() 272 | _, ok := m.RMap[sp.Symbol] 273 | if ok { //read on closed channel everythings fine 274 | m.Threads[sp.T1Id] = m.Threads[sp.T1Id].Deriv(sp.Symbol) 275 | m.Succ = m.isSucc() 276 | } else { 277 | m.Stop = true 278 | } 279 | } else { 280 | if sp.Symbol != types.Eps(1) { 281 | m.Trace += sp.Symbol.String() 282 | // m.Threads[sp.T1Id] = m.Threads[sp.T1Id].Deriv(sp.Symbol, sp.T1Id) 283 | m.Stop = true 284 | } 285 | } 286 | } 287 | 288 | func run3(initM machine2) { 289 | //reader := bufio.NewReader(os.Stdin) 290 | 291 | machines := []machine2{initM} 292 | 293 | for { 294 | for i := range machines { 295 | if machines[i].Succ || machines[i].Stop || machines[i].Abort { 296 | continue 297 | } 298 | 299 | syncpoints, selectSp := machines[i].syncAble() 300 | // fmt.Println("SYNCPOINTS", syncpoints, machines[i].Threads, machines[i].Trace) 301 | 302 | if len(syncpoints) == 0 { 303 | machines[i].Stop = true 304 | } else { 305 | for j := range syncpoints { // for each syncpoint, create a clone (but not for the last one) 306 | if j < len(syncpoints)-1 { 307 | clone := machines[i].clone() 308 | clone.sync(syncpoints[j], selectSp) 309 | machines = append(machines, clone) 310 | } else { 311 | machines[i].sync(syncpoints[j], selectSp) 312 | } 313 | } 314 | } 315 | //reader.ReadString('\n') 316 | } 317 | //reader.ReadString('\n') 318 | count := 0 319 | for i := range machines { 320 | if machines[i].Succ || machines[i].Stop || machines[i].Abort { 321 | count++ 322 | } 323 | } 324 | if count == len(machines) { 325 | break 326 | } 327 | } 328 | 329 | fmt.Println("Machines created:", len(machines)) 330 | doubledismiss := make(map[string]int) 331 | stopped, succs, aborted := 0, 0, 0 332 | for i := range machines { 333 | _, ok := doubledismiss[machines[i].Trace] 334 | if !ok && !machines[i].Abort { 335 | fmt.Println(machines[i].Succ, machines[i].Trace, machines[i].Threads) 336 | doubledismiss[machines[i].Trace] = 1 337 | } 338 | if machines[i].Succ { 339 | succs++ 340 | } else if machines[i].Abort { 341 | aborted++ 342 | } else if machines[i].Stop { 343 | stopped++ 344 | } 345 | } 346 | fmt.Printf("Succs: %v\nAbort: %v\nStopped: %v\n", succs, aborted, stopped) 347 | //reader.ReadString('\n') 348 | } 349 | 350 | func run(rs []types.R, filter func(rs []types.R) []types.R, partner map[types.R]types.R) { 351 | //reader := bufio.NewReader(os.Stdin) 352 | 353 | machines := []machine{machine{Rs: rs}} 354 | 355 | for { 356 | for i := range machines { 357 | if machines[i].Succ || machines[i].Stop || machines[i].Abort { 358 | continue 359 | } 360 | 361 | if len(machines[i].Rs) == 0 { 362 | machines[i].Stop = true 363 | } else { 364 | failedRs := 0 365 | // fmt.Println(len(machines[i].Rs)) 366 | for r := range machines[i].Rs { 367 | if machines[i].Rs[r].ContainsPhi() { 368 | continue 369 | } 370 | // succ := false 371 | 372 | next := machines[i].Rs[r].NextSym() 373 | // fmt.Println("next:", next, machines[i].Rs) 374 | // fmt.Println(machines[i].Trace, machines[i].Rs[r], next) 375 | next = filter(next) 376 | // fmt.Println("next2:", next) 377 | 378 | doubleFilter := make(map[types.R]int) 379 | for _, n := range next { 380 | _, ok := doubleFilter[n] 381 | if !ok { 382 | doubleFilter[n] = 1 383 | } 384 | } 385 | next = make([]types.R, 0, len(next)) 386 | for k, _ := range doubleFilter { 387 | next = append(next, k) 388 | } 389 | fmt.Println(next) 390 | for _, vl := range machines[i].Rs { 391 | if !vl.ContainsPhi() { 392 | fmt.Println(vl) 393 | } 394 | } 395 | 396 | if len(next) == 0 { 397 | if machines[i].Rs[r].Nullable() { 398 | machines[i].Succ = true 399 | } else { 400 | failedRs++ 401 | } 402 | } else { 403 | for _, n := range next { 404 | clone := machines[i] 405 | 406 | tmp := make([]types.R, 0) 407 | for k := range clone.Rs { 408 | tmp = append(tmp, clone.Rs[k].PDeriv(n)...) 409 | } 410 | 411 | tmp2 := make([]types.R, 0) 412 | for k := range tmp { 413 | if !tmp[k].ContainsPhi() { 414 | tmp2 = append(tmp2, tmp[k].PDeriv(partner[n])...) 415 | } 416 | //tmp2 = append(tmp2, tmp[k].PDeriv(partner[n])...) 417 | } 418 | 419 | for _, t := range tmp2 { 420 | if t.Nullable() { 421 | // succ = true 422 | clone.Succ = true 423 | } 424 | // if !t.ContainsPhi() { 425 | // clone.Rs = append(clone.Rs, t) 426 | // } 427 | } 428 | clone.Rs = tmp2 429 | clone.Trace += n.String() + partner[n].String() 430 | machines = append(machines, clone) 431 | } 432 | } 433 | } 434 | if failedRs == len(machines[i].Rs) { 435 | machines[i].Stop = true 436 | } else { 437 | machines[i].Abort = true 438 | } 439 | 440 | // machines[i].Stop = true 441 | } 442 | // reader.ReadString('\n') 443 | } 444 | 445 | count := 0 446 | 447 | for i := range machines { 448 | if machines[i].Succ || machines[i].Stop || machines[i].Abort { 449 | count++ 450 | } 451 | } 452 | if count == len(machines) { 453 | break 454 | } 455 | } 456 | 457 | fmt.Println(len(machines)) 458 | doubledismiss := make(map[string]int) 459 | stopped, succs, aborted := 0, 0, 0 460 | for i := range machines { 461 | // fmt.Println(machines[i].Rs) 462 | _, ok := doubledismiss[machines[i].Trace] 463 | if !ok && !machines[i].Abort { 464 | fmt.Println(machines[i].Succ, machines[i].Trace, machines[i].Rs[0]) 465 | doubledismiss[machines[i].Trace] = 1 466 | } 467 | if machines[i].Succ { 468 | succs++ 469 | } else if machines[i].Abort { 470 | aborted++ 471 | } else if machines[i].Stop { 472 | stopped++ 473 | } 474 | } 475 | fmt.Printf("Succs: %v\nAborted: %v\nStopped: %v\n", succs, aborted, stopped) 476 | // reader.ReadString('\n') 477 | } 478 | 479 | func Run(r types.R, pmap map[types.R]types.R) { 480 | partnerFilter := func(rs []types.R) (ret []types.R) { 481 | ret = make([]types.R, 0) 482 | doubleDismiss := make(map[types.R]int) 483 | for _, e := range rs { 484 | if _, ok := doubleDismiss[e]; !ok { 485 | p := pmap[e] 486 | for _, r := range rs { 487 | if r == p { 488 | ret = append(ret, e) 489 | doubleDismiss[e] = 1 490 | doubleDismiss[r] = 1 491 | break 492 | } 493 | } 494 | } 495 | 496 | } 497 | return 498 | } 499 | 500 | run([]types.R{r}, partnerFilter, pmap) 501 | } 502 | 503 | func Run2(threads []types.R, pmap map[types.R]types.R, cmap map[types.R][]types.R, rmap map[types.R]int) { 504 | m := machine2{Threads: threads, PMap: pmap, CMap: cmap, StateMap: make(map[types.R]int), 505 | ClosedChannels: make([]types.R, 0), RMap: rmap} 506 | run3(m) 507 | } 508 | --------------------------------------------------------------------------------