├── .gitignore ├── BACKUP.md ├── Makefile ├── README.md ├── basics ├── README.md ├── complex │ └── complex.go ├── exceptions │ └── exeptions.go ├── flags │ └── main.go ├── hello │ └── main.go ├── index │ ├── index.go │ └── index_test.go ├── palindrome │ ├── palindrome.go │ └── palindrome_test.go ├── sorting │ └── main.go ├── swap │ └── main.go └── types │ ├── list │ └── lists.go │ ├── simpletypes.go │ ├── slicecap │ └── slicecap.go │ ├── slices │ ├── slices.go │ └── slices_test.go │ └── strings │ ├── strings.go │ └── strings_test.go ├── bp ├── antlr │ ├── Bool.g4 │ ├── Bool.interp │ ├── Bool.tokens │ ├── BoolLexer.interp │ ├── BoolLexer.tokens │ ├── bool_base_listener.go │ ├── bool_evaluator.go │ ├── bool_lexer.go │ ├── bool_listener.go │ └── bool_parser.go ├── ast │ └── ast.go ├── lexer │ ├── lexer.go │ └── lexer_test.go ├── main.go └── parser │ ├── parser.go │ └── parser_test.go ├── cp ├── README.md ├── channels │ ├── blockingqueue │ │ ├── blockingqueue.go │ │ └── blockingqueue_test.go │ ├── deadlock │ │ └── main.go │ ├── fan │ │ ├── fanin.go │ │ ├── fanin_test.go │ │ ├── fanout.go │ │ └── fanout_test.go │ ├── fibonacci │ │ └── main.go │ ├── lecturer │ │ ├── lecturer1 │ │ │ └── main.go │ │ ├── lecturer2 │ │ │ └── main.go │ │ ├── lecturer3 │ │ │ └── main.go │ │ ├── lecturer4 │ │ │ └── main.go │ │ ├── lecturer5 │ │ │ └── main.go │ │ ├── lecturer6 │ │ │ └── main.go │ │ └── lecturer7 │ │ │ └── main.go │ ├── philosophers │ │ ├── philosophers.go │ │ ├── philosophers_test.go │ │ └── table.go │ ├── pingpong │ │ └── pingpong.go │ └── timeout │ │ └── main.go └── locks │ ├── README.md │ ├── blockingqueue │ ├── blockingqueue.go │ └── blockingqueue_test.go │ ├── philosophers │ ├── philosophers.go │ ├── philosophers_test.go │ └── table.go │ └── resourcemanager │ ├── README.md │ ├── resourcegraph.go │ ├── resourcegraph_test.go │ └── resourcemanager.go ├── docs ├── 01-1-About.pdf ├── 01-1-About.slide ├── 01-2-Overview.pdf ├── 01-2-Overview.slide ├── 01-3-Introduction to Golang.pdf ├── 01-3-Introduction to Golang.slide ├── 02-Go Programming - Basics and OOP.pdf ├── 02-Go Programming - Basics and OOP.slide ├── 03-Go-Programming-OOP.pdf ├── 03-Go-Programming-OOP.slide ├── 04-Go-Programming-Parser.pdf ├── 04-Go-Programming-Parser.slide ├── 05-Functional-Programming.pdf ├── 05-Functional-Programming.slide ├── 06-Concurrent-Programming.pdf ├── 06-Concurrent-Programming.slide ├── 07-Distributed-Programming-Raft.pdf ├── 07-Distributed-Programming-Raft.slide ├── 08-WebAssembly.pdf ├── 08-WebAssembly.slide ├── 09-Systems-Programming.pdf ├── 09-Systems-Programming.slide ├── 10-Enterprise-Programming-Modules.pdf ├── 10-Enterprise-Programming-Modules.slide ├── 11-Logic-Programming.pdf ├── 11-Logic-Programming.slide ├── README.md ├── exercises │ ├── Exercise1.md │ ├── Exercise10.md │ ├── Exercise11.md │ ├── Exercise2.1.md │ ├── Exercise2.2.md │ ├── Exercise3.md │ ├── Exercise4.md │ ├── Exercise5.md │ ├── Exercise6.md │ ├── Exercise7.md │ ├── Exercise8.md │ ├── Exercise9.md │ └── exercise-1 │ │ ├── Windows │ │ ├── codebase │ │ │ ├── bin │ │ │ │ └── .gitkeep │ │ │ ├── pkg │ │ │ │ └── .gitkeep │ │ │ └── src │ │ │ │ └── .gitkeep │ │ └── software │ │ │ ├── ascii-art.txt │ │ │ ├── set-env.cmd │ │ │ └── start-console.cmd │ │ └── macOS │ │ ├── .zshrc │ │ ├── codebase │ │ ├── bin │ │ │ └── .gitkeep │ │ ├── pkg │ │ │ └── .gitkeep │ │ └── src │ │ │ └── .gitkeep │ │ └── software │ │ ├── ascii-art.txt │ │ ├── set-env │ │ └── start-console ├── img │ ├── 00-programming-languages.jpeg │ ├── 01-cncf-projects.png │ ├── 01-exercise.png │ ├── 01-go-programming-language.png │ ├── 01-languages.png │ ├── 02-complex.png │ ├── 02-exercise.png │ ├── 03-exercise.key │ ├── 03-exercise.png │ ├── 04-lambda.key │ ├── 04-lambda.png │ ├── 04-parsers │ │ ├── 01-practice-go.gif │ │ ├── 02-menti.png │ │ ├── 02-parsers-for-what.png │ │ ├── 03-parsers-overview.png │ │ ├── 04-ast-vs-cst.png │ │ ├── 05-tree-terms.png │ │ ├── 05-whaat.gif │ │ ├── Parsers.006.png │ │ ├── Parsers.007.png │ │ ├── Parsers.008.png │ │ ├── Parsers.009.png │ │ ├── Parsers.010.png │ │ ├── Parsers.011.png │ │ └── programming.png │ ├── 05-alternative.svg │ ├── 05-ast.svg │ ├── 05-concatenation.svg │ ├── 05-input-is-text.svg │ ├── 05-number-grammar.svg │ ├── 05-once-or-more.svg │ ├── 05-optional.svg │ ├── 05-os-file.svg │ ├── 05-parser-is-function.svg │ ├── 05-repetition.svg │ ├── 05-result-is-anything.svg │ ├── 05-rune-array.svg │ ├── 05-strings-are-bytes.svg │ ├── 06-dining-philosophers.png │ ├── 06-go-concurrency.jpeg │ ├── 06-moores-law.png │ ├── 06-philosophers-channel.jpeg │ ├── 06-philosophers-channel.key │ ├── 07-idserv.png │ ├── 07-parallel-distributed.key │ ├── 07-parallel-distributed.png │ ├── 07-proxy-pattern.png │ ├── 08-webassembly │ │ ├── 01-01-mvp-03-final-e1539905426663-768x664.png │ │ ├── 01-02-heavyweight-03-P-07-e1540219610872-768x551.png │ │ ├── 01-02-heavyweight-04-final-e1540219657102-768x696.png │ │ ├── 01-04-js-interop-00-A-768x432.png │ │ ├── 01-04-js-interop-02-P-05-e1540220264112-768x395.png │ │ ├── 01-04-js-interop-03-final-e1540220313636-768x415.png │ │ ├── 01-05-high-level-03-P-04-e1540220662110-768x240.png │ │ ├── 01-05-high-level-04-final-e1540220704600-768x621.png │ │ ├── 01-07-runtime-09-final-e1539904436477-768x489.png │ │ ├── 0a-all-browsers.png │ │ ├── 0a-bytecode.png │ │ ├── 0a-javascript-compilation.png │ │ ├── 0a-portability.png │ │ └── 0a-webassembly-compilation.png │ ├── 10-buildlist.svg │ ├── 10-conflicting-versions.png │ └── go.png ├── snippets │ └── cp ├── studywork │ ├── COP_Kotlin_Stefan_Bialek_.adoc │ ├── CoProgrammingLanguage.adoc │ ├── README.md │ ├── Study-Work-Presentation.pdf │ ├── Study-Work-Presentation.slide │ ├── StudyWork.xlsx │ ├── paper.md │ ├── psta.md │ └── studywork.slide └── talks │ └── raft │ ├── Implementing Raft.pptx │ └── Implementing-Raft.slide ├── dp ├── idserv │ ├── Makefile │ ├── client │ │ └── main.go │ ├── core │ │ └── idserv-impl.go │ ├── idserv-api.go │ └── remote │ │ ├── idserv │ │ ├── idserv.pb.go │ │ └── idserv.proto │ │ ├── proxy │ │ └── proxy.go │ │ ├── server │ │ └── main.go │ │ └── stub │ │ └── idserv-stub.go ├── kvstore │ ├── Makefile │ ├── README.md │ ├── core │ │ ├── kvstore-impl.go │ │ └── raft │ │ │ ├── cluster.go │ │ │ ├── cluster_test.go │ │ │ ├── configuration.go │ │ │ ├── node-utils.go │ │ │ ├── node.go │ │ │ ├── node_test.go │ │ │ ├── noderpc.go │ │ │ ├── replicatedlog.go │ │ │ ├── statemachine.go │ │ │ └── timer_test.go │ ├── kvstore-api.go │ └── remote │ │ ├── dkvs.go │ │ ├── proxy.go │ │ └── stub.go └── raft │ ├── Makefile │ ├── main.go │ └── node │ ├── node.go │ ├── node.pb.go │ ├── node.proto │ └── node_grpc.pb.go ├── fp ├── clojures │ └── main.go ├── composition │ └── main.go ├── functions │ └── main.go ├── lambdacalculus │ └── main.go ├── mockingbird │ └── main.go ├── parser │ ├── boolparser.go │ ├── boolparser_test.go │ └── parser.go ├── streams │ ├── streams.go │ └── streams_test.go └── successor │ └── main.go ├── go.mod ├── go.sum ├── library ├── Makefile ├── main.go ├── mylib.c └── mylib.h ├── logic ├── age.pl ├── cannibals.pl ├── einstein.pl ├── family.pl ├── hanoi.pl ├── juliet.pl ├── map.pl ├── palindrome.pl └── river.pl ├── modules ├── Dockerfile ├── client │ ├── client.go │ ├── go.mod │ └── go.sum ├── mail │ ├── api.go │ ├── go.mod │ ├── go.sum │ ├── impl.go │ └── v2 │ │ ├── api.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── impl.go └── plugin │ ├── go.mod │ ├── go.sum │ └── plugin.go ├── oop ├── boolparser │ ├── ast │ │ ├── ast.go │ │ └── ast_test.go │ ├── lexer │ │ ├── lexer.go │ │ └── lexer_test.go │ └── parser │ │ ├── parser.go │ │ └── parser_test.go ├── delegation │ └── delegation.go ├── embedding │ └── embedding.go ├── geometry │ ├── geoobject │ │ ├── geoobject.go │ │ ├── ggpainter.go │ │ └── stringpainter.go │ └── main.go ├── mail │ ├── client │ │ ├── client.go │ │ └── client_test.go │ ├── mail.go │ ├── smtp │ │ └── sender.go │ └── util │ │ └── registry.go ├── multi │ └── multi.go ├── polymorphism │ └── polymorphism.go ├── rational │ ├── rational.go │ └── rational_test.go ├── rational2 │ ├── rational.go │ └── rational_test.go └── stack │ ├── stack.go │ └── stack_test.go ├── plugin ├── Makefile ├── master.go └── plugin.go ├── raft └── raft.go ├── servers ├── fileserver │ └── main.go └── server │ └── server.go ├── sp ├── container │ ├── container.go │ ├── container_simple1.go │ ├── container_simple2.go │ ├── container_simple3.go │ └── container_simple4.go ├── empty.go └── samples │ ├── os │ └── pid.go │ ├── random │ └── main.go │ ├── sqlite │ ├── cfuncs.go │ └── sqlite.go │ └── syscall │ └── pid.go └── webassembly ├── C ├── add │ ├── add.c │ ├── add.js │ └── compile.sh └── memory_math │ ├── compile.sh │ ├── foo.c │ └── foo.js ├── docker ├── Dockerfile └── README.md ├── go ├── call │ ├── compile.sh │ ├── index.html │ └── main.go ├── hello │ ├── compile.sh │ ├── index.html │ └── main.go ├── mandelbrot │ └── main.go └── mandelbrot_wasm │ ├── compile.sh │ ├── index.html │ └── main.go └── wat ├── add.js ├── add.wasm ├── add.wat ├── compile.sh └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | **/coverage.out 2 | docs/exercises/StudyWork.xlsx 3 | .idea/ 4 | *.iml 5 | .vscode/ 6 | **/.DS_Store 7 | 8 | /plugin/plugin.so 9 | /plugin/master 10 | /plugin/master.exe 11 | 12 | /library/libmylib.so 13 | /library/libmylib.a 14 | /library/mylib.o 15 | /library/main 16 | 17 | /modules/**/client 18 | /modules/**/client.exe 19 | /modules/**/plugin.so 20 | -------------------------------------------------------------------------------- /BACKUP.md: -------------------------------------------------------------------------------- 1 | 2 | ## Lecture 2 - Basics in Go Programming, OOP Part I 3 | 4 | - Pointer, Arrays, Maps, Object Oriented Programming 5 | - Reasons for Go https://www.youtube.com/watch?v=5kj5ApnhPAE 6 | - Swap, Index, Rational Numbers, Containers 7 | 8 | ## Lecture 3 - Object Oriented Programming in Go 9 | 10 | - Structs, Interfaces, Embedding, Polymorphism 11 | 12 | ## Lecture 4 - Functional Programming and the Lambda Calculus 13 | - Functional Programming 14 | - Lambda Calculus 15 | - Streams in Go 16 | 17 | ## Lecture 5 - Functional Parsers 18 | - What is a Parser? 19 | - Functional Parsers and Parser Combinators 20 | - Building a Parser in Go 21 | 22 | ## Lecture 6 - Concurrent Programming 23 | - Why concurrent programming matters! 24 | - Go routines and channels 25 | - Go concurrency patterns 26 | - The dining philosophers problem 27 | 28 | ## Lecture 7 - Concurrent Programming - Part II 29 | - Deadlocks and Detection 30 | - The Resource Access Graph 31 | - Building a Resource Manager 32 | 33 | ## Lecture 8 - Distributed Programming 34 | - Introduction 35 | - Sockets and low level programming 36 | - RPC and GRPC 37 | - ID generator with GRPC 38 | 39 | ## Lecture 9 - Distributed Programming - The Raft Protocol 40 | - Introduction into Consensus Protocols 41 | - Raft 42 | - Implementing Raft with Go 43 | 44 | ## Lecture 10 - Modules and Versioning 45 | - Introduction into Go 1.11 Modules 46 | - Implementing Modules 47 | 48 | ## Lecture 11 - System Programming 49 | - What is System Programming? 50 | - Calling C 51 | - Implementing Docker 52 | 53 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Standard Makefile. Usage: make . Exclude raft package (slow tests!) 3 | # 4 | PKGS := $(shell go list ./... | grep -v /raft) 5 | 6 | .PHONY: test all build test install clean slideshow help coverage 7 | 8 | help: 9 | clear 10 | @echo "---------------------------------------------------------------------------------------------------------" 11 | @echo "Usage: make " 12 | @echo "---------------------------------------------------------------------------------------------------------" 13 | @echo "Valid targets are:" 14 | @echo " make all : Runs build, test, install." 15 | @echo " make build : Builds all packages." 16 | @echo " make test : Runs all tests." 17 | @echo " make install : Installs all packages." 18 | @echo " make clean : Clean up and clears caches." 19 | @echo " make coverage : Executes the tests with coverage and starts the go tool cover" 20 | @echo " make slideshow : Starts a golang present slideshow on port 3999. Blocks until CTRL-C ist pressed. " 21 | @echo " make help : This info. " 22 | @echo "---------------------------------------------------------------------------------------------------------" 23 | 24 | test: 25 | go test $(PKGS) 26 | 27 | build: 28 | go build $(PKGS) 29 | 30 | install: 31 | go install $(PKGS) 32 | 33 | clean: 34 | go clean -testcache -cache $(PKGS) 35 | 36 | all: build test install 37 | 38 | coverage: 39 | go test -coverprofile=coverage.out $(PKGS) 40 | go tool cover -html=coverage.out 41 | 42 | slideshow: 43 | cd docs; present -notes 44 | -------------------------------------------------------------------------------- /basics/README.md: -------------------------------------------------------------------------------- 1 | # Basics 2 | 3 | - Exceptions - Java like exception handling based on panic, defer and recover 4 | - Flags for command line applications 5 | - Hello World (UTF-8) 6 | - Inverted index with maps and strings (book index example) 7 | - Palindrome with strings and runes (UTF-8 safe) 8 | - Sorting of custom types 9 | - Swap with Pointers 10 | - Types: Primitive types, maps, strings and slices 11 | -------------------------------------------------------------------------------- /basics/complex/complex.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/cmplx" 6 | ) 7 | 8 | func main() { 9 | c := 3 + 4i 10 | fmt.Printf("c=%v\n", c) 11 | r, θ := cmplx.Polar(c) 12 | fmt.Printf("r=%v, θ=%v\n", r, θ) 13 | } 14 | -------------------------------------------------------------------------------- /basics/exceptions/exeptions.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // TryCatchBlock is a codeblock with a try and optional catch, finally clause. 8 | type TryCatchBlock struct { 9 | T func() 10 | C func(Exception) 11 | F func() 12 | } 13 | 14 | // Exception is a Exception type. 15 | type Exception interface{} 16 | 17 | // Throw is a alias for panic. 18 | func Throw(up Exception) { 19 | panic(up) 20 | } 21 | 22 | // Do does call the try function als installs a catch and finally handler. 23 | func (tcf TryCatchBlock) Do() { 24 | if tcf.F != nil { 25 | defer tcf.F() 26 | } 27 | if tcf.C != nil { 28 | defer func() { 29 | if r := recover(); r != nil { 30 | tcf.C(r) 31 | } 32 | }() 33 | } 34 | tcf.T() 35 | } 36 | 37 | // TryCatch helper for a better syntax. 38 | func TryCatch(t func(), c func(ex Exception), f func()) { 39 | TryCatchBlock{T: t, C: c, F: f}.Do() 40 | } 41 | 42 | // Test exception handling. 43 | func main() { 44 | 45 | fmt.Println("Starting ...") 46 | 47 | TryCatch( 48 | func() { 49 | fmt.Println("Trying ...") 50 | Throw("Some Exception") // throws an exception 51 | }, 52 | func(e Exception) { 53 | fmt.Printf("Caught %v\n", e) 54 | }, 55 | func() { 56 | fmt.Println("Finally...") 57 | }) 58 | fmt.Println("Shutdown gracefully") 59 | } 60 | -------------------------------------------------------------------------------- /basics/flags/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | package main 5 | 6 | import ( 7 | "flag" 8 | "fmt" 9 | ) 10 | 11 | // Simple test for the Go flag API. 12 | func main() { 13 | // construct a string flag with a default ip address and a description. 14 | ip := flag.String("ip", "192.168.1.1", "Overrides the default IP address.") 15 | port := flag.String("port", "8080", "Overrides the default listen port.") 16 | 17 | // flag.Args() parses the arg of our program. 18 | if len(flag.Args()) == 0 { 19 | fmt.Printf("Program Usage:\n") 20 | // PrintDefaults() prints a description and the default values to stdout. 21 | flag.PrintDefaults() 22 | } 23 | 24 | flag.Parse() 25 | 26 | fmt.Println("\nDefault value for IP: " + *ip) 27 | fmt.Println("\nDefault value for port: " + *port) 28 | } 29 | 30 | // END OMIT 31 | -------------------------------------------------------------------------------- /basics/hello/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | package main 5 | 6 | import "fmt" 7 | 8 | func main() { 9 | fmt.Printf("Hello %s", "Programming with Go \xE2\x98\xAF\n") // \xE2\x98\xAF -> ☯ 10 | fmt.Printf("Hello %s", "Programming with Go ☯\n") 11 | } 12 | -------------------------------------------------------------------------------- /basics/index/index.go: -------------------------------------------------------------------------------- 1 | // Package index makes a book index out of pages. 2 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 3 | // Licensed under the Apache License, Version 2.0 4 | package index 5 | 6 | import "fmt" 7 | 8 | // Page contains an array of words. 9 | type Page []string 10 | 11 | // Book is an array of pages. 12 | type Book []Page 13 | 14 | // Index contains a list of pages for each word in a book. 15 | type Index map[string][]int 16 | 17 | // MakeIndex generates an index structure 18 | func MakeIndex(book Book) Index { 19 | idx := make(Index) 20 | for i, page := range book { 21 | for _, word := range page { 22 | pages := idx[word] 23 | idx[word] = append(pages, i) 24 | } 25 | } 26 | return idx 27 | } 28 | 29 | // Stringer support 30 | func (idx Index) String() string { 31 | result := "" 32 | for k, v := range idx { 33 | result += fmt.Sprintf("\n\tWord: %v : Pages: %v", k, v) 34 | } 35 | return result + "\n" 36 | } 37 | 38 | // MakePage constructs a page from a string array. 39 | func MakePage(words []string) Page { 40 | page := new(Page) 41 | *page = words 42 | return *page 43 | } 44 | 45 | // MakeBook constructs a book from a page array. 46 | func MakeBook(pages []Page) Book { 47 | book := new(Book) 48 | *book = pages 49 | return *book 50 | } 51 | -------------------------------------------------------------------------------- /basics/index/index_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | package index 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | ) 10 | 11 | func TestIndex(t *testing.T) { 12 | 13 | // prepare book 14 | p1 := MakePage([]string{"A", "A", "B", "C"}) 15 | p2 := MakePage([]string{"A", "C", "D"}) 16 | p3 := MakePage([]string{"A", "B", "D"}) 17 | book := MakeBook([]Page{p1, p2, p3}) 18 | 19 | // calculate index 20 | idx := MakeIndex(book) 21 | 22 | // stringer support => not automated 23 | fmt.Printf("Index: %v", idx) 24 | } 25 | -------------------------------------------------------------------------------- /basics/palindrome/palindrome.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package palindrome implements multiple functions for palindromes. 5 | package palindrome 6 | 7 | import "github.com/0xqab/concepts-of-programming-languages/basics/types/strings" 8 | 9 | // IsPalindrome implementation. Does only work for 1-Byte UTF-8 chars (ASCII). 10 | func IsPalindrome(word string) bool { 11 | for pos := 0; pos < len(word)/2; pos++ { 12 | if word[pos] != word[len(word)-pos-1] { 13 | return false 14 | } 15 | } 16 | return true 17 | } 18 | 19 | // END1 OMIT 20 | 21 | // IsPalindrome2 is using runes. This works for all UTF-8 chars (SBC, MBC). 22 | func IsPalindrome2(word string) bool { 23 | var runes = []rune(word) 24 | for pos, ch := range runes { 25 | if ch != runes[len(runes)-pos-1] { 26 | return false 27 | } 28 | } 29 | return true 30 | } 31 | 32 | // END2 OMIT 33 | 34 | // IsPalindrome3 is implemented by reusing Reverse(). Reverse works for UTF-8 chars. 35 | func IsPalindrome3(word string) bool { 36 | return strings.Reverse(word) == word 37 | } 38 | 39 | // END3 OMIT 40 | -------------------------------------------------------------------------------- /basics/palindrome/palindrome_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | package palindrome 5 | 6 | import "testing" 7 | 8 | //START OMIT 9 | // palindrome_test.go 10 | func TestPalindrome(t *testing.T) { 11 | if !IsPalindrome("") { 12 | t.Error("isPalindrome('' should be true. But is false.") 13 | } 14 | if !IsPalindrome("o") { 15 | t.Error("isPalindrome('o' should be true. But is false.") 16 | } 17 | if !IsPalindrome("oto") { 18 | t.Error("isPalindrome('oto' should be true. But is false.") 19 | } 20 | if IsPalindrome("ottos") { 21 | t.Error("isPalindrome('ottos' should be false. But is true.") 22 | } 23 | //END OMIT 24 | } 25 | 26 | func TestPalindrome2(t *testing.T) { 27 | testPalindromeUTF8(t, IsPalindrome2) 28 | } 29 | 30 | func TestPalindrome3(t *testing.T) { 31 | testPalindromeUTF8(t, IsPalindrome3) 32 | } 33 | 34 | func testPalindromeUTF8(t *testing.T, isPalindrome func(word string) bool) { 35 | if !isPalindrome("☯otto☯") { 36 | t.Error("isPalindrome('☯otto☯' should be true. But is false.") 37 | } 38 | if !isPalindrome("") { 39 | t.Error("isPalindrome(Empty string should be a palindrome. But is not. Method returns false.") 40 | } 41 | if !isPalindrome("o") { 42 | t.Error("isPalindrome('o' should be true. But is false.") 43 | } 44 | if !isPalindrome("oto") { 45 | t.Error("isPalindrome('oto' should be true. But is false.") 46 | } 47 | if isPalindrome("ottos") { 48 | t.Error("isPalindrome('ottos' should be false. But is true.") 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /basics/sorting/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "sort" 6 | ) 7 | 8 | // AxisSorter sorts planets by axis. 9 | type AxisSorter []Planet 10 | 11 | func (a AxisSorter) Len() int { return len(a) } 12 | func (a AxisSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 13 | func (a AxisSorter) Less(i, j int) bool { return a[i].Axis < a[j].Axis } 14 | 15 | // NameSorter sorts planets by name. 16 | type NameSorter []Planet 17 | 18 | func (a NameSorter) Len() int { return len(a) } 19 | func (a NameSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } 20 | func (a NameSorter) Less(i, j int) bool { return a[i].Name < a[j].Name } 21 | 22 | // Planet represents a planet in our solarsystem. 23 | type Planet struct { 24 | Name string `json:"name"` 25 | Aphelion float64 `json:"aphelion"` // in million km 26 | Perihelion float64 `json:"perihelion"` // in million km 27 | Axis int64 `json:"axis"` // in km 28 | Radius float64 `json:"radius"` 29 | } 30 | 31 | func main() { 32 | var mars Planet 33 | mars.Name = "Mars" 34 | mars.Aphelion = 249.2 35 | mars.Perihelion = 206.7 36 | mars.Axis = 227939100 37 | mars.Radius = 3389.5 38 | 39 | var earth Planet 40 | earth.Name = "Earth" 41 | earth.Aphelion = 151.930 42 | earth.Perihelion = 147.095 43 | earth.Axis = 149598261 44 | earth.Radius = 6371.0 45 | 46 | var venus Planet 47 | venus.Name = "Venus" 48 | venus.Aphelion = 108.939 49 | venus.Perihelion = 107.477 50 | venus.Axis = 108208000 51 | venus.Radius = 6051.8 52 | 53 | planets := []Planet{mars, venus, earth} 54 | log.Println("unsorted:", planets) 55 | 56 | sort.Sort(AxisSorter(planets)) 57 | log.Println("by axis:", planets) 58 | 59 | sort.Sort(NameSorter(planets)) 60 | log.Println("by name:", planets) 61 | } 62 | -------------------------------------------------------------------------------- /basics/swap/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | package main 5 | 6 | import "fmt" 7 | 8 | func main() { 9 | var a, b = 1, 2 10 | fmt.Printf("Initial : a=%d, b=%d\n", a, b) 11 | a, b = b, a 12 | fmt.Printf("After a,b = b,a : a=%d, b=%d\n", a, b) 13 | swap0 := func(x, y int) (int, int) { 14 | return y, x 15 | } 16 | a, b = swap0(a, b) 17 | fmt.Printf("After a,b = swap0(a,b) : a=%d, b=%d\n", a, b) 18 | swap1(a, b) 19 | fmt.Printf("After swap1(a,b) : a=%d, b=%d\n", a, b) 20 | swap2(&a, &b) 21 | fmt.Printf("After swap2(&a,&b) : a=%d, b=%d\n", a, b) 22 | pa, pb := &a, &b 23 | swap3(&pa, &pb) 24 | fmt.Printf("After swap3(&pa, &pb): a=%d, b=%d, *pa=%v, *pb=%v\n", a, b, *pa, *pb) 25 | } 26 | 27 | // END0 OMIT 28 | 29 | func swap1(x, y int) { 30 | x, y = y, x 31 | } 32 | 33 | // END1 OMIT 34 | 35 | func swap2(x *int, y *int) { 36 | *x, *y = *y, *x 37 | } 38 | 39 | // END2 OMIT 40 | 41 | func swap3(x **int, y **int) { 42 | *x, *y = *y, *x 43 | } 44 | 45 | // END3 OMIT 46 | -------------------------------------------------------------------------------- /basics/types/list/lists.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 by Johannes Siedersleben 2 | // 04.07.2018 3 | 4 | package main 5 | 6 | import ( 7 | "container/list" 8 | "fmt" 9 | ) 10 | 11 | func main() { 12 | var xs = list.New() 13 | for i := 0; i < 10; i++ { 14 | xs.PushBack(i+1000) 15 | } 16 | 17 | var x list.Element 18 | x.Value = 7 19 | 20 | var y *list.Element 21 | y = xs.Front() 22 | fmt.Println(y.Value) 23 | 24 | var sum int 25 | for x := xs.Front(); x != nil; x = x.Next() { 26 | sum += x.Value.(int) 27 | } 28 | 29 | fmt.Print(sum) 30 | } 31 | -------------------------------------------------------------------------------- /basics/types/simpletypes.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 by Johannes Siedersleben 2 | // 29.06.2018 3 | 4 | package main 5 | 6 | import ( 7 | "fmt" 8 | "math" 9 | ) 10 | 11 | func nop(x int) {} // no effect 12 | func add(x, y int) int { return x + y } 13 | func addp(px, py *int) int { return *px + *py } // adds what px, py are pointing to 14 | func swap(px, py *int) { *px, *py = *py, *px } // swaps what px, py are pointing to 15 | func swapp(ppx, ppy **int) { *ppx, *ppy = *ppy, *ppx } // swaps what ppx, ppy are pointing to 16 | 17 | // Integer is an alias for int. 18 | type Integer = int 19 | 20 | // Int is struct containing an int value. 21 | type Int struct { 22 | value Integer 23 | } 24 | 25 | var m = 400 26 | 27 | // Automatic increment per line with iota 28 | const ( 29 | zero = iota 30 | one 31 | two 32 | ) 33 | 34 | func id(x *int) *int { return x } 35 | func add500() { m += 500 } 36 | func inc(x *int) { *x++ } 37 | 38 | func (x Int) Add(y Int) Int { return NewInt(x.value + y.value) } 39 | func NewInt(value int) Int { var v = new(Int); v.value = value; return *v } 40 | func Add(x, y Integer) Integer { return x + y } 41 | func Exec(f func()) { f() } 42 | func Execl(f func(int), arg int) { f(arg) } 43 | 44 | func main() { 45 | var c = nop 46 | var a = 6 47 | 48 | const z complex64 = complex(100, 200) 49 | const pi = math.Pi 50 | fmt.Println(real(z), imag(z), pi) 51 | 52 | c(a) // calls nop 53 | Exec(add500) // calls add500, m = 900 54 | fmt.Println(m) 55 | Execl(func(x int) { fmt.Println(x) }, 7777) // prints 7777 56 | 57 | inc(&a) 58 | fmt.Println(a) // 7 59 | a = 6 60 | b := 8 61 | b = 9 62 | fmt.Println(a, b) // 6, 9 63 | swap(&a, &b) // &a, &b unchanged, a, b swapped 64 | fmt.Println(a, b) // 9, 6 65 | 66 | var q = id(&a) 67 | fmt.Println(*q) // *q = 9 68 | 69 | var r = NewInt(78) 70 | var s = NewInt(43) 71 | var t = r.Add(s) 72 | fmt.Println(t) // {121} 73 | 74 | var u = 29 75 | var v = 67 76 | var w = Add(u, v) 77 | fmt.Println(w) 78 | 79 | pa := &a // *pa == a 80 | pb := &b // *pb == b 81 | swap(pa, pb) // a, b swapped 82 | fmt.Println(a, b) // 6, 9 83 | 84 | swap(&a, &b) // a, b swapped 85 | fmt.Println(*pa, *pb) // 9, 6 86 | 87 | ppa := &pa 88 | ppb := &pb 89 | swapp(ppa, ppb) // pa, pb swapped, a, b untouched 90 | fmt.Println(*pa, *pb) // 6, 9 91 | fmt.Println(a, b) // 9, 6 92 | 93 | fmt.Println(add(a, b)) 94 | fmt.Println(addp(&a, &b)) 95 | 96 | xs := []int{11, 22, 33} 97 | var sum int 98 | for _, x := range xs { 99 | sum += x 100 | } 101 | fmt.Println(sum) 102 | } 103 | -------------------------------------------------------------------------------- /basics/types/slicecap/slicecap.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | var slice []int 7 | capBefore := 1 8 | for i := 0; i < 1e7; i++ { 9 | slice = append(slice, i) 10 | capAfter := cap(slice) 11 | if capAfter != capBefore { 12 | percent := 100 * float64(capAfter) / float64(capBefore) 13 | fmt.Printf("Cap increased from %d -> %d (by %f%%) at len %d\n", 14 | capBefore, capAfter, percent, len(slice)) 15 | capBefore = capAfter 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /basics/types/slices/slices.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | package slices 4 | -------------------------------------------------------------------------------- /basics/types/slices/slices_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | package slices 4 | 5 | import ( 6 | "fmt" 7 | "testing" 8 | ) 9 | 10 | func TestSliceAppend(t *testing.T) { 11 | array := [2]string{"A", "B"} 12 | slice := array[:] // slice the array 13 | fmt.Printf("Slice: %v, Capacity: %v, Length: %v\n", slice, cap(slice), len(slice)) 14 | 15 | // append() does not work for arrays, only for slices. 16 | slice = append(slice, "C") 17 | fmt.Printf("Slice: %v, Capacity: %v, Length: %v\n", slice, cap(slice), len(slice)) 18 | slice = append(slice, "D") 19 | slice = append(slice, "E") 20 | fmt.Printf("Slice: %v, Capacity: %v, Length: %v\n", slice, cap(slice), len(slice)) 21 | } 22 | 23 | func TestSliceCopy(t *testing.T) { 24 | array := [2]string{"A", "B"} 25 | slice := array[:1] // slice the array 26 | fmt.Printf("Array: %p\n", &array) 27 | fmt.Printf("Slice: %p\n", slice) 28 | slice1 := slice 29 | fmt.Printf("Slice 1: %p\n", slice1) 30 | 31 | f := func(s []string) { 32 | fmt.Printf("Slice 1: %p\n", s) 33 | } 34 | f(slice1) 35 | 36 | slice1 = append(slice1, "C") 37 | fmt.Printf("Slice 1: %p\n", slice1) 38 | 39 | array[0] = "X" 40 | fmt.Printf("Slice: %s, %p\n", slice, slice) 41 | fmt.Printf("Array: %s, %p\n", array, &array) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /basics/types/strings/strings.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package strings contains string utility functions. 5 | package strings 6 | 7 | // Reverse reverses an unicode string. 8 | func Reverse(s string) string { 9 | r := []rune(s) 10 | for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 { 11 | r[i], r[j] = r[j], r[i] 12 | } 13 | return string(r) 14 | } 15 | 16 | // End OMIT 17 | -------------------------------------------------------------------------------- /basics/types/strings/strings_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | package strings 4 | 5 | import ( 6 | "fmt" 7 | "testing" 8 | ) 9 | 10 | func TestStringLength(t *testing.T) { 11 | 12 | // Unicode code length 13 | length := len("A") 14 | fmt.Printf("Length: %d\n", length) 15 | length = len("±") 16 | fmt.Printf("Length: %d\n", length) 17 | length = len("☯") 18 | fmt.Printf("Length: %d\n", length) 19 | } 20 | 21 | func TestReverse(t *testing.T) { 22 | 23 | s1 := "Hello, world" 24 | s2 := "Hello, 世界" 25 | s3 := "The quick bròwn 狐 jumped over the lazy 犬" 26 | 27 | if Reverse(Reverse(s1)) != s1 { 28 | t.Errorf("Reversed string %s ist not equal to %s", Reverse(Reverse(s1)), s1) 29 | } 30 | if Reverse(Reverse(s2)) != s2 { 31 | t.Errorf("Reversed string %s ist not equal to %s", Reverse(Reverse(s2)), s2) 32 | } 33 | if Reverse(Reverse(s3)) != s3 { 34 | t.Errorf("Reversed string %s ist not equal to %s", Reverse(Reverse(s3)), s3) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /bp/antlr/Bool.g4: -------------------------------------------------------------------------------- 1 | grammar Bool; 2 | 3 | // Tokens 4 | NOT: '!'; 5 | AND: '&'; 6 | OR: '|'; 7 | P_OPEN: '('; 8 | P_CLOSE: ')'; 9 | VAR: [a-zA-Z0-9]+; 10 | WHITESPACE: [ \r\n\t]+ -> skip; 11 | 12 | // Rules 13 | expr: NOT expr # Not 14 | | expr AND expr # And 15 | | expr OR expr # Or 16 | | VAR # Variable 17 | | P_OPEN expr P_CLOSE # Parenthesis 18 | ; 19 | 20 | // antlr -Dlanguage=G Bool.g4 21 | -------------------------------------------------------------------------------- /bp/antlr/Bool.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | '!' 4 | '&' 5 | '|' 6 | '(' 7 | ')' 8 | null 9 | null 10 | 11 | token symbolic names: 12 | null 13 | NOT 14 | AND 15 | OR 16 | P_OPEN 17 | P_CLOSE 18 | VAR 19 | WHITESPACE 20 | 21 | rule names: 22 | expr 23 | 24 | 25 | atn: 26 | [3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 3, 9, 26, 4, 2, 9, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 5, 2, 13, 10, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 7, 2, 21, 10, 2, 12, 2, 14, 2, 24, 11, 2, 3, 2, 2, 3, 2, 3, 2, 2, 2, 2, 28, 2, 12, 3, 2, 2, 2, 4, 5, 8, 2, 1, 2, 5, 6, 7, 3, 2, 2, 6, 13, 5, 2, 2, 7, 7, 13, 7, 8, 2, 2, 8, 9, 7, 6, 2, 2, 9, 10, 5, 2, 2, 2, 10, 11, 7, 7, 2, 2, 11, 13, 3, 2, 2, 2, 12, 4, 3, 2, 2, 2, 12, 7, 3, 2, 2, 2, 12, 8, 3, 2, 2, 2, 13, 22, 3, 2, 2, 2, 14, 15, 12, 6, 2, 2, 15, 16, 7, 4, 2, 2, 16, 21, 5, 2, 2, 7, 17, 18, 12, 5, 2, 2, 18, 19, 7, 5, 2, 2, 19, 21, 5, 2, 2, 6, 20, 14, 3, 2, 2, 2, 20, 17, 3, 2, 2, 2, 21, 24, 3, 2, 2, 2, 22, 20, 3, 2, 2, 2, 22, 23, 3, 2, 2, 2, 23, 3, 3, 2, 2, 2, 24, 22, 3, 2, 2, 2, 5, 12, 20, 22] -------------------------------------------------------------------------------- /bp/antlr/Bool.tokens: -------------------------------------------------------------------------------- 1 | NOT=1 2 | AND=2 3 | OR=3 4 | P_OPEN=4 5 | P_CLOSE=5 6 | VAR=6 7 | WHITESPACE=7 8 | '!'=1 9 | '&'=2 10 | '|'=3 11 | '('=4 12 | ')'=5 13 | -------------------------------------------------------------------------------- /bp/antlr/BoolLexer.interp: -------------------------------------------------------------------------------- 1 | token literal names: 2 | null 3 | '!' 4 | '&' 5 | '|' 6 | '(' 7 | ')' 8 | null 9 | null 10 | 11 | token symbolic names: 12 | null 13 | NOT 14 | AND 15 | OR 16 | P_OPEN 17 | P_CLOSE 18 | VAR 19 | WHITESPACE 20 | 21 | rule names: 22 | NOT 23 | AND 24 | OR 25 | P_OPEN 26 | P_CLOSE 27 | VAR 28 | WHITESPACE 29 | 30 | channel names: 31 | DEFAULT_TOKEN_CHANNEL 32 | HIDDEN 33 | 34 | mode names: 35 | DEFAULT_MODE 36 | 37 | atn: 38 | [3, 24715, 42794, 33075, 47597, 16764, 15335, 30598, 22884, 2, 9, 39, 8, 1, 4, 2, 9, 2, 4, 3, 9, 3, 4, 4, 9, 4, 4, 5, 9, 5, 4, 6, 9, 6, 4, 7, 9, 7, 4, 8, 9, 8, 3, 2, 3, 2, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 3, 5, 3, 6, 3, 6, 3, 7, 6, 7, 29, 10, 7, 13, 7, 14, 7, 30, 3, 8, 6, 8, 34, 10, 8, 13, 8, 14, 8, 35, 3, 8, 3, 8, 2, 2, 9, 3, 3, 5, 4, 7, 5, 9, 6, 11, 7, 13, 8, 15, 9, 3, 2, 4, 5, 2, 50, 59, 67, 92, 99, 124, 5, 2, 11, 12, 15, 15, 34, 34, 2, 40, 2, 3, 3, 2, 2, 2, 2, 5, 3, 2, 2, 2, 2, 7, 3, 2, 2, 2, 2, 9, 3, 2, 2, 2, 2, 11, 3, 2, 2, 2, 2, 13, 3, 2, 2, 2, 2, 15, 3, 2, 2, 2, 3, 17, 3, 2, 2, 2, 5, 19, 3, 2, 2, 2, 7, 21, 3, 2, 2, 2, 9, 23, 3, 2, 2, 2, 11, 25, 3, 2, 2, 2, 13, 28, 3, 2, 2, 2, 15, 33, 3, 2, 2, 2, 17, 18, 7, 35, 2, 2, 18, 4, 3, 2, 2, 2, 19, 20, 7, 40, 2, 2, 20, 6, 3, 2, 2, 2, 21, 22, 7, 126, 2, 2, 22, 8, 3, 2, 2, 2, 23, 24, 7, 42, 2, 2, 24, 10, 3, 2, 2, 2, 25, 26, 7, 43, 2, 2, 26, 12, 3, 2, 2, 2, 27, 29, 9, 2, 2, 2, 28, 27, 3, 2, 2, 2, 29, 30, 3, 2, 2, 2, 30, 28, 3, 2, 2, 2, 30, 31, 3, 2, 2, 2, 31, 14, 3, 2, 2, 2, 32, 34, 9, 3, 2, 2, 33, 32, 3, 2, 2, 2, 34, 35, 3, 2, 2, 2, 35, 33, 3, 2, 2, 2, 35, 36, 3, 2, 2, 2, 36, 37, 3, 2, 2, 2, 37, 38, 8, 8, 2, 2, 38, 16, 3, 2, 2, 2, 5, 2, 30, 35, 3, 8, 2, 2] -------------------------------------------------------------------------------- /bp/antlr/BoolLexer.tokens: -------------------------------------------------------------------------------- 1 | NOT=1 2 | AND=2 3 | OR=3 4 | P_OPEN=4 5 | P_CLOSE=5 6 | VAR=6 7 | WHITESPACE=7 8 | '!'=1 9 | '&'=2 10 | '|'=3 11 | '('=4 12 | ')'=5 13 | -------------------------------------------------------------------------------- /bp/antlr/bool_base_listener.go: -------------------------------------------------------------------------------- 1 | // Code generated from Bool.g4 by ANTLR 4.8. DO NOT EDIT. 2 | 3 | package parser // Bool 4 | 5 | import "github.com/antlr/antlr4/runtime/Go/antlr" 6 | 7 | // BaseBoolListener is a complete listener for a parse tree produced by BoolParser. 8 | type BaseBoolListener struct{} 9 | 10 | var _ BoolListener = &BaseBoolListener{} 11 | 12 | // VisitTerminal is called when a terminal node is visited. 13 | func (s *BaseBoolListener) VisitTerminal(node antlr.TerminalNode) {} 14 | 15 | // VisitErrorNode is called when an error node is visited. 16 | func (s *BaseBoolListener) VisitErrorNode(node antlr.ErrorNode) {} 17 | 18 | // EnterEveryRule is called when any rule is entered. 19 | func (s *BaseBoolListener) EnterEveryRule(ctx antlr.ParserRuleContext) {} 20 | 21 | // ExitEveryRule is called when any rule is exited. 22 | func (s *BaseBoolListener) ExitEveryRule(ctx antlr.ParserRuleContext) {} 23 | 24 | // EnterNot is called when production Not is entered. 25 | func (s *BaseBoolListener) EnterNot(ctx *NotContext) {} 26 | 27 | // ExitNot is called when production Not is exited. 28 | func (s *BaseBoolListener) ExitNot(ctx *NotContext) {} 29 | 30 | // EnterParenthesis is called when production Parenthesis is entered. 31 | func (s *BaseBoolListener) EnterParenthesis(ctx *ParenthesisContext) {} 32 | 33 | // ExitParenthesis is called when production Parenthesis is exited. 34 | func (s *BaseBoolListener) ExitParenthesis(ctx *ParenthesisContext) {} 35 | 36 | // EnterVariable is called when production Variable is entered. 37 | func (s *BaseBoolListener) EnterVariable(ctx *VariableContext) {} 38 | 39 | // ExitVariable is called when production Variable is exited. 40 | func (s *BaseBoolListener) ExitVariable(ctx *VariableContext) {} 41 | 42 | // EnterOr is called when production Or is entered. 43 | func (s *BaseBoolListener) EnterOr(ctx *OrContext) {} 44 | 45 | // ExitOr is called when production Or is exited. 46 | func (s *BaseBoolListener) ExitOr(ctx *OrContext) {} 47 | 48 | // EnterAnd is called when production And is entered. 49 | func (s *BaseBoolListener) EnterAnd(ctx *AndContext) {} 50 | 51 | // ExitAnd is called when production And is exited. 52 | func (s *BaseBoolListener) ExitAnd(ctx *AndContext) {} 53 | -------------------------------------------------------------------------------- /bp/antlr/bool_evaluator.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | type Evaluator struct { 4 | *BaseBoolListener 5 | vars map[string]bool 6 | stack []bool 7 | } 8 | 9 | func NewEvaluator(vars map[string]bool) *Evaluator { 10 | return &Evaluator{ 11 | BaseBoolListener: &BaseBoolListener{}, 12 | vars: vars, 13 | stack: []bool{}, 14 | } 15 | } 16 | 17 | func (e *Evaluator) push(b bool) { 18 | e.stack = append(e.stack, b) 19 | } 20 | 21 | func (e *Evaluator) pop() bool { 22 | if len(e.stack) < 1 { 23 | panic("empty stack") 24 | } 25 | result := e.stack[len(e.stack)-1] 26 | e.stack = e.stack[:len(e.stack)-1] 27 | return result 28 | } 29 | 30 | func (e *Evaluator) Result() bool { 31 | return e.pop() 32 | } 33 | 34 | func (e *Evaluator) ExitNot(ctx *NotContext) { 35 | e.push(!e.pop()) 36 | } 37 | 38 | func (e *Evaluator) ExitAnd(ctx *AndContext) { 39 | e.push(e.pop() && e.pop()) 40 | } 41 | 42 | func (e *Evaluator) ExitOr(ctx *OrContext) { 43 | e.push(e.pop() || e.pop()) 44 | } 45 | 46 | func (e *Evaluator) ExitVariable(ctx *VariableContext) { 47 | e.push(e.vars[ctx.GetText()]) 48 | } 49 | -------------------------------------------------------------------------------- /bp/antlr/bool_listener.go: -------------------------------------------------------------------------------- 1 | // Code generated from Bool.g4 by ANTLR 4.8. DO NOT EDIT. 2 | 3 | package parser // Bool 4 | 5 | import "github.com/antlr/antlr4/runtime/Go/antlr" 6 | 7 | // BoolListener is a complete listener for a parse tree produced by BoolParser. 8 | type BoolListener interface { 9 | antlr.ParseTreeListener 10 | 11 | // EnterNot is called when entering the Not production. 12 | EnterNot(c *NotContext) 13 | 14 | // EnterParenthesis is called when entering the Parenthesis production. 15 | EnterParenthesis(c *ParenthesisContext) 16 | 17 | // EnterVariable is called when entering the Variable production. 18 | EnterVariable(c *VariableContext) 19 | 20 | // EnterOr is called when entering the Or production. 21 | EnterOr(c *OrContext) 22 | 23 | // EnterAnd is called when entering the And production. 24 | EnterAnd(c *AndContext) 25 | 26 | // ExitNot is called when exiting the Not production. 27 | ExitNot(c *NotContext) 28 | 29 | // ExitParenthesis is called when exiting the Parenthesis production. 30 | ExitParenthesis(c *ParenthesisContext) 31 | 32 | // ExitVariable is called when exiting the Variable production. 33 | ExitVariable(c *VariableContext) 34 | 35 | // ExitOr is called when exiting the Or production. 36 | ExitOr(c *OrContext) 37 | 38 | // ExitAnd is called when exiting the And production. 39 | ExitAnd(c *AndContext) 40 | } 41 | -------------------------------------------------------------------------------- /bp/ast/ast.go: -------------------------------------------------------------------------------- 1 | package ast 2 | 3 | import "fmt" 4 | 5 | type Node interface { 6 | Eval(vars map[string]bool) bool 7 | } 8 | 9 | type Not struct { 10 | Expr Node 11 | } 12 | 13 | func (n Not) Eval(vars map[string]bool) bool { 14 | return !n.Expr.Eval(vars) 15 | } 16 | 17 | func (n Not) String() string { 18 | return fmt.Sprintf("!(%v)", n.Expr) 19 | } 20 | 21 | type And struct { 22 | LeftExpr Node 23 | RightExpr Node 24 | } 25 | 26 | func (n And) Eval(vars map[string]bool) bool { 27 | return n.LeftExpr.Eval(vars) && n.RightExpr.Eval(vars) 28 | } 29 | 30 | func (n And) String() string { 31 | return fmt.Sprintf("(%v & %v)", n.LeftExpr, n.RightExpr) 32 | } 33 | 34 | type Or struct { 35 | LeftExpr Node 36 | RightExpr Node 37 | } 38 | 39 | func (n Or) Eval(vars map[string]bool) bool { 40 | return n.LeftExpr.Eval(vars) || n.RightExpr.Eval(vars) 41 | } 42 | 43 | func (n Or) String() string { 44 | return fmt.Sprintf("(%v | %v)", n.LeftExpr, n.RightExpr) 45 | } 46 | 47 | type Var struct { 48 | Name string 49 | } 50 | 51 | func (n Var) Eval(vars map[string]bool) bool { 52 | return vars[n.Name] 53 | } 54 | 55 | func (n Var) String() string { 56 | return fmt.Sprintf("%s", n.Name) 57 | } 58 | -------------------------------------------------------------------------------- /bp/lexer/lexer.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "regexp" 7 | "unicode" 8 | ) 9 | 10 | var varRegex = regexp.MustCompile("[a-zA-Z0-9]") 11 | 12 | type Lexer struct { 13 | io.RuneScanner 14 | } 15 | 16 | func (l Lexer) NextToken() (string, error) { 17 | var variable []rune 18 | for { 19 | r, _, err := l.ReadRune() 20 | if err == io.EOF && len(variable) > 0 { 21 | return string(variable), nil 22 | } else if err != nil { 23 | return "", err 24 | } 25 | if varRegex.MatchString(string(r)) { 26 | variable = append(variable, r) 27 | } else { 28 | if len(variable) > 0 { 29 | err := l.UnreadRune() 30 | return string(variable), err 31 | } 32 | if r == '!' || r == '&' || r == '|' || r == '(' || r == ')' { 33 | return string(r), nil 34 | } else if unicode.IsSpace(r) { 35 | continue 36 | } else { 37 | return "", fmt.Errorf("invalid rune '%c'", r) 38 | } 39 | } 40 | } 41 | } 42 | 43 | func (l Lexer) AllTokens() ([]string, error) { 44 | var tokens []string 45 | for { 46 | token, err := l.NextToken() 47 | if err == io.EOF { 48 | return tokens, nil 49 | } else if err != nil { 50 | return nil, err 51 | } else { 52 | tokens = append(tokens, token) 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /bp/lexer/lexer_test.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | ) 7 | 8 | func TestLexer_AllTokens_ABC(t *testing.T) { 9 | lex := Lexer{RuneScanner: strings.NewReader("A & B | !C")} 10 | tokens, err := lex.AllTokens() 11 | if err != nil { 12 | t.Fatal(err) 13 | } 14 | joined := strings.Join(tokens, ",") 15 | if joined != "A,&,B,|,!,C" { 16 | t.Fatalf("Expected 'A,&,B,|,!,C', but got '%s'", joined) 17 | } 18 | } 19 | func TestLexer_AllTokens_MultiChar(t *testing.T) { 20 | lex := Lexer{RuneScanner: strings.NewReader("Bernhard | !Bernhard")} 21 | tokens, err := lex.AllTokens() 22 | if err != nil { 23 | t.Fatal(err) 24 | } 25 | joined := strings.Join(tokens, ",") 26 | if joined != "Bernhard,|,!,Bernhard" { 27 | t.Fatalf("Expected 'Bernhard,|,!,Bernhard', but got '%s'", joined) 28 | } 29 | } 30 | 31 | func TestLexer_AllTokens_Unicode(t *testing.T) { 32 | lex := Lexer{RuneScanner: strings.NewReader("ü1😀A")} 33 | _, err := lex.AllTokens() 34 | if err == nil && err.Error() != "invalid rune 'ü'" { 35 | t.Fatal("expected error 'invalid rune 'ü''") 36 | } 37 | } 38 | 39 | func TestLexer_AllTokens_NotNotA(t *testing.T) { 40 | lex := Lexer{RuneScanner: strings.NewReader("!!A")} 41 | tokens, err := lex.AllTokens() 42 | if err != nil { 43 | t.Fatal(err) 44 | } 45 | joined := strings.Join(tokens, ",") 46 | if joined != "!,!,A" { 47 | t.Fatalf("Expected '!,!,A', but got '%s'", joined) 48 | } 49 | } 50 | 51 | func TestLexer_AllTokens_Empty(t *testing.T) { 52 | lex := Lexer{RuneScanner: strings.NewReader("")} 53 | tokens, err := lex.AllTokens() 54 | if err != nil { 55 | t.Fatal(err) 56 | } 57 | joined := strings.Join(tokens, ",") 58 | if joined != "" { 59 | t.Fatalf("Expected '', but got '%s'", joined) 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /bp/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | antp "github.com/0xqab/concepts-of-programming-languages/bp/antlr" 6 | "github.com/0xqab/concepts-of-programming-languages/bp/lexer" 7 | "github.com/0xqab/concepts-of-programming-languages/bp/parser" 8 | "github.com/antlr/antlr4/runtime/Go/antlr" 9 | "strings" 10 | ) 11 | 12 | func main() { 13 | source := "A & B | !C" 14 | reader := strings.NewReader(source) 15 | lex := lexer.Lexer{RuneScanner: reader} 16 | pars := parser.Parser{Tokenizer: lex} 17 | ast, err := pars.Parse() 18 | if err != nil { 19 | panic(err) 20 | } 21 | fmt.Printf("AST: %v\n", ast) 22 | fmt.Printf("eval(true, true, true) = %t\n", ast.Eval(map[string]bool{"A": true, "B": true, "C": true})) 23 | fmt.Printf("eval(true, true, false) = %t\n", ast.Eval(map[string]bool{"A": true, "B": true, "C": false})) 24 | fmt.Printf("eval(true, false, true) = %t\n", ast.Eval(map[string]bool{"A": true, "B": false, "C": true})) 25 | fmt.Printf("eval(false, true, true) = %t\n", ast.Eval(map[string]bool{"A": false, "B": true, "C": true})) 26 | fmt.Printf("eval(false, false, false) = %t\n", ast.Eval(map[string]bool{"A": false, "B": false, "C": false})) 27 | fmt.Printf("eval(false, false, true) = %t\n", ast.Eval(map[string]bool{"A": false, "B": false, "C": true})) 28 | 29 | antlrLexer := antp.NewBoolLexer(antlr.NewInputStream(source)) 30 | antlrParser := antp.NewBoolParser(antlr.NewCommonTokenStream(antlrLexer, 0)) 31 | antlrAst := antlrParser.Expr() 32 | fmt.Printf("antlr.eval(true, true, true) = %t\n", antlrEval(antlrAst, map[string]bool{"A": true, "B": true, "C": true})) 33 | fmt.Printf("antlr.eval(true, true, false) = %t\n", antlrEval(antlrAst, map[string]bool{"A": true, "B": true, "C": false})) 34 | fmt.Printf("antlr.eval(true, false, true) = %t\n", antlrEval(antlrAst, map[string]bool{"A": true, "B": false, "C": true})) 35 | fmt.Printf("antlr.eval(false, true, true) = %t\n", antlrEval(antlrAst, map[string]bool{"A": false, "B": true, "C": true})) 36 | fmt.Printf("antlr.eval(false, false, false) = %t\n", antlrEval(antlrAst, map[string]bool{"A": false, "B": false, "C": false})) 37 | fmt.Printf("antlr.eval(false, false, true) = %t\n", antlrEval(antlrAst, map[string]bool{"A": false, "B": false, "C": true})) 38 | } 39 | 40 | func antlrEval(antlrAst antp.IExprContext, vars map[string]bool) bool { 41 | evaluator := antp.NewEvaluator(vars) 42 | antlr.ParseTreeWalkerDefault.Walk(evaluator, antlrAst) 43 | return evaluator.Result() 44 | } 45 | -------------------------------------------------------------------------------- /bp/parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "fmt" 5 | "github.com/0xqab/concepts-of-programming-languages/bp/ast" 6 | "io" 7 | ) 8 | 9 | type Tokenizer interface { 10 | NextToken() (string, error) 11 | } 12 | 13 | type Parser struct { 14 | Tokenizer Tokenizer 15 | rootNode ast.Node 16 | token string // ll(1) 17 | } 18 | 19 | // ::= { } 20 | // ::= { } 21 | // ::= | | () 22 | // ::= '|' 23 | // ::= '&' 24 | // ::= '!' 25 | // ::= '[a-zA-Z0-9]+' 26 | 27 | func (p *Parser) Parse() (ast.Node, error) { 28 | p.rootNode = nil 29 | if err := p.expression(); err != nil { 30 | return nil, err 31 | } 32 | return p.rootNode, nil 33 | } 34 | 35 | func (p *Parser) expression() error { 36 | if err := p.term(); err != nil { 37 | return err 38 | } 39 | for p.token == "|" { 40 | lhs := p.rootNode 41 | if err := p.term(); err != nil { 42 | return err 43 | } 44 | rhs := p.rootNode 45 | p.rootNode = &ast.Or{LeftExpr: lhs, RightExpr: rhs} 46 | } 47 | return nil 48 | } 49 | 50 | func (p *Parser) term() error { 51 | if err := p.factor(); err != nil { 52 | return err 53 | } 54 | for p.token == "&" { 55 | lhs := p.rootNode 56 | if err := p.factor(); err != nil { 57 | return err 58 | } 59 | rhs := p.rootNode 60 | p.rootNode = &ast.And{LeftExpr: lhs, RightExpr: rhs} 61 | } 62 | return nil 63 | } 64 | 65 | func (p *Parser) factor() error { 66 | token, err := p.Tokenizer.NextToken() 67 | if err == io.EOF { 68 | return nil 69 | } 70 | if err != nil { 71 | return err 72 | } 73 | p.token = token 74 | if p.token == "!" { 75 | if err := p.factor(); err != nil { 76 | return err 77 | } 78 | p.rootNode = &ast.Not{Expr: p.rootNode} 79 | } else if p.token == "(" { 80 | if err := p.expression(); err != nil { 81 | return err 82 | } 83 | p.token, err = p.Tokenizer.NextToken() 84 | if err == io.EOF { 85 | return nil 86 | } 87 | if err != nil { 88 | return err 89 | } 90 | } else { 91 | p.rootNode = ast.Var{Name: p.token} 92 | p.token, err = p.Tokenizer.NextToken() 93 | if err == io.EOF { 94 | return nil 95 | } 96 | if err != nil { 97 | return err 98 | } 99 | } 100 | return nil 101 | } 102 | 103 | func (p *Parser) String() string { 104 | return fmt.Sprint(p.rootNode) 105 | } 106 | -------------------------------------------------------------------------------- /cp/README.md: -------------------------------------------------------------------------------- 1 | # Concurrent Programming Samples 2 | 3 | - channels 4 | - locks 5 | 6 | 7 | ## Channels 8 | 9 | ## Locks 10 | 11 | -------------------------------------------------------------------------------- /cp/channels/blockingqueue/blockingqueue.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package blockingqueue contains a blocking LIFO container. 5 | package blockingqueue 6 | 7 | // BlockingQueue is a FIFO container with a fixed capacity. 8 | // It blocks a reader when it is empty and a writer when it is full. 9 | type BlockingQueue struct { 10 | channel chan interface{} 11 | } 12 | 13 | // NewBlockingQueue constructs a BlockingQueue with a given capacity. 14 | func NewBlockingQueue(capacity int) *BlockingQueue { 15 | q := BlockingQueue{make(chan interface{}, capacity)} 16 | return &q 17 | } 18 | 19 | // Put puts an item in the queue and blocks it the queue is full. 20 | func (q *BlockingQueue) Put(item interface{}) { 21 | q.channel <- item 22 | } 23 | 24 | // Take takes an item from the queue and blocks if the queue is empty. 25 | func (q *BlockingQueue) Take() interface{} { 26 | return <-q.channel 27 | } 28 | 29 | // EOF 30 | -------------------------------------------------------------------------------- /cp/channels/blockingqueue/blockingqueue_test.go: -------------------------------------------------------------------------------- 1 | package blockingqueue 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | ) 8 | 9 | // Copyright 2018 Johannes Weigend 10 | // Licensed under the Apache License, Version 2.0 11 | 12 | func TestBlockingQueue(t *testing.T) { 13 | bq1 := NewBlockingQueue(1) 14 | done := make(chan bool) 15 | // slow writer 16 | go func(bq *BlockingQueue) { 17 | bq.Put("A") 18 | time.Sleep(100 * time.Millisecond) 19 | bq.Put("B") 20 | time.Sleep(100 * time.Millisecond) 21 | bq.Put("C") 22 | }(bq1) 23 | // reader will be blocked 24 | go func(bq *BlockingQueue) { 25 | item := bq.Take() 26 | fmt.Printf("Got %v\n", item) 27 | item = bq.Take() 28 | fmt.Printf("Got %v\n", item) 29 | item = bq.Take() 30 | fmt.Printf("Got %v\n", item) 31 | done <- true 32 | }(bq1) 33 | 34 | <-done 35 | } 36 | 37 | // EOF OMIT 38 | -------------------------------------------------------------------------------- /cp/channels/deadlock/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func main() { 6 | ch := make(chan int) 7 | ch <- 1 8 | ch <- 2 // dead by now 9 | fmt.Println(<-ch) 10 | fmt.Println(<-ch) 11 | } 12 | -------------------------------------------------------------------------------- /cp/channels/fan/fanin.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package utils contains functions to work with channels. 5 | package utils 6 | 7 | import ( 8 | "fmt" 9 | "log" 10 | ) 11 | 12 | // FanIn reads from N-Channels and forwards the result to the output channel. 13 | func FanIn(channels []chan int, output chan int) { 14 | for i := 0; i < len(channels); i++ { 15 | // fan in 16 | go func(i int) { 17 | for { 18 | n, ok := <-channels[i] 19 | if !ok { 20 | break 21 | } 22 | output <- n 23 | } 24 | log.Println("input channel closed: done.") 25 | }(i) 26 | } 27 | } 28 | 29 | // FanIn OMIT 30 | 31 | // Print prints all data from a channel until the channel is closed. 32 | func Print(ch chan int) { 33 | go func() { 34 | for { 35 | res, ok := <-ch 36 | if !ok { 37 | break 38 | } 39 | fmt.Println(res) 40 | } 41 | log.Println("output channel closed: done.") 42 | }() 43 | } 44 | -------------------------------------------------------------------------------- /cp/channels/fan/fanin_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package fan contains examples for fanout und fanin functions using channels. 5 | package utils 6 | 7 | import ( 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func TestFanIn(t *testing.T) { 13 | 14 | // FanIn reads from an array of input channels and send the results to a output channel . 15 | inCh := []chan int{make(chan int), make(chan int)} 16 | outCh := make(chan int) 17 | 18 | // FanIn from an array of channels 19 | FanIn(inCh, outCh) 20 | 21 | // read from one channel and print results to stdout. 22 | Print(outCh) 23 | 24 | inCh[0] <- 2 25 | inCh[1] <- 1 26 | 27 | time.Sleep(100 * time.Millisecond) 28 | 29 | close(inCh[0]) 30 | close(inCh[1]) 31 | 32 | time.Sleep(100 * time.Millisecond) 33 | } 34 | -------------------------------------------------------------------------------- /cp/channels/fan/fanout.go: -------------------------------------------------------------------------------- 1 | // Package utils contains examples for fanout und fanin functions using channels. 2 | package utils 3 | 4 | // FanOut reads from a channel and starts an async processing task. 5 | // The result values of the tasks will be returned in the result channel 6 | func FanOut(input chan int, task func(int, chan int)) chan int { 7 | result := make(chan int) 8 | go func() { 9 | for { 10 | x, ok := <-input 11 | if !ok { 12 | break 13 | } 14 | go task(x, result) 15 | } 16 | }() 17 | return result 18 | } 19 | 20 | // EOF OMIT 21 | -------------------------------------------------------------------------------- /cp/channels/fan/fanout_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package fan contains examples for fanout und fanin functions using channels. 5 | package utils 6 | 7 | import ( 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func TestFanOut(t *testing.T) { 13 | 14 | inCh := make(chan int, 10) 15 | // write data to in channel 16 | for i := 0; i < 10; i++ { 17 | inCh <- i 18 | } 19 | 20 | task := func(v int, res chan int) { 21 | time.Sleep(1 * time.Millisecond) // simulate long running calculation 22 | res <- v * v // return v*v 23 | } 24 | 25 | outChan := FanOut(inCh, task) 26 | 27 | Print(outChan) 28 | 29 | time.Sleep(100 * time.Millisecond) 30 | 31 | close(inCh) 32 | } 33 | -------------------------------------------------------------------------------- /cp/channels/fibonacci/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | func fib() <-chan int { 6 | c := make(chan int) 7 | go func() { 8 | for i, j := 0, 1; ; i, j = i+j, i { 9 | c <- i 10 | } 11 | }() 12 | return c 13 | } 14 | 15 | // MAIN OMIT 16 | func main() { 17 | fibChan := fib() // <- write func fib 18 | for n := 1; n <= 10; n++ { 19 | fmt.Printf("The %dth Fibonacci number is %d\n", n, <-fibChan) 20 | } 21 | } 22 | // EOF OMIT 23 | -------------------------------------------------------------------------------- /cp/channels/lecturer/lecturer1/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func lecturer() { 10 | for i := 0; i < 5; i++ { 11 | fmt.Printf("%d Bla bla goroutines bla channels bla bla\n", i) 12 | time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) 13 | } 14 | } 15 | 16 | func main() { 17 | lecturer() 18 | } 19 | 20 | // EOF OMIT 21 | -------------------------------------------------------------------------------- /cp/channels/lecturer/lecturer2/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func lecturer() { 10 | for i := 0; i < 5; i++ { 11 | fmt.Printf("%d Bla bla goroutines bla channels bla bla\n", i) 12 | time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) 13 | } 14 | } 15 | 16 | func main() { 17 | go lecturer() 18 | } 19 | 20 | // EOF OMIT 21 | -------------------------------------------------------------------------------- /cp/channels/lecturer/lecturer3/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func lecturer(c chan string) { 10 | for i := 0; i < 5; i++ { 11 | c <- fmt.Sprintf("%d Bla bla goroutines bla channels bla bla\n", i) 12 | time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) 13 | } 14 | } 15 | 16 | func main() { 17 | c := make(chan string) 18 | go lecturer(c) 19 | for i := 0; i < 5; i++ { 20 | fmt.Printf(<-c) 21 | } 22 | } 23 | 24 | // EOF OMIT 25 | -------------------------------------------------------------------------------- /cp/channels/lecturer/lecturer4/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func lecturer() <-chan string { 10 | c := make(chan string) 11 | go func() { 12 | for i := 0; i < 5; i++ { 13 | c <- fmt.Sprintf("%d Bla bla goroutines bla channels bla bla\n", i) 14 | time.Sleep(time.Duration(rand.Intn(1e3)) * time.Millisecond) 15 | } 16 | }() 17 | return c 18 | } 19 | 20 | func main() { 21 | c := lecturer() 22 | for i := 0; i < 5; i++ { 23 | fmt.Printf(<-c) 24 | } 25 | } 26 | 27 | // EOF OMIT 28 | -------------------------------------------------------------------------------- /cp/channels/lecturer/lecturer5/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func lecturer(name string, speed int) <-chan string { 10 | c := make(chan string) 11 | go func() { 12 | for i := 0; i < 5; i++ { 13 | c <- fmt.Sprintf("%s: %d Bla bla goroutines bla channels bla bla\n", name, i) 14 | time.Sleep(time.Duration(rand.Intn(1e3*speed)) * time.Millisecond) 15 | } 16 | }() 17 | return c 18 | } 19 | 20 | func main() { 21 | a := lecturer("Anne", 1) 22 | b := lecturer("Bart", 2) 23 | for i := 0; i < 5; i++ { 24 | fmt.Printf(<-a) 25 | fmt.Printf(<-b) 26 | } 27 | } 28 | 29 | // EOF OMIT 30 | -------------------------------------------------------------------------------- /cp/channels/lecturer/lecturer6/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func lecturer(name string, speed int) <-chan string { 10 | c := make(chan string) 11 | go func() { 12 | for i := 0; i < 5; i++ { 13 | c <- fmt.Sprintf("%s: %d Bla bla goroutines bla channels bla bla\n", name, i) 14 | time.Sleep(time.Duration(rand.Intn(1e3*speed)) * time.Millisecond) 15 | } 16 | }() 17 | return c 18 | } 19 | 20 | // START OMIT 21 | // func lecturer(name string, speed int) <-chan string { ... } 22 | 23 | func fanIn(c1, c2 <-chan string) <-chan string { 24 | c := make(chan string) 25 | go func() { for { c <- <-c1 } }() 26 | go func() { for { c <- <-c2 } }() 27 | return c 28 | } 29 | 30 | func main() { 31 | a := lecturer("Anne", 1) 32 | b := lecturer("Bart", 2) 33 | c := fanIn(a, b) 34 | for i := 0; i < 10; i++ { 35 | fmt.Printf(<-c) 36 | } 37 | } 38 | 39 | // EOF OMIT 40 | -------------------------------------------------------------------------------- /cp/channels/lecturer/lecturer7/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math/rand" 6 | "time" 7 | ) 8 | 9 | func lecturer(name string, speed int) <-chan string { 10 | c := make(chan string) 11 | go func() { 12 | for i := 0; i < 5; i++ { 13 | c <- fmt.Sprintf("%s: %d Bla bla goroutines bla channels bla bla\n", name, i) 14 | time.Sleep(time.Duration(rand.Intn(1e3*speed)) * time.Millisecond) 15 | } 16 | }() 17 | return c 18 | } 19 | 20 | func main() { 21 | a := lecturer("Anne", 1) 22 | b := lecturer("Bart", 2) 23 | for i := 0; i < 10; i++ { 24 | select { 25 | case msgFromAnne := <-a: fmt.Printf(msgFromAnne) 26 | case msgFromBart := <-b: fmt.Printf(msgFromBart) 27 | } 28 | } 29 | } 30 | 31 | // EOF OMIT 32 | -------------------------------------------------------------------------------- /cp/channels/philosophers/philosophers.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package philosophers 16 | 17 | import ( 18 | "fmt" 19 | "time" 20 | ) 21 | 22 | // Philosopher represents one philosopher. 23 | type Philosopher struct { 24 | id int 25 | table *Table 26 | } 27 | 28 | // NewPhilosopher constructs a philosopher. 29 | func NewPhilosopher(id int, table *Table) *Philosopher { 30 | p := new(Philosopher) 31 | p.id = id 32 | p.table = table 33 | return p 34 | } 35 | 36 | // Run loops forever. 37 | func (p *Philosopher) run() { 38 | for { 39 | p.takeForks() 40 | p.eat() 41 | p.putForks() 42 | p.think() 43 | } 44 | } 45 | 46 | // Take forks by channeling our id to the table and wait until the table returns true on the reserved channel. 47 | func (p *Philosopher) takeForks() { 48 | fmt.Printf("Philosopher #%d is getting hungry\n", p.id) 49 | // try to get forks from table 50 | gotForks := false 51 | for !gotForks { 52 | p.table.getTakeChannel() <- p.id 53 | gotForks = <-p.table.getReservedChannel(p.id) 54 | } 55 | } 56 | 57 | // Put forks by channeling our id to the table. The table is responsible for the put logic. 58 | func (p *Philosopher) putForks() { 59 | fmt.Printf("Philosopher #%d puts down forks\n", p.id) 60 | p.table.getPutChannel() <- p.id 61 | } 62 | 63 | // Eating. 64 | func (p *Philosopher) eat() { 65 | fmt.Printf("Philosopher #%d starts eating\n", p.id) 66 | time.Sleep(2 * time.Second) 67 | } 68 | 69 | // Thinking. 70 | func (p *Philosopher) think() { 71 | fmt.Printf("Philosopher #%d is thinking\n", p.id) 72 | time.Sleep(3 * time.Second) 73 | } 74 | -------------------------------------------------------------------------------- /cp/channels/philosophers/philosophers_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package philosophers 15 | 16 | import ( 17 | "testing" 18 | "time" 19 | ) 20 | 21 | // ===================================================================================================================== 22 | // Main Test. 23 | // ===================================================================================================================== 24 | 25 | func TestPhilosophers(t *testing.T) { 26 | 27 | var COUNT = 5 28 | 29 | // start table for 5 30 | table := NewTable(COUNT) 31 | 32 | // start philosophers 33 | for i := 0; i < COUNT; i++ { 34 | philosopher := NewPhilosopher(i, table) 35 | go philosopher.run() 36 | } 37 | go table.run() 38 | 39 | // wait 1 millisecond --> check output 40 | time.Sleep(10 * time.Second) 41 | } 42 | -------------------------------------------------------------------------------- /cp/channels/pingpong/pingpong.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "time" 8 | ) 9 | 10 | // Ball contains the number of hits. 11 | type Ball struct{ hits int } 12 | 13 | func main() { 14 | table := make(chan *Ball) 15 | go player("ping", table) 16 | go player("pong", table) 17 | 18 | table <- new(Ball) // game on; toss the ball 19 | time.Sleep(1 * time.Second) 20 | <-table // game over; grab the ball 21 | } 22 | 23 | func player(name string, table chan *Ball) { 24 | for { 25 | ball := <-table 26 | ball.hits++ 27 | fmt.Println(name, ball.hits) 28 | time.Sleep(100 * time.Millisecond) 29 | table <- ball 30 | } 31 | } 32 | 33 | // EOF OMIT 34 | -------------------------------------------------------------------------------- /cp/channels/timeout/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | ) 7 | 8 | func setTimeout(task func() int, timeout time.Duration) (int, error) { 9 | taskChan := make(chan int) 10 | go func() { 11 | taskChan <- task() 12 | }() 13 | timerChan := time.After(timeout) 14 | select { 15 | case result := <-taskChan: 16 | return result, nil 17 | case <-timerChan: 18 | return 0, fmt.Errorf("operation timed out") 19 | } 20 | } 21 | 22 | // MAIN OMIT 23 | func main() { 24 | res, err := setTimeout(func() int { 25 | time.Sleep(2000 * time.Millisecond) 26 | return 1 27 | }, 1*time.Second) 28 | 29 | if err != nil { 30 | fmt.Println(err.Error()) 31 | } else { 32 | fmt.Printf("operation returned %d", res) 33 | } 34 | } 35 | // EOF OMIT 36 | -------------------------------------------------------------------------------- /cp/locks/README.md: -------------------------------------------------------------------------------- 1 | ![Logo](../../doc/article/img/Logo.png "Logo") 2 | ### *Concurrency with Go* 3 | 4 | - Blocking Queue 5 | - Resource Manager 6 | 7 | ## Using the go sync package to write a Java like Blocking Queue. 8 | **Go Channels are great. No Question. But sometimes you want to have more control about when to block and what to do if some condition is reached.** 9 | The Go sync package offers the same possibilities as java.util.concurrent does. 10 | 11 | 12 | ```go 13 | import "sync" 14 | 15 | // BlockingQueue is a FIFO container with a fixed capacity. 16 | // It blocks a reader when it is empty and a writer when it is full. 17 | type BlockingQueue struct { 18 | m sync.Mutex 19 | c sync.Cond 20 | data []interface{} 21 | capacity int 22 | } 23 | ``` 24 | 25 | ```go 26 | // NewBlockingQueue constructs a BlockingQuee with a given capacity. 27 | func NewBlockingQueue(capacity int) *BlockingQueue { 28 | q := new(BlockingQueue) 29 | q.c = sync.Cond{L: &q.m} 30 | q.capacity = capacity 31 | return q 32 | } 33 | ``` 34 | 35 | ```go 36 | // Put puts an item in the queue and blocks it the queue is full. 37 | func (q *BlockingQueue) Put(item interface{}) { 38 | q.c.L.Lock() 39 | defer q.c.L.Unlock() 40 | 41 | for q.isFull() { 42 | q.c.Wait() 43 | } 44 | q.data = append(q.data, item) 45 | q.c.Signal() 46 | } 47 | ``` 48 | 49 | 50 | ```go 51 | // Take takes an item from the queue and blocks if the queue is empty. 52 | func (q *BlockingQueue) Take() interface{} { 53 | q.c.L.Lock() 54 | defer q.c.L.Unlock() 55 | 56 | for q.isEmpty() { 57 | q.c.Wait() 58 | } 59 | result := q.data[0] 60 | q.data = q.data[1 : len(q.data)] 61 | q.c.Signal() 62 | return result 63 | } 64 | ``` 65 | 66 | ```go 67 | // isFull returns true if the capacity is reached. 68 | func (q *BlockingQueue) isFull() bool { 69 | return len(q.data) == q.capacity 70 | } 71 | 72 | // isEmpty returns true if there are no elements in the queue. 73 | func (q *BlockingQueue) isEmpty() bool { 74 | return len(q.data) == 0 75 | } 76 | ``` 77 | 78 | 79 | ```go 80 | func TestBlockingQueue(t *testing.T) { 81 | 82 | bq := NewBlockingQueue(1) 83 | done := make(chan bool) 84 | 85 | // slow writer 86 | go func() { 87 | bq.Put("A") 88 | time.Sleep(100 * time.Millisecond) 89 | bq.Put("B") 90 | time.Sleep(100 * time.Millisecond) 91 | bq.Put("C") 92 | }() 93 | 94 | // reader will be blocked 95 | go func() { 96 | item := bq.Take() 97 | fmt.Printf("Got %v\n", item) 98 | item = bq.Take() 99 | fmt.Printf("Got %v\n", item) 100 | item = bq.Take() 101 | fmt.Printf("Got %v\n", item) 102 | done <- true 103 | }() 104 | 105 | // block while done 106 | <-done 107 | } 108 | ``` -------------------------------------------------------------------------------- /cp/locks/blockingqueue/blockingqueue.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, copied from Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package blockingqueue contains a blocking LIFO container. 5 | package blockingqueue 6 | 7 | import "sync" 8 | 9 | // BlockingQueue is a FIFO container with a fixed capacity. 10 | // It blocks a reader when it is empty and a writer when it is full. 11 | type BlockingQueue struct { 12 | m sync.Mutex 13 | c sync.Cond 14 | data []interface{} 15 | capacity int 16 | } 17 | 18 | // NewBlockingQueue constructs a BlockingQuee with a given capacity. 19 | func NewBlockingQueue(capacity int) *BlockingQueue { 20 | q := new(BlockingQueue) 21 | q.c = sync.Cond{L: &q.m} 22 | q.capacity = capacity 23 | return q 24 | } 25 | 26 | // A1 27 | 28 | // Put puts an item in the queue and blocks it the queue is full. 29 | func (q *BlockingQueue) Put(item interface{}) { 30 | q.c.L.Lock() 31 | defer q.c.L.Unlock() 32 | 33 | for q.isFull() { 34 | q.c.Wait() 35 | } 36 | q.data = append(q.data, item) 37 | q.c.Signal() 38 | } 39 | 40 | // Take takes an item from the queue and blocks if the queue is empty. 41 | func (q *BlockingQueue) Take() interface{} { 42 | q.c.L.Lock() 43 | defer q.c.L.Unlock() 44 | 45 | for q.isEmpty() { 46 | q.c.Wait() 47 | } 48 | result := q.data[0] 49 | q.data = q.data[1:len(q.data)] 50 | q.c.Signal() 51 | return result 52 | } 53 | 54 | // A2 55 | 56 | // isFull returns true if the capacity is reached. 57 | func (q *BlockingQueue) isFull() bool { 58 | return len(q.data) == q.capacity 59 | } 60 | 61 | // isEmpty returns true if there are no elements in the queue. 62 | func (q *BlockingQueue) isEmpty() bool { 63 | return len(q.data) == 0 64 | } 65 | -------------------------------------------------------------------------------- /cp/locks/blockingqueue/blockingqueue_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | package blockingqueue 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func TestBlockingQueue(t *testing.T) { 13 | 14 | bq := NewBlockingQueue(1) 15 | done := make(chan bool) 16 | 17 | // slow writer 18 | go func(bq *BlockingQueue) { 19 | bq.Put("A") 20 | time.Sleep(100 * time.Millisecond) 21 | bq.Put("B") 22 | time.Sleep(100 * time.Millisecond) 23 | bq.Put("C") 24 | }(bq) 25 | 26 | // reader will be blocked 27 | go func(bq *BlockingQueue) { 28 | item := bq.Take() 29 | fmt.Printf("Got %v\n", item) 30 | item = bq.Take() 31 | fmt.Printf("Got %v\n", item) 32 | item = bq.Take() 33 | fmt.Printf("Got %v\n", item) 34 | done <- true 35 | }(bq) 36 | 37 | // block while done 38 | <-done 39 | } 40 | 41 | // EOF OMIT 42 | -------------------------------------------------------------------------------- /cp/locks/philosophers/philosophers_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | package philosophers 15 | 16 | import ( 17 | "testing" 18 | "time" 19 | ) 20 | 21 | // ===================================================================================================================== 22 | // Main Test. 23 | // ===================================================================================================================== 24 | 25 | func TestPhilosophers(t *testing.T) { 26 | 27 | var COUNT = 5 28 | 29 | // start table for 5 30 | table := NewTable(COUNT) 31 | 32 | // start philosophers 33 | for i := 0; i < COUNT; i++ { 34 | philosopher := NewPhilosopher(i, table) 35 | go philosopher.run() 36 | } 37 | 38 | // wait 1 millisecond --> check output 39 | time.Sleep(1000 * time.Millisecond) 40 | } 41 | -------------------------------------------------------------------------------- /cp/locks/philosophers/table.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package philosophers implements the Dining Philosophers Problem. 16 | package philosophers 17 | 18 | import ( 19 | "github.com/0xqab/concepts-of-programming-languages/cp/locks/resourcemanager" 20 | ) 21 | 22 | // ===================================================================================================================== 23 | // Dining Philosophers Problem. See https://en.wikipedia.org/wiki/Dining_philosophers_problem. 24 | // The synchronization is done with channels. There are two channels for put and request fork operation. 25 | // There is one channel per philosopher to signal when the forks can be taken. 26 | // ===================================================================================================================== 27 | 28 | // Table represents the table with dynamic seat count. 29 | type Table struct { 30 | manager *resourcemanager.ResourceManager 31 | forkInUse []bool 32 | nbrOfSeats int 33 | } 34 | 35 | // NewTable constructs a table with n seats. 36 | func NewTable(nbrOfSeats int) *Table { 37 | table := new(Table) 38 | table.manager = resourcemanager.NewResourceManager() 39 | table.forkInUse = make([]bool, nbrOfSeats) 40 | table.nbrOfSeats = nbrOfSeats 41 | return table 42 | } 43 | 44 | // GetManager returns the resource manager. 45 | func (t *Table) GetManager() *resourcemanager.ResourceManager { 46 | return t.manager 47 | } 48 | -------------------------------------------------------------------------------- /cp/locks/resourcemanager/README.md: -------------------------------------------------------------------------------- 1 | ## *Concurrency with Go - Resource Manager* 2 | 3 | ResourceManager implements a deadlock avoidance strategy by finding cycles in a Ressource Allocation Graph. 4 | It blocks requests, when a resource is in use. The user is responsible to implement a retry strategy when a deadlock is recognized. 5 | 6 | The Resource Manager has two operations: 7 | 8 | 1. Acquire(processName, resourceName) bool 9 | 2. Release(processName, resourceName) 10 | 11 | If a resource is already in use, the Acquire() method blocks until the resource is free. 12 | The Acquire() method returns true if the resource could be claimed. In case of a deadlock the method returns false. 13 | It is up to the caller to retry the operation, if the resource is in use and the claim will produce a deadlock operation. 14 | 15 | ### Sample 16 | 17 | ``` 18 | Acquire ("P1", "R1" ) : P1 <- R1 (ok) - Process 1 got Resource 1 19 | Acquire ("P1", "R3" ) : P1 <- R3 (ok) - Process 1 got Resource 3 20 | Acquire ("P2", "R2" ) : P2 <- R2 (ok) - Process 2 got Resource 2 21 | Acquire ("P2", "R1" ) : P2 -> R1 (wait) - Process 2 cant get Resource 1 (in use by Process 1) : wait 22 | Acquire ("P1", "R2" ) returns false : P1 -> R2 (deadlock) - acquire will recognize the deadlock and returns false 23 | ``` 24 | 25 | ### Dining Philosophers 26 | ```go 27 | // take forks 28 | for !gotForks { 29 | gotForks := manager.Acquire("P" + id, "F" + id)) 30 | if gotForks { 31 | gotForks = manager.Acquire("P" + id, "F" + (id + 1) % COUNT) 32 | if !gotForks { // deadlock detected, release fork 33 | m.Release("P" + id, "F" + id)) 34 | } 35 | } else { 36 | // deadlock detected -> try again 37 | } 38 | } 39 | 40 | // eat 41 | 42 | // put forks 43 | manager.Release("P" + id, "F" + ((id + 1) % COUNT)) 44 | manager.Release("P" + id, "F" + id) 45 | ``` 46 | -------------------------------------------------------------------------------- /cp/locks/resourcemanager/resourcegraph.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package resourcemanager contains a blocking resource manger which avoids deadlocks 5 | package resourcemanager 6 | 7 | import ( 8 | "encoding/json" 9 | "fmt" 10 | ) 11 | 12 | // ResourceGraph is a simple RAG ResourceAllocationGraph. 13 | // A graph is a collection of edges. Each edge is of the form 14 | // edge := source -> [target1, target2, ... targetN] 15 | type ResourceGraph struct { 16 | edges map[string][]string 17 | } 18 | 19 | // NewResourceGraph creates an empty graph. 20 | func NewResourceGraph() *ResourceGraph { 21 | resourceGraph := new(ResourceGraph) 22 | resourceGraph.edges = make(map[string][]string) 23 | return resourceGraph 24 | } 25 | 26 | // AddLink adds a link to the graph. 27 | func (r *ResourceGraph) AddLink(source, dest string) { 28 | destinations := r.edges[source] 29 | destinations = append(destinations, dest) 30 | r.edges[source] = destinations 31 | } 32 | 33 | // RemoveLink removes a link from the graph. 34 | func (r *ResourceGraph) RemoveLink(source, dest string) { 35 | destinations := r.edges[source] 36 | destinations = removeItem(destinations, dest) 37 | if len(destinations) > 0 { 38 | r.edges[source] = destinations 39 | } else { 40 | delete(r.edges, source) // remove entry complete from map 41 | } 42 | } 43 | 44 | // Get destinations for a given source. 45 | func (r *ResourceGraph) Get(source string) []string { 46 | destinations := r.edges[source] 47 | return destinations 48 | } 49 | 50 | // DetectCycle reports true if there is a cycle between source and dest 51 | func (r *ResourceGraph) DetectCycle(source string, dest string) bool { 52 | return r.detectCycle1(source, source, dest) 53 | } 54 | 55 | // traverse the graph and check if dest is reachable from first 56 | func (r *ResourceGraph) detectCycle1(first string, source string, dest string) bool { 57 | 58 | if first == dest { 59 | return true 60 | } 61 | result := false 62 | destinations := r.edges[source] 63 | if destinations == nil { 64 | return result 65 | } 66 | 67 | for _, element := range destinations { 68 | result = result || r.detectCycle1(first, dest, element) 69 | } 70 | 71 | return result 72 | } 73 | 74 | // Stringer implementation. 75 | func (r *ResourceGraph) String() string { 76 | b, _ := json.MarshalIndent(r.edges, "", " ") 77 | return fmt.Sprintf("%v", string(b)) 78 | } 79 | 80 | // Helper removes an item from a string list. 81 | func removeItem(list []string, item string) []string { 82 | 83 | for i := len(list) - 1; i >= 0; i-- { 84 | v := list[i] 85 | if v == item { 86 | // found 87 | list[i] = list[len(list)-1] 88 | return list[0 : len(list)-1] 89 | } 90 | } 91 | return list // not found 92 | } 93 | -------------------------------------------------------------------------------- /cp/locks/resourcemanager/resourcegraph_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | package resourcemanager 4 | 5 | import ( 6 | "fmt" 7 | "testing" 8 | "time" 9 | ) 10 | 11 | // TestResourceGraph tests the resource graph. 12 | func TestResourceGraph(t *testing.T) { 13 | graph := NewResourceGraph() 14 | 15 | graph.AddLink("a", "b") 16 | graph.AddLink("a", "c") 17 | graph.AddLink("b", "c") 18 | 19 | // check no cycle 20 | if graph.DetectCycle("c", "a") { 21 | t.Error("c->a is not a cycle!") 22 | } 23 | 24 | // add a cycle 25 | graph.AddLink("c", "a") 26 | if !graph.DetectCycle("c", "a") { 27 | t.Error("c->a is a cycle!") 28 | } 29 | 30 | graph.RemoveLink("c", "a") 31 | if graph.DetectCycle("c", "a") { 32 | t.Error("c->a is not a cycle!") 33 | } 34 | } 35 | 36 | func TestSimpleResourceManager(t *testing.T) { 37 | manager := NewResourceManager() 38 | manager.Acquire("P1", "R1") 39 | manager.Acquire("P2", "R2") 40 | go manager.Acquire("P1", "R2") // should block 41 | fmt.Printf("%v", manager) 42 | manager.Release("P2", "R2") 43 | time.Sleep(10 * time.Millisecond) 44 | fmt.Printf("%v", manager) 45 | } 46 | 47 | // TestResourceManager tests the manager which blocks if a resource is in use and no deadlock is detected. 48 | // Acquire ("P1", "R1" ) : P1 <- R1 (ok) - Process 1 got Resource 1 49 | // Acquire ("P1", "R3" ) : P1 <- R3 (ok) - Process 1 got Resource 3 50 | // Acquire ("P2", "R2" ) : P2 <- R2 (ok) - Process 2 got Resource 2 51 | // Acquire ("P2", "R1" ) : P2 -> R1 (wait) - Process 2 cant get Resource 1 (in use by Process 1) : wait 52 | // Acquire ("P1", "R2" ) returns false : P1 -> R2 (deadlock) - acquire will recognize the deadlock and raturns false 53 | func TestResourceManager(t *testing.T) { 54 | 55 | manager := NewResourceManager() 56 | p1 := make(chan bool) 57 | p2 := make(chan bool) 58 | 59 | go func() { 60 | manager.Acquire("P1", "R1") 61 | manager.Acquire("P1", "R3") 62 | p1 <- true 63 | }() 64 | // block p1 until finished 65 | <-p1 66 | 67 | go func() { 68 | manager.Acquire("P2", "R2") 69 | p2 <- false 70 | manager.Acquire("P2", "R1") // waits 71 | p2 <- true 72 | }() 73 | 74 | if manager.Acquire("P1", "R1") { 75 | t.Error("P1/R2 should detect a deadlock and return false") 76 | } 77 | 78 | if <-p2 { 79 | t.Error("P2 should block when requesting R1") 80 | } 81 | 82 | manager.Release("P1", "R1") 83 | 84 | if !<-p2 { 85 | t.Error("P2 should not block anymore when requesting R1") 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /docs/01-1-About.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/01-1-About.pdf -------------------------------------------------------------------------------- /docs/01-2-Overview.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/01-2-Overview.pdf -------------------------------------------------------------------------------- /docs/01-3-Introduction to Golang.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/01-3-Introduction to Golang.pdf -------------------------------------------------------------------------------- /docs/01-3-Introduction to Golang.slide: -------------------------------------------------------------------------------- 1 | Introduction to Golang 2 | Concepts of Programming Languages 3 | 05 Oct 2020 4 | Tags: go, programming, master 5 | 6 | Bernhard Saumweber 7 | Rosenheim Technical University 8 | bernhard.saumweber@qaware.de 9 | http://www.qaware.de 10 | 11 | * Gopher 12 | .image https://talks.golang.org/2012/10things/gopher.jpg 13 | 14 | : Taschenratte (heimisch in Mittel- und Nordamerika) 15 | 16 | * Why Go? 17 | - Go is the major language behind the Cloud Native Stack 18 | .link https://www.cncf.io/ 19 | .image ./img/01-cncf-projects.png 100 1024 20 | - The most important components are written in Go: Docker, Kubernetes, etcd, Prometheus, Grafana, ... 21 | - Go is Open Source and maintained by Google 22 | - Go is a distributed, parallel language designed for systems programming at Google to solve the problems of C++ code. 23 | 24 | : 2007: Start der Entwicklung: Robert Griesemer, Rob Pike und Ken Thompson 25 | : 2009: Präsentation (Video inc) 26 | : 2012: Version 1 27 | : 2014: Erste Gopher-Konferenz 28 | 29 | * Hello World 30 | .play ../basics/hello/main.go 31 | 32 | * Palindrome 33 | .code ../basics/palindrome/palindrome.go /IsPalindrome/,/END1 OMIT/ 34 | .code ../basics/palindrome/palindrome_test.go /START OMIT/,/END OMIT/ 35 | 36 | * Introduction to Golang 37 | Rob Pike @ Google 2009 (60 Min) 38 | 39 | .link https://www.youtube.com/watch?v=rKnDgT73v8s 40 | .image img/01-go-programming-Language.png 450 700 41 | 42 | * Some Questions 43 | - What makes Go different to other Languages? 44 | - What makes Go similar to other Languages? 45 | - Discuss your personal opinions in a group of students! 46 | 47 | : Paradigmen: nebenläufig, imperativ, strukturiert, modular, objektorientiert 48 | : Ziele: Kompiliergeschwindigkeit, Nebenläufigkeit, Netzwerk- und Cloudcomputing 49 | : Keine dynamisch Typumwandlung, Typen müssen immer konvertiert werden 50 | : Zeiger, aber keine Zeigerarithmetik; Komposition statt Vererbung (Mixin) 51 | : OOP, aber nicht klassenbasiert; Polymorophie über Interfaces mit dynamische Bindung (zur Laufzeit passende Methode aufgerufen) 52 | : Nebenläufigkeit: Goroutinen, Channels 53 | 54 | * Exercise 1 55 | .link https://github.com/0xqab/concepts-of-programming-languages/blob/master/docs/exercises/Exercise1.md 56 | .image img/01-exercise.png 500 700 57 | 58 | * See also 59 | 60 | .link https://github.com/0xqab/concepts-of-programming-languages 61 | .link https://golang.org/ 62 | .link https://golang.org/doc/ 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /docs/02-Go Programming - Basics and OOP.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/02-Go Programming - Basics and OOP.pdf -------------------------------------------------------------------------------- /docs/03-Go-Programming-OOP.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/03-Go-Programming-OOP.pdf -------------------------------------------------------------------------------- /docs/04-Go-Programming-Parser.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/04-Go-Programming-Parser.pdf -------------------------------------------------------------------------------- /docs/05-Functional-Programming.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/05-Functional-Programming.pdf -------------------------------------------------------------------------------- /docs/06-Concurrent-Programming.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/06-Concurrent-Programming.pdf -------------------------------------------------------------------------------- /docs/07-Distributed-Programming-Raft.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/07-Distributed-Programming-Raft.pdf -------------------------------------------------------------------------------- /docs/08-WebAssembly.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/08-WebAssembly.pdf -------------------------------------------------------------------------------- /docs/09-Systems-Programming.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/09-Systems-Programming.pdf -------------------------------------------------------------------------------- /docs/10-Enterprise-Programming-Modules.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/10-Enterprise-Programming-Modules.pdf -------------------------------------------------------------------------------- /docs/11-Logic-Programming.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/11-Logic-Programming.pdf -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # How to use the Slides 2 | These slide files (.slide) are intended to be viewed with the 'present' tool. 3 | Use go get to install 'present.' 4 | 5 | $ go get code.google.com/p/go.talks/present 6 | 7 | You can start the slideshow by running the present tool 8 | 9 | $ present 10 | 11 | This will start a webserver. The current directory and all subdirs are served. 12 | 13 | Or use the provided Makefile: 14 | 15 | $ make slideshow 16 | 17 | This will also start the present tool. 18 | -------------------------------------------------------------------------------- /docs/exercises/Exercise1.md: -------------------------------------------------------------------------------- 1 | # Exercise 1 - Getting Started with Go 2 | 3 | If you do not finish during the lecture period, please finish it as homework. 4 | 5 | ## Setup 6 | 7 | - Install Go from inside a virtual disk 8 | (.vhdx on Windows or .sparseimage on Mac) in a /software/go subdirectory. 9 | 10 | - Win: 11 | - Mac: 12 | 13 | - Create a Go workspace on the disk in the <>/codebase/gopath directory 14 | - 15 | - Create a shell script (.sh / .cmd) to make your changes to the `GOPATH` and PATH environment variables persistent. 16 | - Create a Github project with your personal account containing a `HelloWorld.go` program 17 | - Use go get github.com/\<\\> to copy the repository into your local `GOPATH`. 18 | - Add `HelloWorld.go` to the checkout path and `commit / push` the file. 19 | - Test the `HelloWorld` program with "go run HelloWorld" 20 | - Optional: Install Visual Studio Code, IntelliJ or any other Editor with Go support inside your virtual disk. 21 | 22 | ## After this Exercise 23 | 24 | - You should know how to compile and run Go code 25 | - You should know about the meaning of the `GOPATH` and PATH variables 26 | - You should have a portable Go installation inside a separate disk or directory on your computer 27 | - Your personal Github project is cloned into your workspace. You are able to add, remove and commit files. 28 | -------------------------------------------------------------------------------- /docs/exercises/Exercise10.md: -------------------------------------------------------------------------------- 1 | # Exercise 10 - Enterprise Programming 2 | 3 | If you do not finish during the lecture period, please finish it as homework. 4 | 5 | ## Exercise 10.1 - Modules 6 | 7 | - Write a Go module mail with API and impl 8 | - The Mail implementation should log a message with logrus (https://github.com/sirupsen/logrus) 9 | - Change your module dependency to a former logrus version 10 | - Write a second Go module client which uses the mail module 11 | - Make an incompatible change to your mail API and increase the major version number 12 | 13 | ## Exercise 10.2 - Plugins 14 | 15 | - Export your Go mail module from the previous exercise to a mail plugin 16 | - The Mail implementation should log a message with logrus (https://github.com/sirupsen/logrus) 17 | - Write a third Go module client which uses the mail plugin and also logrus 18 | - Make an incompatible change to your mail API and increase the major version number 19 | - Try to use a different logrus version in the plugin (e.g. v1.7.0) and the client (e.g. v1.4.2) 20 | 21 | Windows users: use Golang in your Windows Subsystem for Linux or a Docker container. 22 | -------------------------------------------------------------------------------- /docs/exercises/Exercise2.1.md: -------------------------------------------------------------------------------- 1 | # Exercise 2.1 - Basics 2 | 3 | If you do not finish during the lecture period, please finish it as homework. 4 | 5 | ## Pointers (swap.go) 6 | 7 | - Write a function to swap two integer variables in the caller function (2 ways) 8 | - Write a function to swap two integer pointers in the caller function (2 ways) 9 | - Write test example code "ExampleSwap inside a swap_test file 10 | 11 | ### Questions 12 | 13 | What is the difference between a pointer and a Java object reference? 14 | What happens if you assign nil to a pointer variable and dereference the pointer? 15 | 16 | ## Book Index (Working with maps, arrays and slices) 17 | 18 | A Book Index is a inverted index which lists all pages a word occurs in a book. 19 | Write a program which generates an inverted index out of an array of book pages. 20 | Each Page contains an array of words. 21 | 22 | - Define custom types for Book, Page and Index 23 | - Make sure the Stringer() interface is implemented for Book and Index to make them printable 24 | - Write an unit test which generates a book and calculates the index and prints it to Stdout 25 | 26 | ## After this Exercise 27 | 28 | - You know difference between Pointers and Values 29 | - You know the basic Go container types: string, map, array, slice 30 | - You know how to make custom types printable 31 | - You know how to write basic unit tests 32 | -------------------------------------------------------------------------------- /docs/exercises/Exercise2.2.md: -------------------------------------------------------------------------------- 1 | # Exercise 2.2 - Basic OOP 2 | 3 | If you do not finish during the lecture period, please finish it as homework. 4 | 5 | ## Rational Numbers (Datatypes) 6 | 7 | Write a type for rational numbers (a/b). Implement a constructor, methods for adding and multiplying rational numbers. 8 | 9 | - Implement the euclidean algorithm for reducing rational numbers. Make sure the == and != operators work correct for 1/2 and 2/4 10 | - Write a constructor function to create rational numbers 11 | - The type should be immutable 12 | - Make sure to implement the Stringer() interface 13 | - Write an unit test to test the rational numbers 14 | - Check the test coverage. It should be greater than 80% 15 | 16 | ### Questions 17 | 18 | - What type has the receiver (pointer or value). Why? 19 | - What does immutable mean? Why is it good design to make Rational immutable? 20 | 21 | ## Stack (Containers) 22 | 23 | Write a generic LIFO container (stack) for all types. The stack should have at least four methods: 24 | 25 | - Push(object) 26 | - Pop() 27 | - Size() 28 | - GetAt(index) 29 | - Write a unit test which uses build in types and object types (Rational) inside the stack. Calculate the sum of all elements in the stack. 30 | 31 | ## After this Exercise 32 | 33 | - You should know how to write OO code in Go 34 | - You should how to reference other packages in your codebase 35 | - You should know the difference between object and data types 36 | - You should know how generic containers are built with Go 37 | -------------------------------------------------------------------------------- /docs/exercises/Exercise3.md: -------------------------------------------------------------------------------- 1 | # Exercise 3 - OOP in Go 2 | 3 | If you do not finish during the lecture period, please finish it as homework. 4 | 5 | ## Exercise 3.1 - Interfaces, Polymorphism and Embedding 6 | 7 | The image shows a typical UML design with inheritance, aggregation and polymorph methods. 8 | 9 | ![oo](../img/03-exercise.png "A typical OO design") 10 | 11 | Implement this design as close as possible to the design in Go: 12 | 13 | - The `Paint()` method should print the names and values of the fields to the console 14 | - Allocate an array of polymorph objects and call Paint() in a loop 15 | 16 | ## Exercise 3.2 - Mail Component and Service Locator 17 | 18 | Implement the following interface: 19 | 20 | ```go 21 | type Sender interface { 22 | // Send a mail to a given address with a subject and text. 23 | Send(message Message) error 24 | } 25 | ``` 26 | 27 | Implement the interface and write a client. The implementation should be provided by 28 | a simple self made service locator registry: 29 | 30 | ```go 31 | // Create an implementation for the mail.Sender interface 32 | var sender = Registry.Get("mail.Sender").(mail.Sender) 33 | 34 | email := mail.Message{To: to, Subject: subject, Text: text} 35 | return sender.Send(email) 36 | ``` 37 | 38 | Interface, client and implementation should be in separate packages. 39 | -------------------------------------------------------------------------------- /docs/exercises/Exercise5.md: -------------------------------------------------------------------------------- 1 | # Exercise 5 - Functional Programming in Go 2 | 3 | If you do not finish during the lecture period, please finish it as homework. 4 | 5 | ## Exercise 5.1 - Warm Up 6 | 7 | Write a Go Programm which shows the following concepts: 8 | 9 | - Functions as Variables 10 | - Anonymous Lambda Functions 11 | - High Order Functions (functions as parameters or return values) 12 | - Clojures (https://en.wikipedia.org/wiki/Closure_(computer_programming)) 13 | 14 | Compare the Syntax with Java. 15 | 16 | ## Exercise 5.2 - Functional Composition (g◦f)(x) 17 | 18 | Write a Go function to compose two *unknown* unary functions (one argument and one return value). The functions to compose should be arguments. 19 | Write a Unit Test for that function. 20 | 21 | ## Exercise 5.3 - Map / Filter / Reduce 22 | Map/Reduce is a famous functional construct implemented in many parallel and distributed collection frameworks like 23 | Hadoop, Apache Spark, Java Streams (not distributed but parallel), C# Linq 24 | 25 | - Implement a custom M/R API with the following interface: 26 | ```go 27 | type Stream interface { 28 | Map(m Mapper) Stream 29 | Filter(p Predicate) Stream 30 | Reduce(a Accumulator) Any 31 | } 32 | ``` 33 | The usage of the interface should be like this: 34 | ```go 35 | stringSlice := []Any{"a", "b", "c", "1", "D"} 36 | 37 | // Map/Reduce 38 | result := ToStream(stringSlice). 39 | Map(toUpperCase). 40 | Filter(notDigit). 41 | Reduce(concat).(string) 42 | 43 | if result != "A,B,C,D" { 44 | t.Error(fmt.Sprintf("Result should be 'A,B,C,D' but is: %v", result)) 45 | } 46 | ``` 47 | 48 | *Questions* 49 | - What is the type of Mapper, Predicate and Accumulator? 50 | - How can you make the types generic, so they work for any type, not only for string? 51 | 52 | ## Exercise 5.4 - Word Count (WC) 53 | Word Count is a famous algorithm for demonstrating the power of distributed collections and functional programming. 54 | Word Count counts how often a word (string) occurs in a collection. It is easy to address that problem with shared state (a map), but 55 | this solution does not scale well. 56 | The question here is how to use a pure functional algorithm to enable parallel and distributed execution. 57 | 58 | After running Word Count, you should get the following result: 59 | 60 | INPUT: "A" "B" "C" "A" "B" "A" 61 | 62 | OUTPUT: ("A":3) ("B":2) ("C":1) 63 | 64 | *Questions* 65 | - How can you implement the problem with the already built Map()/Filter()/Reduce() functions? 66 | - Write an Unit Test to prove that your solution works as expected! 67 | -------------------------------------------------------------------------------- /docs/exercises/Exercise6.md: -------------------------------------------------------------------------------- 1 | # Exercise 6 - Concurrent Programming in Go 2 | 3 | If you do not finish during the lecture period, please finish it as homework. 4 | 5 | ## Exercise 6.1 - Generator 6 | 7 | Write a generator for Fibonacci numbers, i.e. a function that returns a channel where the next Fibonacci number can be read. 8 | ```go 9 | func main() { 10 | fibChan := fib() // <- write func fib 11 | for n := 1; n <= 10; n++ { 12 | fmt.Printf("The %dth Fibonacci number is %d\n", n, <-fibChan) 13 | } 14 | } 15 | ``` 16 | Also write a test for the `fib()` function. 17 | 18 | ## Exercise 6.2 - Timeout 19 | 20 | Write a function `setTimeout()` that times out an operation after a given amount of time. Hint: Have a look at the built-in `time.After()` function and make use of the `select` statement. 21 | ```go 22 | func main() { 23 | res, err := setTimeout(func() int { 24 | time.Sleep(2000 * time.Millisecond) 25 | return 1 26 | }, 1*time.Second) 27 | 28 | if err != nil { 29 | fmt.Println(err.Error()) 30 | } else { 31 | fmt.Printf("operation returned %d", res) 32 | } 33 | } 34 | ``` 35 | Also write a test for the `setTimeout()` function. 36 | 37 | ## Exercise 6.3 - Dining Philosophers 38 | 39 | Write a program to simulate the Dining Philosophers Problem by using Go Channels. 40 | - There should be one Go Routine for each Philosopher and the Table 41 | - Make sure that: 42 | - The distribution of forks is fair - No philosopher dies on starvation 43 | - Use the given Unit Test: 44 | 45 | ```go 46 | func TestPhilosophers(t *testing.T) { 47 | 48 | var COUNT = 5 49 | 50 | // start table for 5 philosophers 51 | table := NewTable(COUNT) 52 | 53 | // create 5 philosophers and run parallel 54 | for i := 0; i < COUNT; i++ { 55 | philosopher := NewPhilosopher(i, table) 56 | go philosopher.run() 57 | } 58 | go table.run() 59 | 60 | // simulate 10 milliseconds --> check output 61 | time.Sleep(10 * time.Millisecond) 62 | } 63 | ``` 64 | 65 | Sample console output: 66 | 67 | ```sh 68 | [->]: Philosopher #0 eats ... 69 | [->]: Philosopher #3 eats ... 70 | [<-]: Philosopher #0 eat ends. 71 | [<-]: Philosopher #3 eat ends. 72 | [->]: Philosopher #0 thinks ... 73 | [->]: Philosopher #1 eats ... 74 | [->]: Philosopher #3 thinks ... 75 | [->]: Philosopher #4 eats ... 76 | [<-]: Philosopher #1 eat ends. 77 | [->]: Philosopher #1 thinks ... 78 | [<-]: Philosopher #4 eat ends. 79 | [->]: Philosopher #2 eats ... 80 | [->]: Philosopher #4 thinks ... 81 | [<-]: Philosopher #0 thinking ends 82 | [->]: Philosopher #0 eats ... 83 | [<-]: Philosopher #3 thinking ends 84 | ``` 85 | -------------------------------------------------------------------------------- /docs/exercises/Exercise7.md: -------------------------------------------------------------------------------- 1 | # Exercise 7 - Distributed Consensus and the Raft Algorithm 2 | 3 | If you do not finish during the lecture period, please finish it as homework. 4 | 5 | ## Exercise 7.1 - Read the Raft Paper 6 | 7 | Read the [Raft Paper](https://raft.github.io/raft.pdf): 8 | 9 | * Section 1 10 | * Section 2 11 | * Section 4 12 | * Section 5 (until including 5.3) 13 | 14 | ## Exercise 7.2 - Coding 15 | 16 | Be creative and write your own Raft Implementation! 17 | 18 | **Examples:** 19 | 20 | * Testable key value store using interfaces and goroutines: 21 | https://github.com/0xqab/concepts-of-programming-languages/tree/master/dp/kvstore/core/raft 22 | * Networkable implementation using gRPC (voting only): 23 | https://github.com/0xqab/concepts-of-programming-languages/tree/master/dp/raft 24 | * Highly abstracted from the paper: 25 | https://github.com/hashicorp/raft 26 | * More implementations: 27 | github.com/search?q=go-raft 28 | -------------------------------------------------------------------------------- /docs/exercises/exercise-1/Windows/codebase/bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/exercises/exercise-1/Windows/codebase/bin/.gitkeep -------------------------------------------------------------------------------- /docs/exercises/exercise-1/Windows/codebase/pkg/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/exercises/exercise-1/Windows/codebase/pkg/.gitkeep -------------------------------------------------------------------------------- /docs/exercises/exercise-1/Windows/codebase/src/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/exercises/exercise-1/Windows/codebase/src/.gitkeep -------------------------------------------------------------------------------- /docs/exercises/exercise-1/Windows/software/ascii-art.txt: -------------------------------------------------------------------------------- 1 | __ __ ____ _____ 2 | /\ \ /\ \__ /\ _`\ /\ __`\ 3 | \ \ \ __\ \ ,_\ ____ \ \ \L\_\ \ \/\ \ 4 | \ \ \ __ /'__`\ \ \/ /',__\ \ \ \L_L\ \ \ \ \ 5 | \ \ \L\ \/\ __/\ \ \_/\__, `\ \ \ \/, \ \ \_\ \ 6 | \ \____/\ \____\\ \__\/\____/ \ \____/\ \_____\ 7 | \/___/ \/____/ \/__/\/___/ \/___/ \/_____/ 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/exercises/exercise-1/Windows/software/set-env.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | type ascii-art.txt 4 | 5 | set SEU_HOME=G: 6 | 7 | set GOROOT=%SEU_HOME%\software\goroot 8 | set GOPATH=%SEU_HOME%\codebase 9 | set GOBIN=%SEU_HOME%\codebase\bin 10 | set PATH=%SEU_HOME%\software\goroot\bin;%PATH% 11 | -------------------------------------------------------------------------------- /docs/exercises/exercise-1/Windows/software/start-console.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | call set-env.cmd 3 | 4 | cd %SEU_HOME%\codebase\src 5 | cmd /k 6 | -------------------------------------------------------------------------------- /docs/exercises/exercise-1/macOS/.zshrc: -------------------------------------------------------------------------------- 1 | PROMPT=$'\n%B%~\n%#%b ' 2 | 3 | alias ll='ls -l' 4 | alias la='ls -la' 5 | -------------------------------------------------------------------------------- /docs/exercises/exercise-1/macOS/codebase/bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/exercises/exercise-1/macOS/codebase/bin/.gitkeep -------------------------------------------------------------------------------- /docs/exercises/exercise-1/macOS/codebase/pkg/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/exercises/exercise-1/macOS/codebase/pkg/.gitkeep -------------------------------------------------------------------------------- /docs/exercises/exercise-1/macOS/codebase/src/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/exercises/exercise-1/macOS/codebase/src/.gitkeep -------------------------------------------------------------------------------- /docs/exercises/exercise-1/macOS/software/ascii-art.txt: -------------------------------------------------------------------------------- 1 | __ __ ____ _____ 2 | /\ \ /\ \__ /\ _`\ /\ __`\ 3 | \ \ \ __\ \ ,_\ ____ \ \ \L\_\ \ \/\ \ 4 | \ \ \ __ /'__`\ \ \/ /',__\ \ \ \L_L\ \ \ \ \ 5 | \ \ \L\ \/\ __/\ \ \_/\__, `\ \ \ \/, \ \ \_\ \ 6 | \ \____/\ \____\\ \__\/\____/ \ \____/\ \_____\ 7 | \/___/ \/____/ \/__/\/___/ \/___/ \/_____/ 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/exercises/exercise-1/macOS/software/set-env: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | clear 4 | cat "$(dirname $0)/ascii-art.txt" 5 | 6 | export SEU_HOME="/Volumes/COPL" 7 | export GOROOT="$SEU_HOME/software/goroot" 8 | export GOPATH="$SEU_HOME/codebase" 9 | export GOBIN="$SEU_HOME/codebase/bin" 10 | export PATH="$GOBIN:$GOROOT/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin" 11 | 12 | export ZDOTDIR="$SEU_HOME" 13 | cd $SEU_HOME/codebase/src 14 | -------------------------------------------------------------------------------- /docs/exercises/exercise-1/macOS/software/start-console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | cd $(dirname $0) 4 | sh -c '. ./set-env && exec zsh -i' 5 | -------------------------------------------------------------------------------- /docs/img/00-programming-languages.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/00-programming-languages.jpeg -------------------------------------------------------------------------------- /docs/img/01-cncf-projects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/01-cncf-projects.png -------------------------------------------------------------------------------- /docs/img/01-exercise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/01-exercise.png -------------------------------------------------------------------------------- /docs/img/01-go-programming-language.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/01-go-programming-language.png -------------------------------------------------------------------------------- /docs/img/01-languages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/01-languages.png -------------------------------------------------------------------------------- /docs/img/02-complex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/02-complex.png -------------------------------------------------------------------------------- /docs/img/02-exercise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/02-exercise.png -------------------------------------------------------------------------------- /docs/img/03-exercise.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/03-exercise.key -------------------------------------------------------------------------------- /docs/img/03-exercise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/03-exercise.png -------------------------------------------------------------------------------- /docs/img/04-lambda.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-lambda.key -------------------------------------------------------------------------------- /docs/img/04-lambda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-lambda.png -------------------------------------------------------------------------------- /docs/img/04-parsers/01-practice-go.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/01-practice-go.gif -------------------------------------------------------------------------------- /docs/img/04-parsers/02-menti.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/02-menti.png -------------------------------------------------------------------------------- /docs/img/04-parsers/02-parsers-for-what.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/02-parsers-for-what.png -------------------------------------------------------------------------------- /docs/img/04-parsers/03-parsers-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/03-parsers-overview.png -------------------------------------------------------------------------------- /docs/img/04-parsers/04-ast-vs-cst.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/04-ast-vs-cst.png -------------------------------------------------------------------------------- /docs/img/04-parsers/05-tree-terms.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/05-tree-terms.png -------------------------------------------------------------------------------- /docs/img/04-parsers/05-whaat.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/05-whaat.gif -------------------------------------------------------------------------------- /docs/img/04-parsers/Parsers.006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/Parsers.006.png -------------------------------------------------------------------------------- /docs/img/04-parsers/Parsers.007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/Parsers.007.png -------------------------------------------------------------------------------- /docs/img/04-parsers/Parsers.008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/Parsers.008.png -------------------------------------------------------------------------------- /docs/img/04-parsers/Parsers.009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/Parsers.009.png -------------------------------------------------------------------------------- /docs/img/04-parsers/Parsers.010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/Parsers.010.png -------------------------------------------------------------------------------- /docs/img/04-parsers/Parsers.011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/Parsers.011.png -------------------------------------------------------------------------------- /docs/img/04-parsers/programming.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/04-parsers/programming.png -------------------------------------------------------------------------------- /docs/img/06-dining-philosophers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/06-dining-philosophers.png -------------------------------------------------------------------------------- /docs/img/06-go-concurrency.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/06-go-concurrency.jpeg -------------------------------------------------------------------------------- /docs/img/06-moores-law.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/06-moores-law.png -------------------------------------------------------------------------------- /docs/img/06-philosophers-channel.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/06-philosophers-channel.jpeg -------------------------------------------------------------------------------- /docs/img/06-philosophers-channel.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/06-philosophers-channel.key -------------------------------------------------------------------------------- /docs/img/07-idserv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/07-idserv.png -------------------------------------------------------------------------------- /docs/img/07-parallel-distributed.key: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/07-parallel-distributed.key -------------------------------------------------------------------------------- /docs/img/07-parallel-distributed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/07-parallel-distributed.png -------------------------------------------------------------------------------- /docs/img/07-proxy-pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/07-proxy-pattern.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/01-01-mvp-03-final-e1539905426663-768x664.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/01-01-mvp-03-final-e1539905426663-768x664.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/01-02-heavyweight-03-P-07-e1540219610872-768x551.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/01-02-heavyweight-03-P-07-e1540219610872-768x551.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/01-02-heavyweight-04-final-e1540219657102-768x696.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/01-02-heavyweight-04-final-e1540219657102-768x696.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/01-04-js-interop-00-A-768x432.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/01-04-js-interop-00-A-768x432.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/01-04-js-interop-02-P-05-e1540220264112-768x395.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/01-04-js-interop-02-P-05-e1540220264112-768x395.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/01-04-js-interop-03-final-e1540220313636-768x415.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/01-04-js-interop-03-final-e1540220313636-768x415.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/01-05-high-level-03-P-04-e1540220662110-768x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/01-05-high-level-03-P-04-e1540220662110-768x240.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/01-05-high-level-04-final-e1540220704600-768x621.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/01-05-high-level-04-final-e1540220704600-768x621.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/01-07-runtime-09-final-e1539904436477-768x489.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/01-07-runtime-09-final-e1539904436477-768x489.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/0a-all-browsers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/0a-all-browsers.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/0a-bytecode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/0a-bytecode.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/0a-javascript-compilation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/0a-javascript-compilation.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/0a-portability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/0a-portability.png -------------------------------------------------------------------------------- /docs/img/08-webassembly/0a-webassembly-compilation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/08-webassembly/0a-webassembly-compilation.png -------------------------------------------------------------------------------- /docs/img/10-conflicting-versions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/10-conflicting-versions.png -------------------------------------------------------------------------------- /docs/img/go.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/img/go.png -------------------------------------------------------------------------------- /docs/snippets/cp: -------------------------------------------------------------------------------- 1 | f("hello", "world") // f runs; we wait 2 | 3 | go f("hello", "world") // f starts running 4 | g() // does not wait for f to return 5 | 6 | timerChan := make(chan time.Time) 7 | go func() { 8 | time.Sleep(deltaT) 9 | timerChan <- time.Now() // send time on timerChan 10 | }() 11 | 12 | // Do something else; when ready, receive. 13 | // Receive will block until timerChan delivers. 14 | // Value sent is other goroutine's completion time. 15 | completedAt := <-timerChan 16 | 17 | select { 18 | case v := <-ch1: 19 | fmt.Println("channel 1 sends", v) 20 | case v := <-ch2: 21 | fmt.Println("channel 2 sends", v) 22 | default: // optional 23 | fmt.Println("neither channel was ready") 24 | } 25 | 26 | func Query(conns []Conn, query string) Result { 27 | ch := make(chan Result, len(conns)) // buffered 28 | for _, conn := range conns { 29 | go func(c Conn) { 30 | ch <- c.DoQuery(query): 31 | }(conn) 32 | } 33 | return <-ch 34 | } 35 | 36 | func XQuery(conns []Conn, query string) Result { 37 | ch := make(chan Result, 1) // buffer of 1 item 38 | for _, conn := range conns { 39 | go func(c Conn) { 40 | select { 41 | case ch <- c.DoQuery(query): 42 | // nothing to do 43 | default: // executes if ch is blocked 44 | // nothing to do 45 | } 46 | }(conn) 47 | } 48 | return <-ch 49 | } 50 | 51 | 52 | func Compose(f, g func(x float) float) 53 | func(x float) float { 54 | return func(x float) float { 55 | return f(g(x)) 56 | } 57 | } 58 | 59 | print(Compose(sin, cos)(0.5)) 60 | 61 | go func() { // copy input to output 62 | for val := range input { 63 | output <- val 64 | } 65 | }() 66 | -------------------------------------------------------------------------------- /docs/studywork/Study-Work-Presentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/studywork/Study-Work-Presentation.pdf -------------------------------------------------------------------------------- /docs/studywork/Study-Work-Presentation.slide: -------------------------------------------------------------------------------- 1 | Semester Work 2 | Concepts of Programming Languages 3 | 12 Dec 2019 4 | Tags: go, programming, concurrent, go routines, channels 5 | 6 | Johannes Weigend 7 | Rosenheim Technical University 8 | johannes.weigend@qaware.de 9 | http://www.qaware.de 10 | 11 | * Semester Work 12 | - 15 Minutes presentation (in German) 13 | - 15.000 - 20.000 character Asciidoc document (in English) 14 | - Sourcecode + Unit Tests + Buildscript on Github (Tagged Version required) 15 | - Deadline - 01-08-2020 - EOB - Delivery per Mail to johannes.weigend@qaware.de 16 | - Where: QAware Office Rosenheim, Brückenstr. 1, 2.OG 17 | 18 | * Timeline - 01-09-2020 19 | 9:45 - 13:15 - Functional Boolparser + Single Process Raft 20 | 21 | - Compare Functional Programming. Go with *F#*: Victor Wolf 22 | - Compare Functional Programming. Go with *Haskell*: Veronika Holzmayer 23 | - Compare Functional Programming. Go with *JavaScript*: Markus Voit 24 | - Compare Functional Programming. Go with *Objective* *C*: Simon Treutlein 25 | 26 | - Compare Parallel Programming. Go with *Python*: Lukas Kiederle 27 | - Compare Parallel Programming. Go with *Scala*: Max Bundscherer 28 | 29 | * Timeline - 01-16-2020 30 | 9:45 - 12:00 - OOP Boolparser + Distributed Raft Microservice 31 | 32 | - Compare Object Oriented Programming. Go with *Smalltalk*: Markus Kaleta 33 | - Compare Object Oriented Programming. Go with *TypeScript*: Alexander Hauenstein 34 | - Compare Object Oriented Programming. Go with *Ruby*: Alexander Hennecke 35 | 36 | - Compare Distributed Programming. Go with *Kotlin*: Tobias Lautenschlager 37 | -------------------------------------------------------------------------------- /docs/studywork/StudyWork.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/studywork/StudyWork.xlsx -------------------------------------------------------------------------------- /docs/studywork/studywork.slide: -------------------------------------------------------------------------------- 1 | 2 | 3 | * Functional 4 | Compare Functional Programming in Go with Elixir 5 | Compare Functional Programming in Go with F# 6 | Compare Functional Programming in Go with Haskell 7 | Compare Functional Programming in Go with JavaScript 8 | 9 | * OOP 10 | Compare Object Oriented Programming in Go with Objective C 11 | Compare Object Oriented Programming in Go with Smalltalk 12 | Compare Object Oriented Programming in Go with Ruby 13 | Compare Object Oriented Programming in Go with Swift 14 | Compare Object Oriented Programming in Go with Ada 15 | Compare Object Oriented Programming in Go with TypeScript 16 | Compare Object Oriented Programming in Go with Pascal 17 | Compare Object Oriented Programming in Go with Lua 18 | Compare Object Oriented Programming in Go with Eiffel 19 | 20 | * Parallel 21 | Compare Go Parallel Programming with Python 22 | Compare Go Parallel Programming with Scala 23 | Compare Go Parallel Programming with Erlang 24 | 25 | * Distributed 26 | Compare Go Distributed Programming with Rust 27 | Compare Go Distributed Programming with Kotlin 28 | Compare Go Distributed Programming with Julia 29 | -------------------------------------------------------------------------------- /docs/talks/raft/Implementing Raft.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/docs/talks/raft/Implementing Raft.pptx -------------------------------------------------------------------------------- /dp/idserv/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Makefile. Usage: make . 3 | # 4 | 5 | 6 | help: 7 | clear 8 | @echo "---------------------------------------------------------------------------------------------------------" 9 | @echo "Usage: make " 10 | @echo "---------------------------------------------------------------------------------------------------------" 11 | @echo "Valid targets are:" 12 | @echo " - ginstall : Installs / Updates the GRPC Go Libraries " 13 | @echo " - gcompile : Compiles the .pb protocol files" 14 | @echo " - run-server : Compiles and starts the server" 15 | @echo " - run-client : Compiles and runs the client" 16 | @echo " - clean : Clean up generated files" 17 | @echo "---------------------------------------------------------------------------------------------------------" 18 | 19 | ginstall: 20 | go get -u google.golang.org/grpc 21 | go get -u github.com/golang/protobuf/protoc-gen-go 22 | echo Make sure that protoc is installed for your platform 23 | 24 | gcompile: 25 | protoc -I remote/idserv/ remote/idserv/idserv.proto --go_out=plugins=grpc:remote/idserv 26 | 27 | clean: 28 | rm remote/idserv/*.pb.go 29 | 30 | run-server: 31 | go run remote/server/main.go 32 | 33 | run-client: 34 | go run client/main.go 35 | 36 | -------------------------------------------------------------------------------- /dp/idserv/client/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | package main 4 | 5 | import ( 6 | "log" 7 | 8 | "github.com/0xqab/concepts-of-programming-languages/dp/idserv" 9 | "github.com/0xqab/concepts-of-programming-languages/dp/idserv/core" 10 | "github.com/0xqab/concepts-of-programming-languages/dp/idserv/remote/proxy" 11 | ) 12 | 13 | // GenerateIds calls n-times NewUUID() in a loop and returns the result as slice. 14 | func GenerateIds(count int, service idserv.IDService) []string { 15 | result := make([]string, count) 16 | for i := 0; i < count; i++ { 17 | result[i] = service.NewUUID("c1") 18 | } 19 | return result 20 | } 21 | 22 | func main() { 23 | var service idserv.IDService 24 | 25 | // Local 26 | service = core.NewIDServiceImpl() 27 | result := GenerateIds(10, service) 28 | 29 | log.Printf("Got Id: %v", result) 30 | 31 | // Remote 32 | service = proxy.NewProxy() 33 | result = GenerateIds(10, service) 34 | 35 | log.Printf("Got Id: %v", result) 36 | } 37 | -------------------------------------------------------------------------------- /dp/idserv/core/idserv-impl.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package impl contains the business logic of the IDService 5 | package core 6 | 7 | import ( 8 | "fmt" 9 | "sync/atomic" 10 | ) 11 | 12 | // IDServiceImpl type 13 | type IDServiceImpl struct { 14 | } 15 | 16 | // The last given Id. 17 | var lastID int64 18 | 19 | // NewIDServiceImpl creates a new instance 20 | func NewIDServiceImpl() *IDServiceImpl { 21 | return new(IDServiceImpl) 22 | } 23 | 24 | // NewUUID implements the IDService interface. 25 | func (ids *IDServiceImpl) NewUUID(clientID string) string { 26 | result := atomic.AddInt64(&lastID, 1) 27 | return fmt.Sprintf("%v:%v", clientID, result) 28 | } 29 | -------------------------------------------------------------------------------- /dp/idserv/idserv-api.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package idserv contains the IDService API. 5 | package idserv 6 | 7 | // IDService can be used to produce network wide unique ids. 8 | type IDService interface { 9 | 10 | // NewUUID generates an UUID with a given client prefix. 11 | NewUUID(clientID string) string 12 | } 13 | -------------------------------------------------------------------------------- /dp/idserv/remote/idserv/idserv.proto: -------------------------------------------------------------------------------- 1 | 2 | syntax = "proto3"; 3 | 4 | package idserv; 5 | 6 | // The IDService definition 7 | service IDService { 8 | // NewUUID generates a globally unique ID 9 | rpc NewUUID (IdRequest) returns (IdReply) {} 10 | } 11 | 12 | // The client sends a unique id. 13 | message IdRequest { 14 | string clientId = 1; 15 | } 16 | 17 | // The response message contains the uuid. 18 | message IdReply { 19 | string uuid = 1; 20 | } -------------------------------------------------------------------------------- /dp/idserv/remote/proxy/proxy.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package proxy contains the client side proxy. 5 | package proxy 6 | 7 | import ( 8 | "context" 9 | "fmt" 10 | "log" 11 | "time" 12 | 13 | "github.com/0xqab/concepts-of-programming-languages/dp/idserv/remote/idserv" 14 | "google.golang.org/grpc" 15 | ) 16 | 17 | const ( 18 | address = "localhost:50051" 19 | defaultName = "client" 20 | ) 21 | 22 | // Proxy is a client side proxy which encapsulates the RPC logic. It implements the IDService interface. 23 | type Proxy struct { 24 | connection *grpc.ClientConn 25 | } 26 | 27 | // NewProxy creates a Proxy and starts the server connection 28 | func NewProxy() *Proxy { 29 | p := new(Proxy) 30 | conn, err := grpc.Dial(address, grpc.WithInsecure()) 31 | if err != nil { 32 | panic(fmt.Sprintf("did not connect: %v", err)) 33 | } 34 | p.connection = conn 35 | return p 36 | } 37 | 38 | // NewUUID implements the IDService interface. 39 | func (p *Proxy) NewUUID(clientID string) string { 40 | c := idserv.NewIDServiceClient(p.connection) 41 | ctx, cancel := context.WithTimeout(context.Background(), time.Second) 42 | defer cancel() 43 | r, err := c.NewUUID(ctx, &idserv.IdRequest{ClientId: clientID}) 44 | if err != nil { 45 | log.Printf("could not generate id: %v", err) 46 | r.Uuid = "" 47 | } 48 | return r.Uuid 49 | } 50 | -------------------------------------------------------------------------------- /dp/idserv/remote/server/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | package main 4 | 5 | import ( 6 | "log" 7 | "net" 8 | 9 | "github.com/0xqab/concepts-of-programming-languages/dp/idserv/remote/idserv" 10 | "github.com/0xqab/concepts-of-programming-languages/dp/idserv/remote/stub" 11 | "google.golang.org/grpc" 12 | "google.golang.org/grpc/reflection" 13 | ) 14 | 15 | const ( 16 | port = ":50051" 17 | ) 18 | 19 | func main() { 20 | lis, err := net.Listen("tcp", port) 21 | if err != nil { 22 | log.Fatalf("failed to listen: %v", err) 23 | } 24 | s := grpc.NewServer() 25 | idserv.RegisterIDServiceServer(s, &stub.Server{}) 26 | // Register reflection service on gRPC server. 27 | reflection.Register(s) 28 | if err := s.Serve(lis); err != nil { 29 | log.Fatalf("failed to serve: %v", err) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /dp/idserv/remote/stub/idserv-stub.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | package stub 5 | 6 | import ( 7 | "context" 8 | 9 | "github.com/0xqab/concepts-of-programming-languages/dp/idserv/core" 10 | "github.com/0xqab/concepts-of-programming-languages/dp/idserv/remote/idserv" 11 | ) 12 | 13 | // Server is used to implement idserv.IdServer 14 | type Server struct{} 15 | 16 | // NewUUID implements idserv.IdService interface 17 | func (s *Server) NewUUID(c context.Context, r *idserv.IdRequest) (*idserv.IdReply, error) { 18 | service := core.IDServiceImpl{} 19 | return &idserv.IdReply{Uuid: service.NewUUID(r.GetClientId())}, nil 20 | } 21 | -------------------------------------------------------------------------------- /dp/kvstore/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/dp/kvstore/Makefile -------------------------------------------------------------------------------- /dp/kvstore/README.md: -------------------------------------------------------------------------------- 1 | # DKVS 2 | ## A Distributed Key Value Store 3 | 4 | KV-Store is a simple, non-persistent distributed Key Value Store with a REST- and GRPC API. 5 | 6 | ```sh 7 | // Copyright 2018 Johannes Weigend 8 | // 9 | // Licensed under the Apache License, Version 2.0 (the "License"); 10 | // you may not use this file except in compliance with the License. 11 | // You may obtain a copy of the License at 12 | // 13 | // http://www.apache.org/licenses/LICENSE-2.0 14 | // 15 | // Unless required by applicable law or agreed to in writing, software 16 | // distributed under the License is distributed on an "AS IS" BASIS, 17 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | // See the License for the specific language governing permissions and 19 | // limitations under the License. 20 | ``` 21 | 22 | The consistency of data is guaranteed by using the RAFT Algorithm: 23 | 24 | http://thesecretlivesofdata.com/raft/ 25 | https://raft.github.io/ 26 | 27 | -------------------------------------------------------------------------------- /dp/kvstore/core/kvstore-impl.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | // KVStore is a distributed key value store using RAFT consensus. 4 | type KVStore struct { 5 | committedData map[string]string 6 | } 7 | 8 | // NewKVStore constructs a new KVStore. 9 | func NewKVStore() *KVStore { 10 | return new(KVStore) 11 | } 12 | 13 | // SetString sets a value for a given key. 14 | func (k *KVStore) SetString(key, value string) { 15 | // Make the new value visible (async) when the majority of cluster members have written it to the logfile. 16 | go func() { 17 | // success - more than 50% of all cluster member have written the value to their logs 18 | k.committedData[key] = value 19 | }() 20 | } 21 | 22 | // GetString returns the value for a given key. 23 | func (k *KVStore) GetString(key string) string { 24 | return k.committedData[key] 25 | } 26 | -------------------------------------------------------------------------------- /dp/kvstore/core/raft/cluster.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package raft is an implementation of the RAFT consensus algorithm. 5 | package raft 6 | 7 | import "errors" 8 | 9 | // Cluster knows the RPC interface of all members. 10 | // The cluster works with multiple nodes for testing or with RPC proxies for remote access in a distributed scenario. 11 | type Cluster struct { 12 | allNodes []*Node 13 | } 14 | 15 | // NewCluster constructs a new cluster with all Node RPC interfaces. 16 | // For local test the NodeRPC is the Node itself. For distributed operation the NodeRPC is a proxy. 17 | func NewCluster(allNodes []*Node) *Cluster { 18 | return &Cluster{allNodes} 19 | } 20 | 21 | // GetRemoteFollowers return the NodeRPC If of all nodes. 22 | func (c *Cluster) GetRemoteFollowers(leaderID int) []NodeRPC { 23 | buf := make([]NodeRPC, len(c.allNodes)-1) 24 | j := 0 25 | for i, n := range c.allNodes { 26 | if i == leaderID { 27 | continue 28 | } 29 | buf[j] = n 30 | j++ 31 | } 32 | return buf 33 | } 34 | 35 | // StartAll stops all nodes in the cluster. 36 | func (c *Cluster) StartAll() { 37 | for _, n := range c.allNodes { 38 | n.Start(c) 39 | } 40 | } 41 | 42 | // StopAll stops all nodes in the cluster. 43 | func (c *Cluster) StopAll() { 44 | for _, n := range c.allNodes { 45 | n.Stop() 46 | } 47 | } 48 | 49 | // StopLeader stops the leader in the cluster. 50 | func (c *Cluster) StopLeader() *Node { 51 | for _, n := range c.allNodes { 52 | if n.isLeader() { 53 | n.Stop() 54 | return n 55 | } 56 | } 57 | return nil // no leader found 58 | } 59 | 60 | // Check checks if a cluster is in a valid state. 61 | // There should be exact one leader. 62 | func (c *Cluster) Check() (bool, error) { 63 | leaderCount := 0 64 | followerCount := 0 65 | candidateCount := 0 66 | for _, n := range c.allNodes { 67 | if n.isLeader() { 68 | leaderCount++ 69 | } else if n.isCandidate() { 70 | candidateCount++ 71 | } else if n.isFollower() { 72 | followerCount++ 73 | } 74 | } 75 | if leaderCount > 1 { 76 | return false, errors.New("there are multiple leaders in the cluster") 77 | } else if leaderCount == 0 { 78 | return false, errors.New("there is no leader in the cluster") 79 | } else if followerCount < len(c.allNodes)/2 { 80 | return false, errors.New("there are not enough followers -> split brain") 81 | } 82 | return true, nil 83 | } 84 | -------------------------------------------------------------------------------- /dp/kvstore/core/raft/cluster_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package raft is an implementation of the RAFT consensus algorithm. 5 | package raft 6 | 7 | import ( 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func TestBigCluster(t *testing.T) { 13 | 14 | n1 := NewNode(0) 15 | n2 := NewNode(1) 16 | n3 := NewNode(2) 17 | n4 := NewNode(3) 18 | n5 := NewNode(4) 19 | 20 | nodes := []*Node{n1, n2, n3, n4, n5} 21 | 22 | cluster := NewCluster(nodes) 23 | 24 | cluster.StartAll() 25 | 26 | time.Sleep(10000 * time.Millisecond) 27 | 28 | ok, err := cluster.Check() 29 | if !ok { 30 | t.Error(err) 31 | } 32 | 33 | cluster.StopAll() 34 | time.Sleep(1000 * time.Millisecond) // wait for grace shutdown 35 | } 36 | 37 | func TestHeartbeat(t *testing.T) { 38 | // single node cluster 39 | n1 := NewNode(0) 40 | nodes := []*Node{n1} 41 | n1.cluster = NewCluster(nodes) 42 | 43 | // startHeartbeat is only allowed in leader state 44 | n1.statemachine.Next(CANDIDATE) 45 | n1.statemachine.Next(LEADER) 46 | n1.heartbeatTimer.resetC <- true 47 | 48 | // wait two second --> check console output 49 | time.Sleep(2000 * time.Millisecond) 50 | n1.Stop() 51 | } 52 | -------------------------------------------------------------------------------- /dp/kvstore/core/raft/configuration.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package raft is an implementation of the RAFT consensus algorithm. 5 | package raft 6 | 7 | // Configuration contains setup information for initializing a remote cluster. 8 | type Configuration struct { 9 | } 10 | -------------------------------------------------------------------------------- /dp/kvstore/core/raft/node-utils.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package raft is an implementation of the RAFT consensus algorithm. 5 | package raft 6 | 7 | import ( 8 | "log" 9 | "time" 10 | ) 11 | 12 | func (n *Node) log(msg string) { 13 | log.Printf("[%v] [%v] [%v] : %v", n.id, n.statemachine.Current(), n.currentTerm, msg) 14 | } 15 | 16 | func (n *Node) isLeader() bool { 17 | return n.statemachine.Current() == LEADER 18 | } 19 | 20 | func (n *Node) isFollower() bool { 21 | return n.statemachine.Current() == FOLLOWER 22 | } 23 | 24 | func (n *Node) isCandidate() bool { 25 | return n.statemachine.Current() == CANDIDATE 26 | } 27 | 28 | func (n *Node) isNotLeader() bool { 29 | return n.isFollower() || n.isCandidate() 30 | } 31 | 32 | type timercontrol struct { 33 | stopC chan bool 34 | resetC chan bool 35 | } 36 | 37 | func createPeriodicTimer(d func() time.Duration, timeout func()) timercontrol { 38 | stopC := make(chan bool) 39 | resetC := make(chan bool) 40 | go func() { 41 | timer := time.NewTimer(d()) 42 | timer.Stop() // Timer must be started explicit by using the reset channel 43 | for { 44 | select { 45 | case <-stopC: 46 | // log.Println("Timer Stopped") 47 | timer.Stop() 48 | break 49 | case <-timer.C: 50 | // log.Println("Timer Timeout") 51 | timer.Stop() 52 | timer.Reset(d()) 53 | go timeout() 54 | break 55 | case <-resetC: 56 | // log.Println("Timer Reset") 57 | timer.Stop() 58 | timer.Reset(d()) 59 | } 60 | } 61 | }() 62 | return timercontrol{stopC, resetC} 63 | } 64 | -------------------------------------------------------------------------------- /dp/kvstore/core/raft/node_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package raft is an implementation of the RAFT consensus algorithm. 5 | package raft 6 | 7 | import ( 8 | "testing" 9 | "time" 10 | ) 11 | 12 | func TestElection(t *testing.T) { 13 | 14 | n1 := NewNode(0) 15 | n2 := NewNode(1) 16 | n3 := NewNode(2) 17 | 18 | nodes := []*Node{n1, n2, n3} 19 | cluster := NewCluster(nodes) 20 | defer cluster.StopAll() 21 | 22 | cluster.StartAll() 23 | 24 | time.Sleep(4000 * time.Millisecond) 25 | 26 | ok, err := cluster.Check() 27 | if !ok { 28 | t.Error(err) 29 | } 30 | 31 | cluster.StopAll() 32 | } 33 | 34 | func TestFailover(t *testing.T) { 35 | 36 | n1 := NewNode(0) 37 | n2 := NewNode(1) 38 | n3 := NewNode(2) 39 | 40 | nodes := []*Node{n1, n2, n3} 41 | cluster := NewCluster(nodes) 42 | 43 | cluster.StartAll() 44 | defer cluster.StopAll() 45 | 46 | time.Sleep(5000 * time.Millisecond) 47 | 48 | cluster.StopLeader() 49 | 50 | time.Sleep(5000 * time.Millisecond) 51 | 52 | ok, err := cluster.Check() 53 | if !ok { 54 | t.Error(err) 55 | } 56 | } 57 | 58 | func TestFailoverResume(t *testing.T) { 59 | 60 | n1 := NewNode(0) 61 | n2 := NewNode(1) 62 | n3 := NewNode(2) 63 | 64 | nodes := []*Node{n1, n2, n3} 65 | 66 | cluster := NewCluster(nodes) 67 | 68 | cluster.StartAll() 69 | defer cluster.StopAll() 70 | 71 | time.Sleep(5000 * time.Millisecond) 72 | 73 | // stop leader 74 | ns := cluster.StopLeader() 75 | 76 | time.Sleep(6000 * time.Millisecond) 77 | 78 | // resume old leader -> get follower 79 | ns.Start(cluster) 80 | 81 | time.Sleep(2000 * time.Millisecond) 82 | 83 | ok, err := cluster.Check() 84 | if !ok { 85 | t.Error(err) 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /dp/kvstore/core/raft/noderpc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package raft is an implementation of the RAFT consensus algorithm. 5 | package raft 6 | 7 | // NodeRPC is the remote interface for Node to Node communication in the RAFT cluster. 8 | type NodeRPC interface { 9 | 10 | // AppendEntries is used by the Leader to replicate logs and it is used as heartbeat. 11 | // The Leader will call the AppendEntries method on all nodes in the cluster. 12 | // Arguments 13 | // - term : leaders term 14 | // - leaderId : leadersId to redirect calls to leader 15 | // - prevLogIndex : Index of log entry immediately processing 16 | // - prevLogTerm : Term of the prevLogIndex entry 17 | // - entries : log entries to store (empty for heartbeat) 18 | // - leaderCommit : leaders commit index 19 | // Results 20 | // - term : current termin (for leader, update itself) 21 | // - success : true if follower contained entry matching prevLogIndex and prevLogTerm 22 | AppendEntries(term, leaderID, prevLogIndex, prevLogTerm int, entries []string, 23 | leaderCommit int) (int, bool) 24 | 25 | // RequestVote is called by candidates to gather votes. 26 | // It returns the current term to update the candidate 27 | // It returns true when the candidate received vote. 28 | // Arguments 29 | // - term : candidates term 30 | // - candidateID : candidate requesting vote 31 | // - lastLogIndex : index of candidates last log entry 32 | // - lastLogTerm : term of candidates last log entry 33 | // Results 34 | // - term : the current term, for candidate to update itself 35 | // - voteGranted : true means candidate received vote 36 | RequestVote(term, candidateID, lastLogIndex, lastLogTerm int) (int, bool) 37 | } 38 | -------------------------------------------------------------------------------- /dp/kvstore/core/raft/replicatedlog.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package raft is an implementation of the RAFT consensus algorithm. 5 | package raft 6 | 7 | // ReplicatedLog is the transactional log for RAFT. 8 | type ReplicatedLog struct { 9 | } 10 | 11 | // NewReplicatedLog constructs a ReplicatedLog. 12 | func NewReplicatedLog() *ReplicatedLog { 13 | return new(ReplicatedLog) 14 | } 15 | -------------------------------------------------------------------------------- /dp/kvstore/core/raft/timer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package raft is an implementation of the RAFT consensus algorithm. 5 | package raft 6 | 7 | import ( 8 | "log" 9 | "testing" 10 | "time" 11 | ) 12 | 13 | func TestTimer(t *testing.T) { 14 | 15 | tc := createPeriodicTimer(func() time.Duration { 16 | return time.Duration(1000) * time.Millisecond 17 | }, func() { log.Println("Timeout") }) 18 | 19 | tc.resetC <- true 20 | time.Sleep(2 * time.Second) 21 | tc.stopC <- true 22 | time.Sleep(1 * time.Second) 23 | tc.resetC <- true 24 | time.Sleep(500 * time.Millisecond) 25 | tc.resetC <- true 26 | time.Sleep(500 * time.Millisecond) 27 | tc.resetC <- true 28 | 29 | time.Sleep(5 * time.Second) 30 | } 31 | -------------------------------------------------------------------------------- /dp/kvstore/kvstore-api.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package kvstore contains the KeyValueStore API. 5 | package kvstore 6 | 7 | // KVStore is the business interface to a distributed key value store. 8 | type KVStore interface { 9 | 10 | // Sets a value for a given key. 11 | SetString(key, value string) 12 | 13 | // GetString returns the value for a given key. 14 | GetString(key string) string 15 | } 16 | -------------------------------------------------------------------------------- /dp/kvstore/remote/dkvs.go: -------------------------------------------------------------------------------- 1 | package remote 2 | -------------------------------------------------------------------------------- /dp/kvstore/remote/proxy.go: -------------------------------------------------------------------------------- 1 | package remote 2 | -------------------------------------------------------------------------------- /dp/kvstore/remote/stub.go: -------------------------------------------------------------------------------- 1 | package remote 2 | -------------------------------------------------------------------------------- /dp/raft/Makefile: -------------------------------------------------------------------------------- 1 | 2 | help: 3 | @echo "Makefile targets:" 4 | @echo " install - get required dependencies" 5 | @echo " proto - generate code from proto files" 6 | @echo " run2 - build and start two raft nodes" 7 | @echo " run3 - build and start three raft nodes" 8 | @echo " run4 - build and start four raft nodes" 9 | @echo " run5 - build and start five raft nodes" 10 | 11 | install: 12 | go get -u google.golang.org/grpc 13 | go get -u github.com/golang/protobuf/protoc-gen-go 14 | @echo "Make sure that protoc is installed for your platform" 15 | @echo " macOS: brew install protoc-gen-go protoc-gen-go-grpc" 16 | @echo " Windows: https://github.com/protocolbuffers/protobuf/releases/latest" 17 | 18 | proto: 19 | protoc --go_out=./node --go-grpc_out=./node ./node/node.proto 20 | 21 | run2: 22 | go build 23 | ./raft -id 0 -count 2 & echo $$! 24 | ./raft -id 1 -count 2 & echo $$! 25 | @echo "Use 'killall raft' to terminate instances" 26 | 27 | run3: 28 | go build 29 | ./raft -id 0 -count 3 & echo $$! 30 | ./raft -id 1 -count 3 & echo $$! 31 | ./raft -id 2 -count 3 & echo $$! 32 | @echo "Use 'killall raft' to terminate instances" 33 | 34 | run4: 35 | go build 36 | ./raft -id 0 -count 4 & echo $$! 37 | ./raft -id 1 -count 4 & echo $$! 38 | ./raft -id 2 -count 4 & echo $$! 39 | ./raft -id 3 -count 4 & echo $$! 40 | @echo "Use 'killall raft' to terminate instances" 41 | 42 | run5: 43 | go build 44 | ./raft -id 0 -count 5 & echo $$! 45 | ./raft -id 1 -count 5 & echo $$! 46 | ./raft -id 2 -count 5 & echo $$! 47 | ./raft -id 3 -count 5 & echo $$! 48 | ./raft -id 4 -count 5 & echo $$! 49 | @echo "Use 'killall raft' to terminate instances" 50 | -------------------------------------------------------------------------------- /dp/raft/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "github.com/0xqab/concepts-of-programming-languages/dp/raft/node" 6 | ) 7 | 8 | var ( 9 | id = flag.Int("id", 0, "Node identifier [0...n]") 10 | count = flag.Int("count", 5, "Number of started nodes") 11 | basePort = flag.Int("baseport", 10000, "Port number of node with id 0") 12 | ) 13 | 14 | func main() { 15 | flag.Parse() 16 | n := node.NewNode(*id, *basePort, *count) 17 | n.Start() 18 | } 19 | -------------------------------------------------------------------------------- /dp/raft/node/node.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option go_package = ".;node"; 3 | 4 | package raft; 5 | 6 | service Node { 7 | rpc RequestVote(RequestVoteRequest) returns (RequestVoteResponse); 8 | rpc AppendEntries(AppendEntriesRequest) returns (AppendEntriesResponse); 9 | } 10 | 11 | message RequestVoteRequest { 12 | int64 term = 1; 13 | int64 candidateId = 2; 14 | int64 lastLogIndex = 3; 15 | int64 lastLogTerm = 4; 16 | } 17 | 18 | message RequestVoteResponse { 19 | bool success = 1; 20 | int64 term = 2; 21 | } 22 | 23 | message AppendEntriesRequest { 24 | int64 term = 1; 25 | int64 leaderId = 2; 26 | int64 prevLogIndex = 3; 27 | int64 prevLogTerm = 4; 28 | repeated LogEntry entries = 5; 29 | int64 leaderCommit = 6; 30 | } 31 | 32 | message LogEntry { 33 | int64 term = 1; 34 | int64 index = 2; 35 | bytes data = 3; 36 | } 37 | 38 | message AppendEntriesResponse { 39 | bool success = 1; 40 | int64 term = 2; 41 | } 42 | -------------------------------------------------------------------------------- /fp/clojures/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // intSeq returns another function, which we define anonymously in the body of intSeq. 6 | // The returned function closes over the variable i to form a closure. 7 | func intSeq() func() int { 8 | i := 0 9 | return func() int { 10 | i++ 11 | return i 12 | } 13 | } 14 | func main() { 15 | // We call intSeq, assigning the result (a function) to nextInt. 16 | // This function value captures its own i value, which will be updated each time we call nextInt. 17 | 18 | nextInt := intSeq() 19 | // See the effect of the closure by calling nextInt a few times. 20 | fmt.Println(nextInt()) 21 | fmt.Println(nextInt()) 22 | 23 | // To confirm that the state is unique to that particular function, create and test a new one. 24 | newInts := intSeq() 25 | fmt.Println(newInts()) 26 | } 27 | 28 | // EOF OMIT 29 | -------------------------------------------------------------------------------- /fp/composition/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | ) 8 | 9 | func main() { 10 | 11 | f := func(x int) int { return x * x } 12 | g := func(x int) int { return x + 1 } 13 | 14 | // Functional Composition: (g◦f)(x) 15 | gf := func(x int) int { return g(f(x)) } 16 | 17 | fmt.Printf("%v\n", gf(2)) // --> 5 18 | 19 | // Generic Composition 20 | type any interface{} 21 | type function func(any) any 22 | 23 | compose := func(g, f function) function { 24 | return func(x any) any { 25 | return g(f(x)) 26 | } 27 | } 28 | square := func(x any) any { return x.(int) * x.(int) } 29 | f2 := func(x any) any { return f(x.(int)) } 30 | 31 | fmt.Printf("%v\n", compose(square, f2)(2)) // --> 16 32 | fmt.Printf("%v\n", compose(compose(square, f2), f2)(2)) // --> 256 33 | } 34 | -------------------------------------------------------------------------------- /fp/functions/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | // START OMIT 6 | func aBlock(i int) { 7 | fmt.Printf("Entering block: i=%v\n", i) 8 | } 9 | 10 | func do(f func(int), loops int) { 11 | for i := 0; i < loops; i++ { 12 | f(i) 13 | } 14 | } 15 | 16 | func main() { 17 | do(aBlock, 5) 18 | } 19 | 20 | // EOF OMIT 21 | -------------------------------------------------------------------------------- /fp/successor/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type fnf func(fnf) fnf 6 | 7 | func main() { 8 | I := func(x fnf) fnf { return x } 9 | 10 | // Functional Numbers 1 11 | ONCE := func(f fnf) fnf { 12 | return func(x fnf) fnf { 13 | return f(x) 14 | } 15 | } 16 | 17 | // Functional Numbers 2 18 | TWICE := func(f fnf) fnf { 19 | return func(x fnf) fnf { 20 | return f(f(x)) 21 | } 22 | } 23 | 24 | // Functional Numbers 3 25 | THRICE := func(f fnf) fnf { 26 | return func(x fnf) fnf { 27 | return f(f(f(x))) 28 | } 29 | } 30 | // NUMBER END OMIT 31 | 32 | // Functional Numbers SUCCESSOR(N) = N + 1 33 | SUCCESSOR := func(w fnf) fnf { 34 | return func(y fnf) fnf { 35 | return func(x fnf) fnf { 36 | return y(w)(y)(x) 37 | } 38 | } 39 | } 40 | 41 | Printer := func(x fnf) fnf { fmt.Print("."); return x } 42 | 43 | SUCCESSOR(ONCE)(Printer)(I) 44 | fmt.Println("SUCCESSOR(ONCE) = 2") 45 | 46 | SUCCESSOR(TWICE)(Printer)(I) 47 | fmt.Println("SUCCESSOR(TWICE) = 3") 48 | 49 | SUCCESSOR(THRICE)(Printer)(I) 50 | fmt.Println("SUCCESSOR(THRICE) = 4") 51 | // EOF OMIT 52 | } 53 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/0xqab/concepts-of-programming-languages 2 | 3 | go 1.13 4 | 5 | require ( 6 | github.com/antlr/antlr4 v0.0.0-20201022163248-67e49703c3b3 7 | github.com/coreos/etcd v3.3.18+incompatible 8 | github.com/fogleman/gg v1.3.0 9 | github.com/gogo/protobuf v1.3.1 // indirect 10 | github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect 11 | github.com/golang/protobuf v1.4.3 12 | golang.org/x/image v0.0.0-20200927104501-e162460cd6b5 // indirect 13 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b // indirect 14 | golang.org/x/sys v0.0.0-20201109165425-215b40eba54c 15 | golang.org/x/text v0.3.4 // indirect 16 | google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a // indirect 17 | google.golang.org/grpc v1.33.2 18 | google.golang.org/protobuf v1.25.0 19 | ) 20 | -------------------------------------------------------------------------------- /library/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help dynamic static main run clean 2 | help: 3 | @echo "dynamic - build dynamic lib" 4 | @echo " static - build static lib" 5 | 6 | dynamic: 7 | # compile the source into an object file (position independent code) 8 | gcc -fPIC -c mylib.c 9 | # convert the resulting object file into a shared library 10 | gcc -shared -o libmylib.so mylib.o 11 | # dynamic OMIT 12 | 13 | static: 14 | # compile the source into an object file 15 | gcc -c mylib.c 16 | # convert the resulting object file into a library 17 | ar rc libmylib.a mylib.o 18 | # build an index inside the library 19 | ranlib libmylib.a 20 | # static OMIT 21 | 22 | main: 23 | go build main.go 24 | 25 | run: 26 | go run main.go 27 | 28 | clean: 29 | rm -f libmylib.so 30 | rm -f libmylib.a 31 | rm -f mylib.o 32 | rm -f main 33 | -------------------------------------------------------------------------------- /library/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // #cgo CFLAGS: -I. 4 | // #cgo LDFLAGS: -L. -lmylib 5 | // #include "mylib.h" 6 | // #include 7 | import "C" 8 | import "unsafe" 9 | 10 | func main() { 11 | s := C.CString("Hello Lib!") 12 | defer C.free(unsafe.Pointer(s)) 13 | C.myprint(s) 14 | } 15 | -------------------------------------------------------------------------------- /library/mylib.c: -------------------------------------------------------------------------------- 1 | #include "mylib.h" 2 | void myprint(char *s) { 3 | printf("You said: %s\n", s); 4 | } 5 | -------------------------------------------------------------------------------- /library/mylib.h: -------------------------------------------------------------------------------- 1 | #include 2 | void myprint(char *s); 3 | -------------------------------------------------------------------------------- /logic/age.pl: -------------------------------------------------------------------------------- 1 | get_age(BirthYear) :- 2 | Age is 2020 - BirthYear, 3 | format('Someone born in ~w is age ~w at the end of ~w.~n', [BirthYear, Age, 2020]). 4 | -------------------------------------------------------------------------------- /logic/family.pl: -------------------------------------------------------------------------------- 1 | male(albert). 2 | male(bob). 3 | male(bill). 4 | male(carl). 5 | male(charlie). 6 | male(dan). 7 | male(edward). 8 | 9 | female(alice). 10 | female(betsy). 11 | female(diana). 12 | 13 | parent(albert, bob). 14 | parent(albert, betsy). 15 | parent(albert, bill). 16 | 17 | parent(alice, bob). 18 | parent(alice, betsy). 19 | parent(alice, bill). 20 | 21 | parent(bob, carl). 22 | parent(bob, charlie). 23 | parent(diana, charlie). 24 | -------------------------------------------------------------------------------- /logic/hanoi.pl: -------------------------------------------------------------------------------- 1 | % HANOI 2 | 3 | move(1,X,Y,_) :- write('Move top disk from '), write(X), write(' to '), write(Y), nl. 4 | move(N,X,Y,Z) :- 5 | N > 1, 6 | M is N-1, 7 | move(M,X,Z,Y), 8 | move(1,X,Y,_), 9 | move(M,Z,Y,X). 10 | 11 | run :- move(3,left,right,center). 12 | -------------------------------------------------------------------------------- /logic/juliet.pl: -------------------------------------------------------------------------------- 1 | loves(romeo, juliet). 2 | loves(juliet, romeo) :- loves(romeo, juliet). 3 | loves(william, juliet). 4 | 5 | happy(juliet). 6 | with_romeo(juliet). 7 | dances(juliet) :- happy(juliet), with_romeo(juliet). 8 | 9 | get_loves_juliet :- 10 | loves(X, juliet), 11 | write(X), write(' loves Juliet'), nl. 12 | -------------------------------------------------------------------------------- /logic/palindrome.pl: -------------------------------------------------------------------------------- 1 | % Palindrome predicate for lists 2 | palindrome_list(L) :- reverse(L, L). 3 | 4 | % Palindrome predicate for atoms and strings 5 | palindrome(X) :- 6 | name(X, L), % actually the same as atom_codes, but being traditional here 7 | reverse(L, L). 8 | 9 | % Palindrome predicate for atoms only 10 | palindrome_atom(A) :- 11 | atom(A), % restricts this predicate to atoms (single quoted or no quotes) 12 | atom_codes(A, L), 13 | reverse(L, L). 14 | 15 | % Palindrome predicate for strings only 16 | palindrome_str(S) :- 17 | string(S), % restricts this predicate to strings (double quoted) 18 | string_codes(S, L), 19 | reverse(L, L). 20 | -------------------------------------------------------------------------------- /logic/river.pl: -------------------------------------------------------------------------------- 1 | % FLUSSÜBERQUERUNG - MANN, WOLF, ZIEGE, KOHL 2 | % 3 | % Ein Mann möchte zusammen mit einem Wolf, einer Ziege und einem Kohlkopf 4 | % einen Fluss überqueren, doch das Boot kann außer ihm nur einen weiteren 5 | % Passagier fassen. Er kann weder den Wolf mit der Ziege noch die Ziege 6 | % mit dem Kohl unbeaufsichtigt an einem Ufer lassen. Aufgabe ist es, 7 | % einen Plan zu entwickeln, der diese Bedingungen einhält und mit möglichst 8 | % wenigen Überfahrten auskommt. 9 | % 10 | % Hinweis: es sind nur 7 Züge erforderlich. 11 | 12 | % Definition der gültige Züge 13 | % Es ist möglich von a nach b und zurück zu wechseln. 14 | cross(a,b). 15 | cross(b,a). 16 | % Der Mann fährt immer mit und kann genau einen Passagier oder nichts mitnehmen). 17 | move([X,X,Ziege,Kohl],wolf,[Y,Y,Ziege,Kohl]) :- cross(X,Y). 18 | move([X,Wolf,X,Kohl],ziege,[Y,Wolf,Y,Kohl]) :- cross(X,Y). 19 | move([X,Wolf,Ziege,X],kohl,[Y,Wolf,Ziege,Y]) :- cross(X,Y). 20 | move([X,Wolf,Ziege,Kohl],nichts,[Y,Wolf,Ziege,Kohl]) :- cross(X,Y). 21 | 22 | 23 | % Wenn der Mann bei der Ziege oder bei Wolf und Kohl ist, ist der Zustand sicher. 24 | safe([Farmer,_,Ziege,_]) :- Farmer = Ziege. 25 | safe([Farmer,Wolf,_,Kohl]) :- Farmer = Wolf, Farmer = Kohl. 26 | 27 | % Rekursive Lösungsdefinition (ähnlich vollständiger Induktion): 28 | % Der Endzustand ist eine gültige Lösung, d.h. also wenn alle den Fluss 29 | % überquert haben und bei Seite b sind. 30 | solution([b,b,b,b],[]). 31 | % Überquerungen, die zu einem sicheren Zustand führen und einer bekannten 32 | % Lösung führen, sind ebenfalls gültige Lösungen. 33 | solution(State,[Move|OtherMoves]) :- move(State,Move,NextState), 34 | safe(NextState), 35 | solution(NextState,OtherMoves). 36 | 37 | run :- length(X,7), solution([a,a,a,a],X), write(X). 38 | % solution([a,a,a,a], [ziege,nichts,wolf,ziege,kohl,nichts,ziege]). 39 | -------------------------------------------------------------------------------- /modules/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.15 2 | 3 | WORKDIR /go/src/app 4 | COPY . . 5 | 6 | RUN cd mail && go build 7 | RUN cd plugin && go build -buildmode=plugin plugin.go 8 | RUN cd client && go build client.go 9 | 10 | CMD ["/go/src/app/client/client"] 11 | -------------------------------------------------------------------------------- /modules/client/client.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | mail "github.com/0xqab/concepts-of-programming-languages/modules/mail/v2" 5 | log "github.com/sirupsen/logrus" 6 | "plugin" 7 | "time" 8 | ) 9 | 10 | func main() { 11 | log.Info("opening plugin") 12 | p, err := plugin.Open("../plugin/plugin.so") 13 | if err != nil { 14 | panic(err) 15 | } 16 | 17 | log.Info("looking up symbol") 18 | senderSymbol, err := p.Lookup("MailSender") 19 | if err != nil { 20 | panic(err) 21 | } 22 | sender := senderSymbol.(*mail.SenderImpl) 23 | 24 | log.Info("sending mail") 25 | err = sender.Send(mail.Message{ 26 | From: "bernhard.saumweber@qaware.de", 27 | To: "johannes.weigend@qaware.de", 28 | Subject: "KP", 29 | Message: "Hallo Welt!", 30 | }, 2000*time.Millisecond) 31 | if err != nil { 32 | panic(err) 33 | } 34 | time.Sleep(2100 * time.Millisecond) 35 | } 36 | -------------------------------------------------------------------------------- /modules/client/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/0xqab/concepts-of-programming-languages/modules/client 2 | 3 | go 1.15 4 | 5 | require ( 6 | github.com/0xqab/concepts-of-programming-languages/modules/mail/v2 v2.0.0 7 | github.com/sirupsen/logrus v1.7.0 8 | ) 9 | 10 | replace github.com/0xqab/concepts-of-programming-languages/modules/mail/v2 => ../mail/v2 11 | -------------------------------------------------------------------------------- /modules/client/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 3 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 4 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 5 | github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= 6 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 7 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 8 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 9 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 10 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= 11 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 12 | -------------------------------------------------------------------------------- /modules/mail/api.go: -------------------------------------------------------------------------------- 1 | package mail 2 | 3 | type Message struct { 4 | From string 5 | To string 6 | Subject string 7 | Message string 8 | } 9 | 10 | type Sender interface { 11 | Send(Message) error 12 | } 13 | 14 | func NewSender() *SenderImpl { 15 | return &SenderImpl{} 16 | } 17 | -------------------------------------------------------------------------------- /modules/mail/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/0xqab/concepts-of-programming-languages/modules/mail 2 | 3 | go 1.15 4 | 5 | require github.com/sirupsen/logrus v1.4.2 6 | -------------------------------------------------------------------------------- /modules/mail/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 4 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 5 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 6 | github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= 7 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 8 | github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= 9 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 10 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 11 | github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= 12 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 13 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= 14 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 15 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= 16 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 17 | -------------------------------------------------------------------------------- /modules/mail/impl.go: -------------------------------------------------------------------------------- 1 | package mail 2 | 3 | import log "github.com/sirupsen/logrus" 4 | 5 | type SenderImpl struct{} 6 | 7 | func (s SenderImpl) Send(message Message) error { 8 | log.WithFields(log.Fields{ 9 | "from": message.From, 10 | "to": message.To, 11 | "size": len(message.Message), 12 | }).Info("sending message...") 13 | return nil 14 | } 15 | -------------------------------------------------------------------------------- /modules/mail/v2/api.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type Message struct { 8 | From string 9 | To string 10 | Subject string 11 | Message string 12 | } 13 | 14 | type Sender interface { 15 | Send(Message, time.Duration) error 16 | } 17 | 18 | func NewSender() *SenderImpl { 19 | return &SenderImpl{} 20 | } 21 | -------------------------------------------------------------------------------- /modules/mail/v2/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/0xqab/concepts-of-programming-languages/modules/mail/v2 2 | 3 | go 1.15 4 | 5 | require github.com/sirupsen/logrus v1.7.0 6 | -------------------------------------------------------------------------------- /modules/mail/v2/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 3 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 4 | github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= 5 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 6 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 7 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 8 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= 9 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 10 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= 11 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 12 | -------------------------------------------------------------------------------- /modules/mail/v2/impl.go: -------------------------------------------------------------------------------- 1 | package v2 2 | 3 | import ( 4 | log "github.com/sirupsen/logrus" 5 | "time" 6 | ) 7 | 8 | type SenderImpl struct { 9 | } 10 | 11 | func (s SenderImpl) Send(message Message, timeout time.Duration) error { 12 | taskChan := make(chan bool) 13 | go func() { 14 | log.WithFields(log.Fields{ 15 | "from": message.From, 16 | "to": message.To, 17 | "size": len(message.Message), 18 | "timeout": timeout, 19 | }).Info("sending message with timeout...") 20 | time.Sleep(1000 * time.Millisecond) 21 | taskChan <- true 22 | }() 23 | timerChan := time.After(timeout) 24 | go func() { 25 | select { 26 | case <-taskChan: 27 | log.Info("message sent") 28 | case <-timerChan: 29 | log.Warn("timeout reached") 30 | } 31 | }() 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /modules/plugin/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/0xqab/concepts-of-programming-languages/modules/plugin 2 | 3 | go 1.15 4 | 5 | require github.com/0xqab/concepts-of-programming-languages/modules/mail/v2 v2.0.0 6 | 7 | replace github.com/0xqab/concepts-of-programming-languages/modules/mail/v2 => ../mail/v2 8 | -------------------------------------------------------------------------------- /modules/plugin/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 3 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 4 | github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= 5 | github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= 6 | github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= 7 | github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 8 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 9 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 10 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= 11 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 12 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4= 13 | golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 14 | -------------------------------------------------------------------------------- /modules/plugin/plugin.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | mail "github.com/0xqab/concepts-of-programming-languages/modules/mail/v2" 5 | ) 6 | 7 | var MailSender mail.SenderImpl 8 | 9 | func main() { 10 | MailSender = *mail.NewSender() 11 | } 12 | -------------------------------------------------------------------------------- /oop/boolparser/ast/ast.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package ast contains an abstract syntax tree for boolean expressions. 5 | package ast 6 | 7 | import "fmt" 8 | 9 | // 10 | // ---------- AST ------------ 11 | // 12 | 13 | // Node is the interface to eval an abstract syntax tree (AST) 14 | type Node interface { 15 | 16 | // Eval evaluates the AST. The variables of the expression are set to true or false in the vars map. 17 | // Missing vars (there are no key in the map) are evaluated to false. 18 | Eval(vars map[string]bool) bool 19 | } 20 | 21 | // Or is the logical OR Operator in an AST 22 | type Or struct { 23 | LHS Node 24 | RHS Node 25 | } 26 | 27 | // Eval implements the Node interface 28 | func (o Or) Eval(vars map[string]bool) bool { 29 | return o.LHS.Eval(vars) || o.RHS.Eval(vars) 30 | } 31 | 32 | func (o Or) String() string { 33 | return fmt.Sprintf("|(%v,%v)", o.LHS, o.RHS) 34 | } 35 | 36 | // And is the logical AND Operator in an AST 37 | type And struct { 38 | LHS Node 39 | RHS Node 40 | } 41 | 42 | // Eval implements the Node interface 43 | func (a And) Eval(vars map[string]bool) bool { 44 | return a.LHS.Eval(vars) && a.RHS.Eval(vars) 45 | } 46 | 47 | func (a And) String() string { 48 | return fmt.Sprintf("&(%v,%v)", a.LHS, a.RHS) 49 | } 50 | 51 | // Not is the NOT operator in the AST 52 | type Not struct { 53 | Ex Node 54 | } 55 | 56 | // Eval implements the Node interface 57 | func (n Not) Eval(vars map[string]bool) bool { 58 | return !n.Ex.Eval(vars) 59 | } 60 | 61 | func (n Not) String() string { 62 | return fmt.Sprintf("!(%v)", n.Ex) 63 | } 64 | 65 | // Val is a boolean variable in an AST 66 | type Val struct { 67 | Name string 68 | } 69 | 70 | // Eval implements the Node interface 71 | func (v Val) Eval(vars map[string]bool) bool { 72 | return vars[v.Name] // missing vars will be evaluated to false! 73 | } 74 | 75 | func (v Val) String() string { 76 | return fmt.Sprintf("'%v'", v.Name) 77 | } 78 | -------------------------------------------------------------------------------- /oop/boolparser/ast/ast_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | package ast 4 | 5 | import ( 6 | "testing" 7 | ) 8 | 9 | func TestAST(t *testing.T) { 10 | 11 | // AST for expression: "A AND B OR !C" 12 | ast := Or{And{Val{"A"}, Val{"B"}}, Not{Val{"C"}}} 13 | 14 | // Table to test all combinations for A, B, C -> 2^3 = 8 combinations. 15 | // Format of Table { Value for A, Value for B, Value for C, Expected Result } 16 | truthTable := [][]bool{ 17 | {false, false, false, true}, 18 | {false, false, true, false}, 19 | {false, true, true, false}, 20 | {false, true, false, true}, 21 | {true, false, false, true}, 22 | {true, true, false, true}, 23 | {true, false, true, false}, 24 | {true, true, true, true}, 25 | } 26 | 27 | // Test all possible combinations 28 | for _, tt := range truthTable { 29 | 30 | vars := map[string]bool{"A": tt[0], "B": tt[1], "C": tt[2]} 31 | expected := tt[3] 32 | result := ast.Eval(vars) 33 | 34 | if result != expected { 35 | t.Errorf("Expected %v but got %v. (Expression := %v, Vars := %v)", expected, result, ast, vars) 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /oop/boolparser/lexer/lexer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package lexer contains an interpreter (parser/compiler) for boolean expressions with variables. 5 | package lexer 6 | 7 | // Lexer is a simple tokenizer for generating tokens for the boolean parser. 8 | type Lexer struct { 9 | input string 10 | tokens []string 11 | current int 12 | } 13 | 14 | // NewLexer constructs a lexer from a given string. 15 | func NewLexer(input string) *Lexer { 16 | lexer := new(Lexer) 17 | lexer.input = input 18 | lexer.current = 0 19 | lexer.tokens = splitTokens(input) 20 | return lexer 21 | } 22 | 23 | // NextToken returns the next token. A token is a non empty string. The function returns "" if there is no token available. 24 | func (l *Lexer) NextToken() string { 25 | if l.current == len(l.tokens) { 26 | return "" 27 | } 28 | token := l.tokens[l.current] 29 | l.current++ 30 | return token 31 | } 32 | 33 | func splitTokens(input string) []string { 34 | result := make([]string, 0) 35 | token := "" 36 | for i := 0; i < len(input); i++ { 37 | currentChar := input[i] 38 | if currentChar == byte(' ') { 39 | continue // ignore whitespace 40 | } 41 | // START OMIT 42 | switch currentChar { 43 | // check for terminal 44 | case byte('&'), byte('|'), byte('!'), byte('('), byte(')'): 45 | if token != "" { 46 | result = append(result, token) 47 | token = "" 48 | } 49 | result = append(result, string(currentChar)) 50 | break 51 | // var assumed 52 | default: 53 | token += string(currentChar) // concat var chars 54 | } 55 | // END OMIT 56 | } 57 | 58 | // append last token if exists 59 | if token != "" { 60 | result = append(result, token) 61 | } 62 | return result 63 | } 64 | -------------------------------------------------------------------------------- /oop/boolparser/lexer/lexer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | package lexer 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | ) 10 | 11 | func TestNewLexer(t *testing.T) { 12 | 13 | lexer := NewLexer("a & b") 14 | if len(lexer.tokens) != 3 { 15 | t.Error(fmt.Sprintf("Wrong token count! Expected: 3, Got: %v", len(lexer.tokens))) 16 | } 17 | 18 | lexer = NewLexer("a|b") 19 | if len(lexer.tokens) != 3 { 20 | t.Error(fmt.Sprintf("Wrong token count! Expected: 3, Got: %v", len(lexer.tokens))) 21 | } 22 | 23 | lexer = NewLexer("a|b&(b|c)") 24 | if len(lexer.tokens) != 9 { 25 | t.Error(fmt.Sprintf("Wrong token count! Expected: 9, Got: %v", len(lexer.tokens))) 26 | } 27 | 28 | tok := lexer.NextToken() 29 | for tok != "" { 30 | fmt.Print(tok) 31 | tok = lexer.NextToken() 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /oop/boolparser/parser/parser_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | package parser 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | 10 | "github.com/0xqab/concepts-of-programming-languages/oop/boolparser/lexer" 11 | ) 12 | 13 | func TestParser_Eval(t *testing.T) { 14 | // create parser 15 | p := NewParser(lexer.NewLexer("a&b&!c")) 16 | 17 | // set vars 18 | vars := map[string]bool{ 19 | "a": true, 20 | "b": true, 21 | "c": false, 22 | } 23 | if p.Eval(vars) != true { 24 | t.Error(fmt.Sprintf("Wrong result detected")) 25 | } 26 | 27 | // set vars 28 | vars = map[string]bool{ 29 | "a": true, 30 | "b": true, 31 | "c": true, 32 | } 33 | if p.Eval(vars) != false { 34 | t.Error(fmt.Sprintf("Wrong result detected")) 35 | } 36 | 37 | // set vars 38 | vars = map[string]bool{ 39 | "a": false, 40 | "b": false, 41 | "c": false, 42 | } 43 | if p.Eval(vars) != false { 44 | t.Error(fmt.Sprintf("Wrong result detected")) 45 | } 46 | 47 | p = NewParser(lexer.NewLexer("a & (b | c & b) & d")) 48 | 49 | // set vars 50 | vars = map[string]bool{ 51 | "a": true, 52 | "b": true, 53 | "c": false, 54 | "d": true, 55 | } 56 | if p.Eval(vars) != true { 57 | t.Error(fmt.Sprintf("Wrong result detected")) 58 | } 59 | 60 | // test string support 61 | if p.String() != "&(&('a',|('b',&('c','b'))),'d')" { 62 | t.Error(fmt.Sprintf("Wrong string representation: %v", p.String())) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /oop/delegation/delegation.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type A struct { 6 | } 7 | 8 | func (a A) Foo() { 9 | a.Bar() 10 | } 11 | 12 | func (a A) Bar() { 13 | fmt.Print("a.bar") 14 | } 15 | 16 | type B struct { 17 | A 18 | } 19 | 20 | func (b B) Bar() { 21 | fmt.Print("b.bar") 22 | } 23 | 24 | func main() { 25 | b := B{} 26 | b.Foo() // "a.bar" or "b.bar"? 27 | } 28 | 29 | // EOF OMIT 30 | -------------------------------------------------------------------------------- /oop/embedding/embedding.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | type Introducer interface{ Introduce() } 8 | type Worker interface{ Work() } 9 | 10 | type Person struct { 11 | Name string 12 | } 13 | 14 | // Person now implicitly satisfies Introducer 15 | func (p Person) Introduce() { 16 | fmt.Printf("Hello, my name is %s\n", p.Name) 17 | } 18 | 19 | type Employee struct { 20 | Person 21 | Worker 22 | EmployeeID int 23 | } 24 | 25 | // EOE OMIT 26 | 27 | // Employee will satisfy Worker even without this declaration 28 | func (e Employee) Work() { 29 | fmt.Printf("<%s is working>\n", e.Name) 30 | } 31 | 32 | func main() { 33 | e := Employee{ 34 | Person: Person{"John"}, 35 | EmployeeID: 1, 36 | } 37 | e.Introduce() // prints "Hello, my name is John" 38 | e.Work() // does not require an implementation (but throws exception if not implemented) 39 | } 40 | 41 | // EOF OMIT 42 | -------------------------------------------------------------------------------- /oop/geometry/geoobject/geoobject.go: -------------------------------------------------------------------------------- 1 | package geoobject 2 | 3 | import "image/color" 4 | 5 | // Position is the position of the screen. 6 | type Position struct { 7 | x, y float64 8 | } 9 | 10 | // GeoObject is the "BaseClass" of any geometrical object. All objects have a position and a color. 11 | type GeoObject struct { 12 | pos Position 13 | color color.Color 14 | } 15 | 16 | // Circle is a concrete GeoObject with a radius. 17 | type Circle struct { 18 | GeoObject 19 | radius float64 20 | } 21 | 22 | // Rectangle is a concrete GeoObject with a width and a height. 23 | type Rectangle struct { 24 | GeoObject 25 | width, height float64 26 | } 27 | 28 | // Triangle is a concrete GeoObject with three points (ABC). 29 | // The coordinates of the three points are relative to the position of the object. 30 | type Triangle struct { 31 | GeoObject 32 | b, c Position 33 | } 34 | -------------------------------------------------------------------------------- /oop/geometry/geoobject/ggpainter.go: -------------------------------------------------------------------------------- 1 | package geoobject 2 | 3 | import ( 4 | "github.com/fogleman/gg" 5 | "image/color" 6 | ) 7 | 8 | type GGPainter interface { 9 | GGPaint(ctx *gg.Context) 10 | } 11 | 12 | func (c Circle) GGPaint(ctx *gg.Context) { 13 | ctx.SetColor(c.color) 14 | ctx.DrawCircle(c.pos.x, c.pos.y, c.radius) 15 | ctx.Stroke() 16 | } 17 | 18 | func (r Rectangle) GGPaint(ctx *gg.Context) { 19 | ctx.SetColor(r.color) 20 | ctx.DrawRectangle(r.pos.x, r.pos.y, r.width, r.height) 21 | ctx.Stroke() 22 | } 23 | 24 | func (t Triangle) GGPaint(ctx *gg.Context) { 25 | ctx.SetColor(t.color) 26 | ctx.DrawLine(t.pos.x, t.pos.y, t.b.x, t.b.y) 27 | ctx.DrawLine(t.b.x, t.b.y, t.c.x, t.c.y) 28 | ctx.DrawLine(t.c.x, t.c.y, t.pos.x, t.pos.y) 29 | ctx.Stroke() 30 | } 31 | 32 | func GGPaint() { 33 | context := gg.NewContext(100, 100) 34 | context.SetLineWidth(3) 35 | 36 | objects := []GGPainter{ 37 | Circle{ 38 | GeoObject: GeoObject{ 39 | pos: Position{x: 50, y: 50}, 40 | color: color.RGBA{R: 255, A: 255}}, 41 | radius: 40}, 42 | Rectangle{ 43 | GeoObject: GeoObject{ 44 | pos: Position{x: 60, y: 40}, 45 | color: color.RGBA{G: 255, A: 255}}, 46 | width: 20, 47 | height: 20}, 48 | Triangle{ 49 | GeoObject: GeoObject{ 50 | pos: Position{x: 10, y: 5}, 51 | color: color.RGBA{B: 255, A: 255}}, 52 | b: Position{x: 50, y: 5}, 53 | c: Position{x: 50, y: 35}}, 54 | } 55 | 56 | for _, v := range objects { 57 | v.GGPaint(context) 58 | } 59 | 60 | err := context.SavePNG("out.png") 61 | if err != nil { 62 | panic(err) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /oop/geometry/geoobject/stringpainter.go: -------------------------------------------------------------------------------- 1 | package geoobject 2 | 3 | import ( 4 | "fmt" 5 | "image/color" 6 | ) 7 | 8 | // Painter is used to paint GeoObjects. 9 | type Painter interface { 10 | Paint() 11 | } 12 | 13 | // Paint is implemented by Circle 14 | func (c Circle) Paint() { 15 | fmt.Printf("Painting circle with radius=%v at position=%v and color=%v\n", c.radius, c.pos, c.color) 16 | } 17 | 18 | // Paint is implemented by Rectangle 19 | func (r Rectangle) Paint() { 20 | fmt.Printf("Painting rectangle with width=%v, height=%v at position=%v and color=%v\n", r.width, r.height, r.pos, r.color) 21 | } 22 | 23 | // Paint is implemented by Triangle 24 | func (t Triangle) Paint() { 25 | fmt.Printf("Painting triangle with pos=%v, b=%v, c=%v and color=%v\n", t.pos, t.b, t.c, t.color) 26 | } 27 | 28 | func Paint() { 29 | // Polymorph slice of Painter objects 30 | objects := []Painter{ 31 | // short initialization 32 | Circle{GeoObject{Position{1, 2}, color.Black}, 40}, 33 | Rectangle{GeoObject{Position{1, 2}, color.Black}, 10, 10}, 34 | Triangle{GeoObject{Position{10, 20}, color.Black}, Position{11, 21}, Position{12, 22}}, 35 | 36 | // or with named identifiers 37 | Circle{ 38 | GeoObject: GeoObject{ 39 | pos: Position{x: 1, y: 2}, 40 | color: color.Black}, 41 | radius: 40}, 42 | Rectangle{ 43 | GeoObject: GeoObject{ 44 | pos: Position{x: 1, y: 2}, 45 | color: color.Black}, 46 | width: 10, 47 | height: 10}, 48 | Triangle{ 49 | GeoObject: GeoObject{ 50 | pos: Position{x: 10, y: 20}, 51 | color: color.Black}, 52 | b: Position{x: 11, y: 21}, 53 | c: Position{x: 12, y: 22}}, 54 | } 55 | for _, v := range objects { 56 | v.Paint() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /oop/geometry/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/0xqab/concepts-of-programming-languages/oop/geometry/geoobject" 4 | 5 | func main() { 6 | geoobject.Paint() 7 | geoobject.GGPaint() 8 | } 9 | -------------------------------------------------------------------------------- /oop/mail/client/client.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package client contains sample code for the mail components. 5 | package client 6 | 7 | import ( 8 | "github.com/0xqab/concepts-of-programming-languages/oop/mail" 9 | "github.com/0xqab/concepts-of-programming-languages/oop/mail/util" 10 | ) 11 | 12 | // Registry is the central configuration for the service locator 13 | var Registry = util.NewRegistry() 14 | 15 | // SendMail sends a mail to a receiver. 16 | func SendMail(to, subject, text string) error { 17 | 18 | // Create an implementation for the mail.Sender interface. 19 | var sender = Registry.Get("mail.Sender").(mail.Sender) 20 | 21 | email := mail.Message{To: to, Subject: subject, Text: text} 22 | return sender.Send(email) 23 | } 24 | 25 | // EOF OMIT 26 | -------------------------------------------------------------------------------- /oop/mail/client/client_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | package client 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/0xqab/concepts-of-programming-languages/oop/mail/smtp" 9 | ) 10 | 11 | // configure Registry to know which mail implementation is used. 12 | func init() { 13 | Registry.Register("mail.Sender", new(smtp.MailSenderImpl)) 14 | } 15 | 16 | func TestMail(t *testing.T) { 17 | err := SendMail("johannes.weigend@qaware.de", "Hello", "Hello from Go!") 18 | if err != nil { 19 | t.Error("err should have been nil") 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /oop/mail/mail.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package mail contains the Mail API interfaces and datatypes for sending Emails. 5 | package mail 6 | 7 | type Message struct { 8 | To string 9 | Subject string 10 | Text string 11 | } 12 | 13 | // Sender is a interface to send mails. 14 | type Sender interface { 15 | 16 | // Send a mail to a given address with a subject and text. 17 | Send(message Message) error 18 | } 19 | 20 | // END OMIT 21 | -------------------------------------------------------------------------------- /oop/mail/smtp/sender.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package smtp sends mails over the smtp protocol. 5 | package smtp 6 | 7 | import ( 8 | "github.com/0xqab/concepts-of-programming-languages/oop/mail" 9 | "log" 10 | ) 11 | 12 | // MailSenderImpl is a sender object. 13 | type MailSenderImpl struct { 14 | } 15 | 16 | // SendMail sends a mail to a receiver. 17 | func (m *MailSenderImpl) Send(message mail.Message) error { 18 | log.Printf("Sending message with SMTP:\n To: %v\n Subject: %v\n Text: %v\n", 19 | message.To, message.Subject, message.Text) 20 | return nil 21 | } 22 | 23 | //END OMIT 24 | -------------------------------------------------------------------------------- /oop/mail/util/registry.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package util contains a simple Service Locator. 5 | package util 6 | 7 | // Registry is a simple Service Locator for interfaces. 8 | type Registry struct { 9 | services map[string]interface{} 10 | } 11 | 12 | // NewRegistry constructor 13 | func NewRegistry() *Registry { 14 | registry := new(Registry) 15 | registry.services = make(map[string]interface{}) 16 | return registry 17 | } 18 | 19 | // Register registers a single interface for a unique name 20 | func (s *Registry) Register(name string, some interface{}) { 21 | s.services[name] = some 22 | } 23 | 24 | // Get returns the registered interface for a given name 25 | func (s *Registry) Get(name string) interface{} { 26 | result := s.services[name] 27 | return result 28 | } 29 | -------------------------------------------------------------------------------- /oop/multi/multi.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | type Fooer interface { 6 | Foo() 7 | } 8 | 9 | type Barer interface { 10 | Bar() 11 | } 12 | 13 | type X struct{} 14 | 15 | func (x X) Foo() {} 16 | func (x X) Bar() {} 17 | 18 | // END1 OMIT 19 | 20 | type Foo struct { 21 | Name string 22 | } 23 | 24 | type Bar struct { 25 | Name string 26 | } 27 | 28 | type Y struct { 29 | Foo 30 | Bar 31 | } 32 | 33 | func main() { 34 | y := Y{ 35 | Foo: Foo{Name: "Foo!"}, 36 | Bar: Bar{Name: "Bar!"}, 37 | } 38 | fmt.Print(y.Foo.Name) 39 | fmt.Print(y.Bar.Name) 40 | //fmt.Print(y.Name) // Ambiguous Reference 41 | } 42 | 43 | // EOF OMIT 44 | -------------------------------------------------------------------------------- /oop/polymorphism/polymorphism.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | // Point is a two dimensional point in a cartesian coordinate system. 8 | type Point struct{ x, y int } 9 | 10 | // Point implements the fmt.Stringer interface. 11 | func (p Point) String() string { 12 | return fmt.Sprintf("x=%v,y=%v", p.x, p.y) 13 | } 14 | 15 | // ColorPoint extends Point by adding a color field. 16 | type ColorPoint struct { 17 | Point // Embedding simulates inheritance but it is (sort-of) delegation! 18 | c int 19 | } 20 | 21 | // ColorPoint implements the fmt.Stringer interface. 22 | func (p ColorPoint) String() string { 23 | return fmt.Sprintf("x=%v,y=%v,c=%v", p.x, p.y, p.c) 24 | // OR: return fmt.Sprintf("%v,c=%v", p.Point, p.c) // Delegate to Point.String() 25 | } 26 | 27 | // END1 OMIT 28 | 29 | func main() { 30 | var p = Point{1, 2} 31 | var cp = ColorPoint{Point{1, 2}, 3} 32 | 33 | fmt.Println(p) 34 | fmt.Println(cp) 35 | fmt.Println(cp.x) // access inherited field 36 | 37 | // p = cp // does not work: No type hierarchy, no polymorphism 38 | p = cp.Point // works 39 | 40 | // s is a interface and supports Polymorphism 41 | var s fmt.Stringer 42 | s = p 43 | fmt.Println(s.String()) 44 | s = cp 45 | fmt.Println(s.String()) 46 | } 47 | 48 | // END2 OMIT 49 | -------------------------------------------------------------------------------- /oop/rational/rational.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | // Package rational implements rational numbers. 5 | package rational 6 | 7 | import "fmt" 8 | 9 | // Rational represents a rational number numerator/denominator. 10 | type Rational struct { 11 | numerator int 12 | denominator int 13 | } 14 | 15 | // END1 OMIT 16 | 17 | // NewRational constructor function 18 | func NewRational(numerator int, denominator int) Rational { 19 | if denominator == 0 { 20 | panic("division by zero") 21 | } 22 | r := Rational{} 23 | divisor := gcd(numerator, denominator) 24 | r.numerator = numerator / divisor 25 | r.denominator = denominator / divisor 26 | return r 27 | } 28 | 29 | // END2 OMIT 30 | 31 | // Multiply method for rational numbers (x1/x2 * y1/y2) 32 | func (x Rational) Multiply(y Rational) Rational { 33 | return NewRational(x.numerator*y.numerator, x.denominator*y.denominator) 34 | } 35 | 36 | // Multiply OMIT 37 | 38 | // Add adds two rational numbers 39 | func (x Rational) Add(y Rational) Rational { 40 | return NewRational(x.numerator*y.denominator+y.numerator*x.denominator, x.denominator*y.denominator) 41 | } 42 | 43 | // Stringer 44 | func (x Rational) String() string { 45 | return fmt.Sprintf("(%v/%v)", x.numerator, x.denominator) 46 | } 47 | 48 | // Stringer OMIT 49 | 50 | // Helper GCD -> Euclidean algorithm 51 | func gcd(x, y int) int { 52 | for y != 0 { 53 | x, y = y, x%y 54 | } 55 | return x 56 | } 57 | -------------------------------------------------------------------------------- /oop/rational/rational_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | 4 | package rational 5 | 6 | import ( 7 | "fmt" 8 | "testing" 9 | ) 10 | 11 | func TestRational(t *testing.T) { 12 | 13 | r1 := NewRational(1, 2) 14 | r2 := NewRational(2, 4) 15 | 16 | // test equal 17 | if r1 != r2 { 18 | t.Error("1/2 should be equal to 2/4 but is not.") 19 | } 20 | 21 | // test multiply 22 | r3 := r1.Multiply(r2) 23 | if r3 != NewRational(1, 4) { 24 | t.Error(fmt.Sprintf("1/2 * 1/2 should be 1/4 but ist %v", r3)) 25 | } 26 | 27 | // test add 28 | r4 := r3.Add(r3) 29 | if r4 != NewRational(1, 2) { 30 | t.Error(fmt.Sprintf("1/4 + 1/4 should be 1/2 but ist %v", r4)) 31 | } 32 | 33 | s:= fmt.Sprintf("x%vx", r4) 34 | if s != "x(1/2)x" { 35 | t.Error(fmt.Sprintf("Expected x(1/2)x but got: %s", s)) 36 | } 37 | 38 | } 39 | 40 | // END OMIT 41 | -------------------------------------------------------------------------------- /oop/rational2/rational.go: -------------------------------------------------------------------------------- 1 | package rational2 2 | 3 | import "fmt" 4 | 5 | type Rational struct { 6 | n int // numerator (Zähler) 7 | d int // denominator (Nenner) 8 | } 9 | 10 | var Zero = Rational{n: 0, d: 1} 11 | var One = Rational{n: 1, d: 1} 12 | 13 | func New(numerator int, denominator int) Rational { 14 | if denominator == 0 { 15 | panic("denominator must not be zero") 16 | } 17 | // reduce fraction 18 | gcd := gcd(numerator, denominator) 19 | return Rational{n: numerator / gcd, d: denominator / gcd} 20 | } 21 | 22 | func (r Rational) Add(b Rational) Rational { 23 | return New(r.n*b.d+r.d*b.n, r.d*b.d) 24 | } 25 | 26 | func (r Rational) Multiply(b Rational) Rational { 27 | return New(r.n*b.n, r.d*b.d) 28 | } 29 | 30 | func (r Rational) String() string { 31 | return fmt.Sprintf("(%d/%d)", r.n, r.d) 32 | } 33 | 34 | func (r Rational) Float32() float32 { 35 | return float32(r.n) / float32(r.d) 36 | } 37 | 38 | func (r Rational) Float64() float64 { 39 | return float64(r.n) / float64(r.d) 40 | } 41 | 42 | func gcd(a, b int) int { 43 | for b != 0 { 44 | a, b = b, a%b 45 | } 46 | return a 47 | } 48 | -------------------------------------------------------------------------------- /oop/rational2/rational_test.go: -------------------------------------------------------------------------------- 1 | package rational2 2 | 3 | import "testing" 4 | 5 | func TestString(t *testing.T) { 6 | var s string 7 | 8 | s = New(2, 3).String() 9 | if s != "(2/3)" { 10 | t.Errorf("expected 2/3, got %s", s) 11 | } 12 | 13 | s = New(2, -3).String() 14 | if s != "(-2/3)" { 15 | t.Errorf("expected -2/3, got %s", s) 16 | } 17 | 18 | s = New(12, 4).String() 19 | if s != "(3/1)" { 20 | t.Errorf("expected 3/1, got %s", s) 21 | } 22 | 23 | s = New(0, 4).String() 24 | if s != "(0/1)" { 25 | t.Errorf("expected 0/1, got %s", s) 26 | } 27 | } 28 | 29 | func TestGcd(t *testing.T) { 30 | var g int 31 | 32 | g = gcd(2, 3) 33 | if g != 1 { 34 | t.Errorf("gcd(2,3) should be 1, but was %d", g) 35 | } 36 | 37 | g = gcd(9, 3) 38 | if g != 3 { 39 | t.Errorf("gcd(9,3) should be 3, but was %d", g) 40 | } 41 | 42 | g = gcd(-2, 4) 43 | if g != -2 { 44 | t.Errorf("gcd(-2,4) should be -2, but was %d", g) 45 | } 46 | } 47 | 48 | func TestAdd(t *testing.T) { 49 | a := New(2, 3) 50 | b := New(1, 2) 51 | c := New(1, 3) 52 | 53 | s1 := a.Add(b) 54 | if s1 != New(7, 6) { 55 | t.Errorf("2/3 + 1/2 should be 7/6, but was %v", s1) 56 | } 57 | 58 | s2 := b.Add(c) 59 | if s2 != New(5, 6) { 60 | t.Errorf("1/2 + 1/3 should be 5/6, but was %v", s2) 61 | } 62 | 63 | s3 := a.Add(c) 64 | if s3 != New(1, 1) { 65 | t.Errorf("2/3 + 1/3 should be 1/1, but was %v", s3) 66 | } 67 | 68 | s4 := a.Add(Zero) 69 | if s4 != a { 70 | t.Errorf("2/3 + 0 should be 2/3, but was %v", s4) 71 | } 72 | } 73 | 74 | func TestMultiply(t *testing.T) { 75 | a := New(2, 3) 76 | b := New(1, 2) 77 | c := New(1, 3) 78 | 79 | s1 := a.Multiply(b) 80 | if s1 != New(2, 6) { 81 | t.Errorf("2/3 * 1/2 should be 2/6, but was %v", s1) 82 | } 83 | 84 | s2 := b.Multiply(c) 85 | if s2 != New(1, 6) { 86 | t.Errorf("1/2 * 1/3 should be 1/6, but was %v", s2) 87 | } 88 | 89 | s3 := a.Multiply(c) 90 | if s3 != New(2, 9) { 91 | t.Errorf("2/3 * 1/3 should be 2/9, but was %v", s3) 92 | } 93 | 94 | s4 := a.Multiply(One) 95 | if s4 != a { 96 | t.Errorf("2/3 * 1 should be 2/3, but was %v", s4) 97 | } 98 | 99 | s5 := a.Multiply(Zero) 100 | if s5 != Zero { 101 | t.Errorf("2/3 * 0 should be 0/1, but was %v", s5) 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /oop/stack/stack.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | //Package stack contains LIFO functions. 16 | package stack 17 | 18 | // Stack is a generic LIFO container for untyped object. 19 | type Stack struct { 20 | data []interface{} 21 | } 22 | 23 | // NewStack constructs an empty stack. 24 | func NewStack() *Stack { 25 | return new(Stack) 26 | } 27 | 28 | // Push pushes a value on the stack. 29 | func (s *Stack) Push(value interface{}) { 30 | s.data = append(s.data, value) 31 | } 32 | 33 | // Pop pops a value from the stack. It returns an error if the stack is empty. 34 | func (s *Stack) Pop() interface{} { 35 | if len(s.data) == 0 { 36 | panic("can not pop: empty stack") 37 | } 38 | var result = s.data[len(s.data)-1] 39 | s.data = s.data[0 : len(s.data)-1] 40 | return result 41 | } 42 | 43 | // Size returns the count of elements in the Stack 44 | func (s *Stack) Size() int { 45 | return len(s.data) 46 | } 47 | 48 | // Get returns the n-th element in the Stack 49 | func (s *Stack) Get(idx int) interface{} { 50 | return s.data[idx] 51 | } 52 | 53 | // END OMIT 54 | -------------------------------------------------------------------------------- /oop/stack/stack_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 2 | // Licensed under the Apache License, Version 2.0 3 | package stack 4 | 5 | import ( 6 | "fmt" 7 | "testing" 8 | 9 | "github.com/0xqab/concepts-of-programming-languages/oop/rational" 10 | ) 11 | 12 | func TestStack(t *testing.T) { 13 | 14 | s := NewStack() 15 | 16 | s.Push("1") 17 | s.Push("2") 18 | s.Push("3") 19 | 20 | if s.Pop() != "3" { 21 | t.Error("Pop() did not return 3") 22 | } 23 | 24 | if s.Pop() != "2" { 25 | t.Error("Pop() did not return 2") 26 | } 27 | 28 | if s.Pop() != "1" { 29 | t.Error("Pop() did not return 1") 30 | } 31 | 32 | defer func() { 33 | if r := recover(); r != nil { 34 | fmt.Println("recovered:", r) 35 | } 36 | }() 37 | 38 | if s.Pop() != nil { 39 | t.Error("Stack should be empty, but is not.") 40 | } 41 | 42 | r1 := rational.NewRational(1, 2) 43 | r2 := rational.NewRational(2, 4) 44 | 45 | s.Push(r1) 46 | s.Push(r2) 47 | 48 | if s.Pop() != r2 { 49 | t.Error("Pop() did not return r2") 50 | } 51 | 52 | } 53 | 54 | func TestCasting(t *testing.T) { 55 | 56 | s := NewStack() 57 | s.Push(1) 58 | s.Push(2) 59 | 60 | sum := 0 61 | for i := 0; i < s.Size(); i++ { 62 | sum += s.Get(i).(int) // type assertion = cast from interface{} to int 63 | } 64 | 65 | if sum != 3 { 66 | t.Error(fmt.Sprintf("Sum result should be 3 but is %v", sum)) 67 | } 68 | } 69 | 70 | // END OMIT 71 | -------------------------------------------------------------------------------- /plugin/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: help plugin master run 2 | 3 | help: 4 | @echo "plugin - build the plugin" 5 | @echo " run - build plugin and run master" 6 | 7 | plugin: 8 | go build -buildmode=plugin plugin.go 9 | 10 | run: plugin 11 | go run master.go plugin.so 12 | -------------------------------------------------------------------------------- /plugin/master.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "plugin" 6 | ) 7 | 8 | func main() { 9 | p, err := plugin.Open(os.Args[1]) 10 | if err != nil { 11 | panic(err) 12 | } 13 | v, err := p.Lookup("V") 14 | if err != nil { 15 | panic(err) 16 | } 17 | f, err := p.Lookup("F") 18 | if err != nil { 19 | panic(err) 20 | } 21 | *v.(*int) = 7 22 | f.(func())() // prints "Hello, number 7" 23 | } 24 | -------------------------------------------------------------------------------- /plugin/plugin.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | 5 | var V int 6 | 7 | func F() { 8 | fmt.Printf("Hello, number %d\n", V) 9 | } 10 | 11 | func main() { 12 | fmt.Println("plugin loaded") 13 | } 14 | -------------------------------------------------------------------------------- /servers/fileserver/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "flag" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | ) 9 | 10 | func main() { 11 | port := flag.String("p", "8080", "port to serve on") 12 | directory := flag.String("d", ".", "the directory of static file to host") 13 | flag.Parse() 14 | 15 | fileServer := http.FileServer(http.Dir(*directory)) 16 | http.Handle("/", fileServer) 17 | fmt.Printf("Starting server at port " + *port + "\n") 18 | log.Fatal(http.ListenAndServe(":"+*port, nil)) 19 | } 20 | -------------------------------------------------------------------------------- /servers/server/server.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | "net/http" 7 | ) 8 | 9 | func main() { 10 | http.HandleFunc("/hello", func(w http.ResponseWriter, r *http.Request) { 11 | if n, err := fmt.Fprintf(w, "Hello!\n"); err != nil { 12 | log.Fatalf("Error after writing %d bytes: %v", n, err.Error()) 13 | } 14 | }) 15 | 16 | fmt.Printf("Starting server at port 8080\n") 17 | log.Fatal(http.ListenAndServe(":8080", nil)) 18 | } 19 | -------------------------------------------------------------------------------- /sp/container/container.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Simple "Docker"/Container implementation by Liz Rice. 4 | 5 | package main 6 | 7 | import ( 8 | "io/ioutil" 9 | "log" 10 | "os" 11 | "os/exec" 12 | "path/filepath" 13 | "strconv" 14 | "syscall" 15 | ) 16 | 17 | // go run main.go run 18 | func main() { 19 | switch os.Args[1] { 20 | case "run": 21 | run() 22 | case "child": 23 | child() 24 | default: 25 | panic("help") 26 | } 27 | } 28 | 29 | func run() { 30 | log.Printf("Running %v \n", os.Args[1:]) 31 | 32 | cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...) 33 | cmd.Stdin = os.Stdin 34 | cmd.Stdout = os.Stdout 35 | cmd.Stderr = os.Stderr 36 | cmd.SysProcAttr = &syscall.SysProcAttr{ 37 | // Does not compile on OSX 38 | Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS, 39 | Unshareflags: syscall.CLONE_NEWNS, 40 | } 41 | 42 | must(cmd.Run()) 43 | } 44 | 45 | func child() { 46 | log.Printf("Running %v \n", os.Args[1:]) 47 | 48 | //cg() 49 | 50 | cmd := exec.Command(os.Args[2], os.Args[3:]...) 51 | cmd.Stdin = os.Stdin 52 | cmd.Stdout = os.Stdout 53 | cmd.Stderr = os.Stderr 54 | 55 | // Does not compile on OSX or Windows 56 | must(syscall.Sethostname([]byte("container"))) 57 | must(syscall.Chroot("/opt/alpinefs")) // local fs 58 | must(os.Chdir("/")) 59 | must(syscall.Mount("proc", "proc", "proc", 0, "")) 60 | 61 | must(cmd.Run()) 62 | 63 | must(syscall.Unmount("proc", 0)) 64 | } 65 | 66 | func cg() { 67 | cgroups := "/sys/fs/cgroup/" 68 | pids := filepath.Join(cgroups, "pids") 69 | os.Mkdir(filepath.Join(pids, "container"), 0755) 70 | must(ioutil.WriteFile(filepath.Join(pids, "container/pids.max"), []byte("20"), 0700)) 71 | // Removes the new cgroup in place after the container exits 72 | must(ioutil.WriteFile(filepath.Join(pids, "container/notify_on_release"), []byte("1"), 0700)) 73 | must(ioutil.WriteFile(filepath.Join(pids, "container/cgroup.procs"), []byte(strconv.Itoa(os.Getpid())), 0700)) 74 | } 75 | 76 | func must(err error) { 77 | if err != nil { 78 | panic(err) 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /sp/container/container_simple1.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Simple "Docker"/Container implementation by Liz Rice. 4 | 5 | package main 6 | 7 | import ( 8 | "log" 9 | "os" 10 | "os/exec" 11 | ) 12 | 13 | // go run main.go run 14 | func main() { 15 | switch os.Args[1] { 16 | case "run": 17 | run() 18 | default: 19 | panic("help") 20 | } 21 | } 22 | 23 | func run() { 24 | log.Printf("Running %v \n", os.Args[1:]) 25 | 26 | cmd := exec.Command(os.Args[2], os.Args[3:]...) 27 | cmd.Stdin = os.Stdin 28 | cmd.Stdout = os.Stdout 29 | cmd.Stderr = os.Stderr 30 | //cmd.SysProcAttr = &syscall.SysProcAttr{ 31 | // Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS, 32 | // Unshareflags: syscall.CLONE_NEWNS, 33 | //} 34 | 35 | must(cmd.Run()) 36 | } 37 | 38 | func must(err error) { 39 | if err != nil { 40 | panic(err) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /sp/container/container_simple2.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Simple "Docker"/Container implementation by Liz Rice. 4 | 5 | package main 6 | 7 | import ( 8 | "log" 9 | "os" 10 | "os/exec" 11 | "syscall" 12 | ) 13 | 14 | // go run main.go run 15 | func main() { 16 | switch os.Args[1] { 17 | case "run": 18 | run() 19 | default: 20 | panic("help") 21 | } 22 | } 23 | 24 | func run() { 25 | log.Printf("Running %v \n", os.Args[1:]) 26 | 27 | cmd := exec.Command(os.Args[2], os.Args[3:]...) 28 | cmd.Stdin = os.Stdin 29 | cmd.Stdout = os.Stdout 30 | cmd.Stderr = os.Stderr 31 | cmd.SysProcAttr = &syscall.SysProcAttr{ 32 | Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS, 33 | Unshareflags: syscall.CLONE_NEWNS, 34 | } 35 | 36 | must(cmd.Run()) 37 | } 38 | 39 | func must(err error) { 40 | if err != nil { 41 | panic(err) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /sp/container/container_simple3.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Simple "Docker"/Container implementation by Liz Rice. 4 | 5 | package main 6 | 7 | import ( 8 | "log" 9 | "os" 10 | "os/exec" 11 | "syscall" 12 | ) 13 | 14 | // go run main.go run 15 | func main() { 16 | switch os.Args[1] { 17 | case "run": 18 | run() 19 | case "child": 20 | child() 21 | default: 22 | panic("help") 23 | } 24 | } 25 | 26 | func run() { 27 | log.Printf("Running %v as PID %d \n", os.Args[1:], os.Getpid()) 28 | 29 | cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...) 30 | cmd.Stdin = os.Stdin 31 | cmd.Stdout = os.Stdout 32 | cmd.Stderr = os.Stderr 33 | cmd.SysProcAttr = &syscall.SysProcAttr{ 34 | Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS, 35 | Unshareflags: syscall.CLONE_NEWNS, 36 | } 37 | 38 | must(cmd.Run()) 39 | } 40 | 41 | func child() { 42 | log.Printf("Running %v as PID %d \n", os.Args[1:], os.Getpid()) 43 | 44 | cmd := exec.Command(os.Args[2], os.Args[3:]...) 45 | cmd.Stdin = os.Stdin 46 | cmd.Stdout = os.Stdout 47 | cmd.Stderr = os.Stderr 48 | 49 | must(cmd.Run()) 50 | } 51 | 52 | func must(err error) { 53 | if err != nil { 54 | panic(err) 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /sp/container/container_simple4.go: -------------------------------------------------------------------------------- 1 | // +build linux 2 | 3 | // Simple "Docker"/Container implementation by Liz Rice. 4 | 5 | package main 6 | 7 | import ( 8 | "log" 9 | "os" 10 | "os/exec" 11 | "syscall" 12 | ) 13 | 14 | // go run main.go run 15 | func main() { 16 | switch os.Args[1] { 17 | case "run": 18 | run() 19 | case "child": 20 | child() 21 | default: 22 | panic("help") 23 | } 24 | } 25 | 26 | func run() { 27 | log.Printf("Running %v as PID %d \n", os.Args[1:], os.Getpid()) 28 | 29 | cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...) 30 | cmd.Stdin = os.Stdin 31 | cmd.Stdout = os.Stdout 32 | cmd.Stderr = os.Stderr 33 | cmd.SysProcAttr = &syscall.SysProcAttr{ 34 | Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS, 35 | Unshareflags: syscall.CLONE_NEWNS, 36 | } 37 | 38 | must(cmd.Run()) 39 | } 40 | 41 | func child() { 42 | log.Printf("Running %v as PID %d \n", os.Args[1:], os.Getpid()) 43 | 44 | cmd := exec.Command(os.Args[2], os.Args[3:]...) 45 | cmd.Stdin = os.Stdin 46 | cmd.Stdout = os.Stdout 47 | cmd.Stderr = os.Stderr 48 | 49 | must(syscall.Chroot("/opt/alpinefs")) // local fs 50 | must(os.Chdir("/")) 51 | must(syscall.Mount("proc", "proc", "proc", 0, "")) 52 | 53 | must(cmd.Run()) 54 | 55 | must(syscall.Unmount("proc", 0)) 56 | } 57 | 58 | func must(err error) { 59 | if err != nil { 60 | panic(err) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /sp/empty.go: -------------------------------------------------------------------------------- 1 | package sp 2 | 3 | // avoid empty package error on build platform Windows or OSX -------------------------------------------------------------------------------- /sp/samples/os/pid.go: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Johannes Weigend 2 | // Licensed under the Apache License, Version 2.0 3 | package main 4 | 5 | import ( 6 | "fmt" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | pid := os.Getpid() 12 | fmt.Println("process id: ", pid) 13 | } 14 | -------------------------------------------------------------------------------- /sp/samples/random/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | // #include <stdlib.h> 4 | import "C" 5 | import "fmt" 6 | 7 | func Seed(i int) { 8 | C.srandom(C.uint(i)) 9 | } 10 | 11 | func Random() int { 12 | var r C.long = C.random() // calls "int rand(void)" from the C std library 13 | return int(r) 14 | } 15 | 16 | func main() { 17 | Seed(1) 18 | fmt.Printf("random int from C is %d", Random()) 19 | } 20 | -------------------------------------------------------------------------------- /sp/samples/sqlite/cfuncs.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | /* 4 | extern int callback(void*, int, char**, char**); 5 | int callback_cgo(void* unused, int columnCount, char** columnTexts, char** columnsNames) { 6 | return callback(unused, columnCount, columnTexts, columnsNames); 7 | } 8 | */ 9 | import "C" 10 | -------------------------------------------------------------------------------- /sp/samples/sqlite/sqlite.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "unsafe" 6 | ) 7 | 8 | /* 9 | #cgo LDFLAGS: -lsqlite3 10 | #include 11 | #include 12 | #include 13 | int callback_cgo(void*, int, char**, char**); 14 | */ 15 | import "C" 16 | 17 | var columnNamesPrinted bool 18 | 19 | //export callback 20 | func callback(_ unsafe.Pointer, columnCount C.int, columnTexts **C.char, columnNames **C.char) C.int { 21 | if !columnNamesPrinted { 22 | names := goStringSlice(columnCount, columnNames) 23 | separator := "" 24 | for i := 0; i < int(columnCount); i++ { 25 | fmt.Printf("| %-20s ", names[i]) 26 | separator += fmt.Sprintf("|----------------------") 27 | } 28 | fmt.Printf("|\n") 29 | fmt.Printf("%s|\n", separator) 30 | columnNamesPrinted = true 31 | } 32 | texts := goStringSlice(columnCount, columnTexts) 33 | for i := 0; i < int(columnCount); i++ { 34 | fmt.Printf("| %-20s ", texts[i]) 35 | } 36 | fmt.Printf("|\n") 37 | return C.SQLITE_OK 38 | } 39 | 40 | func exec(db *C.sqlite3, statement string) error { 41 | sql := C.CString(statement) 42 | defer C.free(unsafe.Pointer(sql)) 43 | columnNamesPrinted = false 44 | rc := C.sqlite3_exec(db, sql, (*[0]byte)(C.callback_cgo), nil, nil) 45 | if rc != C.SQLITE_OK { 46 | errorMessage := C.GoString(C.sqlite3_errmsg(db)) 47 | return fmt.Errorf("sqlite3_exec returned code %d: %v", int(rc), errorMessage) 48 | } 49 | return nil 50 | } 51 | 52 | func main() { 53 | var db *C.sqlite3 54 | filename := C.CString("test.db") 55 | defer C.free(unsafe.Pointer(filename)) 56 | rc := C.sqlite3_open(filename, &db) 57 | defer C.sqlite3_close(db) 58 | if rc != C.SQLITE_OK { 59 | panic(fmt.Sprintf("sqlite3_open returned code %d", int(rc))) 60 | } 61 | 62 | err := exec(db, "create table if not exists students (id integer not null primary key autoincrement, name text);") 63 | if err != nil { 64 | panic(err) 65 | } 66 | err = exec(db, "insert into students (name) values ('Johannes Weigend');") 67 | if err != nil { 68 | panic(err) 69 | } 70 | err = exec(db, "insert into students (name) values ('Bernhard Saumweber');") 71 | if err != nil { 72 | panic(err) 73 | } 74 | err = exec(db, "select * from students;") 75 | if err != nil { 76 | panic(err) 77 | } 78 | } 79 | 80 | // converts a C string array of known length to a Golang string slice 81 | func goStringSlice(argc C.int, argv **C.char) []string { 82 | length := int(argc) 83 | temp := (*[1 << 30]*C.char)(unsafe.Pointer(argv))[:length:length] 84 | slice := make([]string, length) 85 | for i, s := range temp { 86 | slice[i] = C.GoString(s) 87 | } 88 | return slice 89 | } 90 | -------------------------------------------------------------------------------- /sp/samples/syscall/pid.go: -------------------------------------------------------------------------------- 1 | // +build linux darwin 2 | 3 | // Copyright 2018 Johannes Weigend, Johannes Siedersleben 4 | // Licensed under the Apache License, Version 2.0 5 | package main 6 | 7 | import ( 8 | "fmt" 9 | 10 | "golang.org/x/sys/unix" 11 | ) 12 | 13 | func main() { 14 | pid, _, _ := unix.Syscall(39, 0, 0, 0) 15 | fmt.Println("process id: ", pid) 16 | } 17 | -------------------------------------------------------------------------------- /webassembly/C/add/add.c: -------------------------------------------------------------------------------- 1 | int add(int a, int b) { 2 | return a+b; 3 | } 4 | 5 | -------------------------------------------------------------------------------- /webassembly/C/add/add.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const buf = fs.readFileSync('./add.wasm'); 3 | 4 | WebAssembly.instantiate(buf) 5 | .then(result => { 6 | console.log(result.instance.exports.add(5, 2)) 7 | }); 8 | 9 | -------------------------------------------------------------------------------- /webassembly/C/add/compile.sh: -------------------------------------------------------------------------------- 1 | clang -O2 -nostdlib -Wl,--no-entry -Wl,--export-all --target=wasm32 -o add.wasm add.c 2 | wasm-dis add.wasm 3 | node add.js 4 | -------------------------------------------------------------------------------- /webassembly/C/memory_math/compile.sh: -------------------------------------------------------------------------------- 1 | set -x 2 | clang -O2 --sysroot=/tmp/wasi-libc -nostartfiles -Wl,--no-entry -Wl,--export-all -target wasm32-unknown-wasi -o foo.wasm foo.c 3 | node foo.js 4 | 5 | -------------------------------------------------------------------------------- /webassembly/C/memory_math/foo.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // pointer points to an integer at memory address 2048 4 | int *data = (int*)2048; 5 | 6 | float foo(float x) 7 | { 8 | // set memory address 9 | *data = x+1; 10 | 11 | return cos(x); 12 | } -------------------------------------------------------------------------------- /webassembly/C/memory_math/foo.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const buf = fs.readFileSync('./foo.wasm'); 3 | 4 | WebAssembly 5 | .instantiate(buf) 6 | .then(result => { 7 | console.log(result.instance.exports.foo(42)); 8 | var memory = new Uint8Array(result.instance.exports.memory.buffer); 9 | console.log(memory[2048]); 10 | }); -------------------------------------------------------------------------------- /webassembly/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:latest 2 | MAINTAINER Sebastian Macke 3 | 4 | RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/testing" >> /etc/apk/repositories 5 | RUN echo "http://dl-cdn.alpinelinux.org/alpine/edge/community" >> /etc/apk/repositories 6 | 7 | RUN apk update && apk upgrade 8 | RUN apk add --no-cache bash file curl 9 | RUN apk add --no-cache go go-doc binaryen wabt 10 | RUN apk add --no-cache npm 11 | RUN apk add --no-cache nano nano-syntax tmux 12 | 13 | # for C support 14 | #RUN apk add git llvm clang lld make 15 | #RUN git clone https://github.com/CraneStation/wasi-libc.git && cd wasi-libc && make install INSTALL_DIR=/tmp/wasi-libc 16 | #RUN mkdir -p /usr/lib/clang/10.0.0/lib/wasi && cd /usr/lib/clang/10.0.0/lib/wasi && wget "https://github.com/jedisct1/libclang_rt.builtins-wasm32.a/raw/master/precompiled/libclang_rt.builtins-wasm32.a" 17 | 18 | # bash 19 | RUN echo 'include "/usr/share/nano/*.nanorc"' > /etc/nanorc 20 | RUN mkdir -p /root/wasm 21 | RUN echo 'export PS1=" [\w] > "' >> ~/.bashrc 22 | 23 | ENTRYPOINT ["/bin/bash"] 24 | -------------------------------------------------------------------------------- /webassembly/docker/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly development environment for WAST, C, and GO 2 | 3 | Start with 4 | ``` 5 | docker build -t wasm_env . 6 | ``` 7 | 8 | Run with 9 | ``` 10 | docker run -it --name wasm -v $PWD:/root/wasm wasm_env:latest 11 | ``` 12 | where $PWD is the path to your `webassembly` folder 13 | 14 | -------------------------------------------------------------------------------- /webassembly/go/call/compile.sh: -------------------------------------------------------------------------------- 1 | set -x 2 | GOARCH=wasm GOOS=js go build -o lib.wasm main.go 3 | #cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" . 4 | cp "/usr/share/doc/go/misc/wasm/wasm_exec.js" . 5 | 6 | -------------------------------------------------------------------------------- /webassembly/go/call/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |

