From 2182034b8515dedfdcc71c328f50e1ac82fb764f Mon Sep 17 00:00:00 2001 From: Ilya Kaznacheev Date: Mon, 22 Oct 2018 03:09:39 +0300 Subject: [PATCH 1/8] Gotooh --- Go/petooh.go | 136 ++++++++++++++++++++++++++++++++++++++++++++++ Go/petooh_test.go | 31 +++++++++++ 2 files changed, 167 insertions(+) create mode 100644 Go/petooh.go create mode 100644 Go/petooh_test.go diff --git a/Go/petooh.go b/Go/petooh.go new file mode 100644 index 0000000..e5104af --- /dev/null +++ b/Go/petooh.go @@ -0,0 +1,136 @@ +package petooh + +import ( + "bufio" + "fmt" + "io" + "log" + "os" + "strings" +) + +const ( + koIncPtr = "Kudah" + koDecPtr = "kudah" + koInc = "Ko" + koDec = "kO" + koOut = "Kukarek" + koJmp = "Kud" + koRet = "kud" + validRunes = "adehkKoOru" +) + +func usage() { + fmt.Printf("Usage: %s filepath\n", os.Args[0]) + os.Exit(0) +} + +// Process function parses and processes source code commands +// +// r should contains source code +// w will get result output +func Process(r io.Reader, w io.Writer) { + var buffer string + var exit bool + level := 0 + pointer := 0 + operations := make([][]string, 1) + cells := make([]int, 1) + + cr := bufio.NewReader(r) + + for { + c, _, err := cr.ReadRune() + if err == io.EOF { + exit = true + } else if err != nil { + log.Fatal(err) + } + + if !strings.ContainsRune(validRunes, c) && !exit { + continue + } + + switch buffer { + case koInc: + if level > 0 { + operations[level] = append(operations[level], buffer) + } else { + cells[pointer]++ + } + buffer = "" + case koDec: + if level > 0 { + operations[level] = append(operations[level], buffer) + } else { + cells[pointer]-- + } + buffer = "" + case koIncPtr: + if level > 0 { + operations[level] = append(operations[level], buffer) + } else { + pointer++ + for len(cells) <= pointer { + cells = append(cells, 0) + } + } + buffer = "" + case koDecPtr: + if level > 0 { + operations[level] = append(operations[level], buffer) + } else { + pointer-- + } + buffer = "" + case koJmp: + if c != 'a' { + level++ + for len(operations) <= level { + operations = append(operations, []string{}) + } + operations[level] = make([]string, 0) + // log.Println("jmp:", buffer, level) + buffer = "" + } + case koRet: + if c != 'a' { + for cells[pointer] > 0 { + for _, operation := range operations[level] { + switch operation { + case koInc: + cells[pointer]++ + case koDec: + cells[pointer]-- + case koIncPtr: + pointer++ + for len(cells) <= pointer { + cells = append(cells, 0) + } + case koDecPtr: + pointer-- + case koOut: + w.Write([]byte(string(cells[pointer]))) + } + } + } + level-- + buffer = "" + } + case koOut: + if level > 0 { + operations[level] = append(operations[level], buffer) + } else { + w.Write([]byte(string(cells[pointer]))) + } + buffer = "" + } + + if exit { + break + } else { + buffer = buffer + string(c) + } + } + +} diff --git a/Go/petooh_test.go b/Go/petooh_test.go new file mode 100644 index 0000000..951fe99 --- /dev/null +++ b/Go/petooh_test.go @@ -0,0 +1,31 @@ +package petooh + +import ( + "bytes" + "strings" + "testing" +) + +const source = `KoKoKoKoKoKoKoKoKoKo Kud-Kudah + KoKoKoKoKoKoKoKo kudah kO kud-Kudah Kukarek kudah + KoKoKo Kud-Kudah + kOkOkOkO kudah kO kud-Kudah Ko Kukarek kudah + KoKoKoKo Kud-Kudah KoKoKoKo kudah kO kud-Kudah kO Kukarek + kOkOkOkOkO Kukarek Kukarek kOkOkOkOkOkOkO + Kukarek` +const res = "PETOOH" + +func TestProcess(t *testing.T) { + + r := strings.NewReader(source) + + // w := strings.Builder{} + w := bytes.NewBuffer([]byte{}) + + Process(r, w) + + if w.String() != res { + t.Errorf("method returns false result %s, but %s expected", w.String(), res) + } + +} From 364a025dc1dc824b047d6e877977148ced310ebc Mon Sep 17 00:00:00 2001 From: Ilya Kaznacheev Date: Mon, 22 Oct 2018 03:19:41 +0300 Subject: [PATCH 2/8] Gotooh example --- Go/example/run.go | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Go/example/run.go diff --git a/Go/example/run.go b/Go/example/run.go new file mode 100644 index 0000000..497cc41 --- /dev/null +++ b/Go/example/run.go @@ -0,0 +1,40 @@ +package main + +import ( + "flag" + "fmt" + "log" + "os" + + petooh "https://github.com/ilyakaznacheev/PETOOH/Go" +) + +func usage() { + fmt.Printf("Usage: %s filepath\n", os.Args[0]) + os.Exit(0) +} + +func init() { + flag.Usage = usage +} + +func main() { + // parse parameters + flag.Parse() + if flag.NArg() == 0 { + usage() + } + filePath := flag.Arg(0) + + // read file + file, err := os.Open(filePath) + if err != nil { + log.Fatal(err) + } + defer file.Close() + + // process file + petooh.Process(file, os.Stdout) + + fmt.Println() +} From 59f9e34f502c426714063ac32f09d21817b4e805 Mon Sep 17 00:00:00 2001 From: Ilya Kaznacheev Date: Mon, 22 Oct 2018 03:41:00 +0300 Subject: [PATCH 3/8] Gotooh interpreter in Go --- Go/README.md | 29 +++++++++++++++++++++++++++++ Go/example/run.go | 2 +- Go/petooh.go | 7 ------- 3 files changed, 30 insertions(+), 8 deletions(-) create mode 100644 Go/README.md diff --git a/Go/README.md b/Go/README.md new file mode 100644 index 0000000..b83f6bb --- /dev/null +++ b/Go/README.md @@ -0,0 +1,29 @@ +### DESCRIPTION + +PETOOH interpreter written in [Go](https://golang.org/). + +### USAGE + +Import package + +``` +go get github.com/Ky6uk/PETOOH/Go +``` + +and use Process() method + +```Go +package main + +import ( + petooh "github.com/Ky6uk/PETOOH/Go" +) +... +petooh.Process(r, w) +``` + +or run example/run.go with path to source file as parameter + +``` +go run example/run.go filepath +``` \ No newline at end of file diff --git a/Go/example/run.go b/Go/example/run.go index 497cc41..4dd26a5 100644 --- a/Go/example/run.go +++ b/Go/example/run.go @@ -6,7 +6,7 @@ import ( "log" "os" - petooh "https://github.com/ilyakaznacheev/PETOOH/Go" + petooh "github.com/Ky6uk/PETOOH/Go" ) func usage() { diff --git a/Go/petooh.go b/Go/petooh.go index e5104af..70c884d 100644 --- a/Go/petooh.go +++ b/Go/petooh.go @@ -2,10 +2,8 @@ package petooh import ( "bufio" - "fmt" "io" "log" - "os" "strings" ) @@ -20,11 +18,6 @@ const ( validRunes = "adehkKoOru" ) -func usage() { - fmt.Printf("Usage: %s filepath\n", os.Args[0]) - os.Exit(0) -} - // Process function parses and processes source code commands // // r should contains source code From 23367a8f104f49cc37235c3e1df0592dfdc2c263 Mon Sep 17 00:00:00 2001 From: Ilya Kaznacheev Date: Mon, 22 Oct 2018 11:32:38 +0300 Subject: [PATCH 4/8] Gotooh interpreter in Go --- Go/README.md | 2 +- Go/example/run.go | 5 ++++- Go/petooh.go | 18 ++++++++++++++---- Go/petooh_test.go | 27 +++++++++++++++++++++++++-- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/Go/README.md b/Go/README.md index b83f6bb..55c697f 100644 --- a/Go/README.md +++ b/Go/README.md @@ -19,7 +19,7 @@ import ( petooh "github.com/Ky6uk/PETOOH/Go" ) ... -petooh.Process(r, w) +err := petooh.Process(r, w) ``` or run example/run.go with path to source file as parameter diff --git a/Go/example/run.go b/Go/example/run.go index 4dd26a5..1789d07 100644 --- a/Go/example/run.go +++ b/Go/example/run.go @@ -34,7 +34,10 @@ func main() { defer file.Close() // process file - petooh.Process(file, os.Stdout) + err = petooh.Process(file, os.Stdout) + if err != nil { + log.Fatal(err) + } fmt.Println() } diff --git a/Go/petooh.go b/Go/petooh.go index 70c884d..ca40f16 100644 --- a/Go/petooh.go +++ b/Go/petooh.go @@ -2,8 +2,8 @@ package petooh import ( "bufio" + "errors" "io" - "log" "strings" ) @@ -22,7 +22,7 @@ const ( // // r should contains source code // w will get result output -func Process(r io.Reader, w io.Writer) { +func Process(r io.Reader, w io.Writer) error { var buffer string var exit bool level := 0 @@ -37,7 +37,7 @@ func Process(r io.Reader, w io.Writer) { if err == io.EOF { exit = true } else if err != nil { - log.Fatal(err) + return errors.New("error reading from file:" + err.Error()) } if !strings.ContainsRune(validRunes, c) && !exit { @@ -74,6 +74,9 @@ func Process(r io.Reader, w io.Writer) { operations[level] = append(operations[level], buffer) } else { pointer-- + if pointer < 0 { + return errors.New("data cell pointer is negative") + } } buffer = "" case koJmp: @@ -83,7 +86,6 @@ func Process(r io.Reader, w io.Writer) { operations = append(operations, []string{}) } operations[level] = make([]string, 0) - // log.Println("jmp:", buffer, level) buffer = "" } case koRet: @@ -102,12 +104,18 @@ func Process(r io.Reader, w io.Writer) { } case koDecPtr: pointer-- + if pointer < 0 { + return errors.New("data cell pointer is negative") + } case koOut: w.Write([]byte(string(cells[pointer]))) } } } level-- + if level < 0 { + return errors.New("operation level is negative") + } buffer = "" } case koOut: @@ -126,4 +134,6 @@ func Process(r io.Reader, w io.Writer) { } } + return nil + } diff --git a/Go/petooh_test.go b/Go/petooh_test.go index 951fe99..1d9ba9b 100644 --- a/Go/petooh_test.go +++ b/Go/petooh_test.go @@ -2,6 +2,7 @@ package petooh import ( "bytes" + "errors" "strings" "testing" ) @@ -15,17 +16,39 @@ const source = `KoKoKoKoKoKoKoKoKoKo Kud-Kudah Kukarek` const res = "PETOOH" +type errorReader struct { +} + +func (er errorReader) Read(p []byte) (n int, err error) { + return 0, errors.New("test") +} + func TestProcess(t *testing.T) { r := strings.NewReader(source) - // w := strings.Builder{} w := bytes.NewBuffer([]byte{}) - Process(r, w) + err := Process(r, w) if w.String() != res { t.Errorf("method returns false result %s, but %s expected", w.String(), res) } + if err != nil { + t.Errorf("failed on source code processing: %s", err) + } + +} + +func TestProcessEmpty(t *testing.T) { + r := errorReader{} + + w := bytes.NewBuffer([]byte{}) + + err := Process(r, w) + + if err == nil { + t.Error("should be error but no error was returned") + } } From 93c6caffad10ab39ad39abfe049269803a1cd604 Mon Sep 17 00:00:00 2001 From: Ilya Kaznacheev Date: Mon, 22 Oct 2018 14:49:59 +0300 Subject: [PATCH 5/8] Petooh interpreter in Go --- Go/README.md | 4 ++-- Go/example/run.go | 2 +- Go/{ => petooh}/petooh.go | 0 Go/{ => petooh}/petooh_test.go | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename Go/{ => petooh}/petooh.go (100%) rename Go/{ => petooh}/petooh_test.go (100%) diff --git a/Go/README.md b/Go/README.md index 55c697f..40f7005 100644 --- a/Go/README.md +++ b/Go/README.md @@ -7,7 +7,7 @@ PETOOH interpreter written in [Go](https://golang.org/). Import package ``` -go get github.com/Ky6uk/PETOOH/Go +go get github.com/Ky6uk/PETOOH/Go/petooh ``` and use Process() method @@ -16,7 +16,7 @@ and use Process() method package main import ( - petooh "github.com/Ky6uk/PETOOH/Go" + petooh "github.com/Ky6uk/PETOOH/Go/petooh" ) ... err := petooh.Process(r, w) diff --git a/Go/example/run.go b/Go/example/run.go index 1789d07..0fd1b64 100644 --- a/Go/example/run.go +++ b/Go/example/run.go @@ -6,7 +6,7 @@ import ( "log" "os" - petooh "github.com/Ky6uk/PETOOH/Go" + "github.com/Ky6uk/PETOOH/Go/petooh" ) func usage() { diff --git a/Go/petooh.go b/Go/petooh/petooh.go similarity index 100% rename from Go/petooh.go rename to Go/petooh/petooh.go diff --git a/Go/petooh_test.go b/Go/petooh/petooh_test.go similarity index 100% rename from Go/petooh_test.go rename to Go/petooh/petooh_test.go From 1bf451ed9125e98ab7f6f54a61a10775df309bfe Mon Sep 17 00:00:00 2001 From: Ilya Kaznacheev Date: Thu, 25 Oct 2018 18:31:36 +0300 Subject: [PATCH 6/8] Add syntax check --- Go/petooh/petooh.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Go/petooh/petooh.go b/Go/petooh/petooh.go index ca40f16..1e44460 100644 --- a/Go/petooh/petooh.go +++ b/Go/petooh/petooh.go @@ -4,6 +4,7 @@ import ( "bufio" "errors" "io" + "log" "strings" ) @@ -18,6 +19,25 @@ const ( validRunes = "adehkKoOru" ) +var koCommands = []string{ + koIncPtr, + koDecPtr, + koInc, + koDec, + koOut, + koJmp, + koRet, +} + +func isCMDSyntaxOK(cmd string) bool { + for _, koCMD := range koCommands { + if strings.HasPrefix(koCMD, cmd) { + return true + } + } + return false +} + // Process function parses and processes source code commands // // r should contains source code @@ -123,8 +143,14 @@ func Process(r io.Reader, w io.Writer) error { operations[level] = append(operations[level], buffer) } else { w.Write([]byte(string(cells[pointer]))) + log.Println() + log.Println(cells[pointer]) } buffer = "" + default: + if !isCMDSyntaxOK(buffer) { + return errors.New("wrong command: " + buffer) + } } if exit { From 59f0f4fb9030be8a0164328856063fb0d4a2d1ba Mon Sep 17 00:00:00 2001 From: Ilya Kaznacheev Date: Sun, 28 Oct 2018 02:10:26 +0300 Subject: [PATCH 7/8] Add more tests --- Go/README.md | 2 +- Go/petooh/petooh.go | 3 -- Go/petooh/petooh_test.go | 64 ++++++++++++++++++++++++++-------------- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/Go/README.md b/Go/README.md index 40f7005..d322153 100644 --- a/Go/README.md +++ b/Go/README.md @@ -16,7 +16,7 @@ and use Process() method package main import ( - petooh "github.com/Ky6uk/PETOOH/Go/petooh" + "github.com/Ky6uk/PETOOH/Go/petooh" ) ... err := petooh.Process(r, w) diff --git a/Go/petooh/petooh.go b/Go/petooh/petooh.go index 1e44460..51db995 100644 --- a/Go/petooh/petooh.go +++ b/Go/petooh/petooh.go @@ -4,7 +4,6 @@ import ( "bufio" "errors" "io" - "log" "strings" ) @@ -143,8 +142,6 @@ func Process(r io.Reader, w io.Writer) error { operations[level] = append(operations[level], buffer) } else { w.Write([]byte(string(cells[pointer]))) - log.Println() - log.Println(cells[pointer]) } buffer = "" default: diff --git a/Go/petooh/petooh_test.go b/Go/petooh/petooh_test.go index 1d9ba9b..e1520de 100644 --- a/Go/petooh/petooh_test.go +++ b/Go/petooh/petooh_test.go @@ -3,18 +3,29 @@ package petooh import ( "bytes" "errors" + "io" "strings" "testing" ) -const source = `KoKoKoKoKoKoKoKoKoKo Kud-Kudah +const ( + valDefault = `KoKoKoKoKoKoKoKoKoKo Kud-Kudah KoKoKoKoKoKoKoKo kudah kO kud-Kudah Kukarek kudah KoKoKo Kud-Kudah kOkOkOkO kudah kO kud-Kudah Ko Kukarek kudah KoKoKoKo Kud-Kudah KoKoKoKo kudah kO kud-Kudah kO Kukarek kOkOkOkOkO Kukarek Kukarek kOkOkOkOkOkOkO Kukarek` -const res = "PETOOH" + wrongSyntax = `Kudak` + wrongPointer = `kudah` + wrongPointerL = `KoKudkudahkud` + wrongLevel = `kudkud` + valLvl = `KudahKokudahKoKudKudah + KoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKo + KoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKo + KoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKoKo + KoKoKoKoKukarekkudahkOkud` +) type errorReader struct { } @@ -23,32 +34,41 @@ func (er errorReader) Read(p []byte) (n int, err error) { return 0, errors.New("test") } -func TestProcess(t *testing.T) { - - r := strings.NewReader(source) - +func processTestData(r io.Reader) (string, error) { w := bytes.NewBuffer([]byte{}) - err := Process(r, w) + return w.String(), err +} - if w.String() != res { - t.Errorf("method returns false result %s, but %s expected", w.String(), res) - } - - if err != nil { - t.Errorf("failed on source code processing: %s", err) +func TestProcess(t *testing.T) { + for _, td := range []struct { + r io.Reader + exp string + }{ + {strings.NewReader(valDefault), "PETOOH"}, //default example + {strings.NewReader(valLvl), "A"}, //simple example with A + } { + res, err := processTestData(td.r) + if res != td.exp { + t.Errorf("method returns false result %s, but %s expected", res, td.exp) + } + if err != nil { + t.Errorf("failed on valDefault code processing: %s", err) + } } - } func TestProcessEmpty(t *testing.T) { - r := errorReader{} - - w := bytes.NewBuffer([]byte{}) - - err := Process(r, w) - - if err == nil { - t.Error("should be error but no error was returned") + for _, r := range []io.Reader{ + errorReader{}, + strings.NewReader(wrongSyntax), //wrong sintax example + strings.NewReader(wrongPointer), //negative pointer + strings.NewReader(wrongPointerL), //negative pointer on second level + strings.NewReader(wrongLevel), //negative level + } { + _, err := processTestData(r) + if err == nil { + t.Error("should be error but no error was returned") + } } } From 626aec498412a04164760be39aa0e0a4ac0ee2e9 Mon Sep 17 00:00:00 2001 From: Ilya Kaznacheev Date: Sun, 28 Oct 2018 15:43:13 +0300 Subject: [PATCH 8/8] Classic Hello World example --- helloworld.koko | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 helloworld.koko diff --git a/helloworld.koko b/helloworld.koko new file mode 100644 index 0000000..7b9de96 --- /dev/null +++ b/helloworld.koko @@ -0,0 +1,9 @@ +KoKoKoKoKoKoKoKoKoKo Kud-Kudah KoKoKoKoKoKoKo Kudah +KoKoKoKoKoKoKoKoKoKo Kudah KoKoKo Kudah Ko kudah kudah kudah kudah +kO kud-Kudah KoKo Kukarek +Kudah Ko Kukarek KoKoKoKoKoKoKo Kukarek Kukarek +KoKoKo Kukarek Kudah KoKo Kukarek kudah kudah +KoKoKoKoKoKoKoKoKoKoKoKoKoKoKo Kukarek +Kudah Kukarek KoKoKo Kukarek +kOkOkOkOkOkO Kukarek kOkOkOkOkOkOkOkO Kukarek Kudah Ko +Kukarek Kudah Kukarek