5 | Hello from HTML! 6 |

7 | 8 | 13 | 14 | 15 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /webassembly/go/call/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "syscall/js" 5 | ) 6 | 7 | func add(this js.Value, input []js.Value) interface{} { 8 | result := input[0].Float() + input[1].Float() 9 | return js.ValueOf(result) 10 | } 11 | 12 | func main() { 13 | document := js.Global().Get("document") 14 | p := document.Call("createElement", "p") 15 | p.Set("innerHTML", "Hello WASM from Go!") 16 | document.Get("body").Call("appendChild", p) 17 | 18 | // register function 19 | js.Global().Set("add", js.FuncOf(add)) 20 | 21 | // prevent exit 22 | c := make(chan struct{}, 0) 23 | <-c 24 | } 25 | -------------------------------------------------------------------------------- /webassembly/go/hello/compile.sh: -------------------------------------------------------------------------------- 1 | set -x 2 | GOARCH=wasm GOOS=js go build -o lib.wasm main.go 3 | #cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" . 4 | cp "/usr/share/doc/go/misc/wasm/wasm_exec.js" . 5 | node wasm_exec.js lib.wasm 6 | 7 | -------------------------------------------------------------------------------- /webassembly/go/hello/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /webassembly/go/hello/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | func main() { 4 | println("Hello World") 5 | } 6 | -------------------------------------------------------------------------------- /webassembly/go/mandelbrot_wasm/compile.sh: -------------------------------------------------------------------------------- 1 | set -x 2 | GOARCH=wasm GOOS=js go build -o lib.wasm main.go 3 | #cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" . 4 | cp "/usr/share/doc/go/misc/wasm/wasm_exec.js" . 5 | -------------------------------------------------------------------------------- /webassembly/go/mandelbrot_wasm/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Go Mandelbrot 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /webassembly/wat/add.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const buf = fs.readFileSync('./add.wasm'); 3 | 4 | WebAssembly.instantiate(buf) 5 | .then(result => { 6 | console.log(result.instance.exports.add(5, 2)) 7 | }); 8 | 9 | -------------------------------------------------------------------------------- /webassembly/wat/add.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0xqab/concepts-of-programming-languages/4aa0140a90eb4a05e164e9826e2bf0e62de1366d/webassembly/wat/add.wasm -------------------------------------------------------------------------------- /webassembly/wat/add.wat: -------------------------------------------------------------------------------- 1 | (module 2 | (type (;0;) (func (param i32 i32) (result i32))) 3 | (func (;0;) (type 0) (param i32 i32) (result i32) 4 | local.get 0 5 | local.get 1 6 | i32.add) 7 | (export "add" (func 0))) 8 | -------------------------------------------------------------------------------- /webassembly/wat/compile.sh: -------------------------------------------------------------------------------- 1 | set -x 2 | wat2wasm add.wat 3 | wasm-dis add.wasm 4 | node add.js 5 | -------------------------------------------------------------------------------- /webassembly/wat/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | WAT wasm 5 | 6 | 7 | 8 | 19 | 20 | 21 | 22 | --------------------------------------------------------------------------------