diff --git a/README.md b/README.md index e1703f0..79a3ff8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Brainfuck **!DRAFT!** 🚧 -Π˜Π½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚Π°Ρ‚ΠΎΡ€ для brainfuck, насписаный Π½Π° golang с Π»ΠΈΠ½Ρ‚Π΅Ρ€ΠΎΠΌ ΠΈ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ функциями +Π˜Π½Ρ‚Π΅Ρ€ΠΏΡ€Π΅Ρ‚Π°Ρ‚ΠΎΡ€ с Ρ„Π°Π·ΠΎΠΉ компиляции для brainfuck, насписаный Π½Π° golang с Π»ΠΈΠ½Ρ‚Π΅Ρ€ΠΎΠΌ ΠΈ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹ΠΌΠΈ функциями > [!WARNING] > This is a WIP project, anything can be changed and/or broken without any notification beforehand diff --git a/brainfuck.json b/brainfuck.json new file mode 100644 index 0000000..3b64a07 --- /dev/null +++ b/brainfuck.json @@ -0,0 +1,42 @@ +{ + "unicode": true, + "memory_cells": 30000, + "load_dump": "data_in.bin", + "save_dump": "data_out.bin", + "sources": [ + "example/hw.bf" + ], + "compiled": "bin/hw.bfc", + "lint": [ + { + "name": "brackets", + "level": "error", + "expected": "=1" + }, + { + "name": "operators", + "level": "warning", + "expected": "=1" + }, + { + "name": "loop_depth", + "level": "warning", + "expected": "<=100" + }, + { + "name": "loop_depth", + "level": "error", + "expected": "<=255" + }, + { + "name": "pointer_balance", + "level": "error", + "expected": "<0" + }, + { + "name": "pointer_balance", + "level": "warning", + "expected": ">30000" + } + ] +} \ No newline at end of file diff --git a/brainfuck.yml b/brainfuck.yml deleted file mode 100644 index 16d8ceb..0000000 --- a/brainfuck.yml +++ /dev/null @@ -1,28 +0,0 @@ -brainfuck: - unicode: true - memory_cells: 30000 - load_dump: 'data_in.bin' - save_dump: 'data_out.bin' - sorces: - - 'example/hw.bf' - compiled: 'bin/hw.bfc' - lint: - - brackets - level: 'error' - expected: '=1' - - operators - level: 'warning' - expected: '=1' - - loop_depth - level: 'warning' - expected: '<=100' - - loop_depth - level: 'error' - expected: '<=255' - - pointer_balance - level: 'error' - expected: '<0' - - pointer_balance - level: 'warning' - expected: '>30000' - \ No newline at end of file diff --git a/src/lexer.go b/src/lexer.go new file mode 100644 index 0000000..85f0393 --- /dev/null +++ b/src/lexer.go @@ -0,0 +1 @@ +package main \ No newline at end of file diff --git a/src/lexer_test.go b/src/lexer_test.go new file mode 100644 index 0000000..85f0393 --- /dev/null +++ b/src/lexer_test.go @@ -0,0 +1 @@ +package main \ No newline at end of file diff --git a/src/validation.go b/src/linter.go similarity index 89% rename from src/validation.go rename to src/linter.go index 7173b89..77f4d8c 100644 --- a/src/validation.go +++ b/src/linter.go @@ -1,8 +1,8 @@ package main -import ( - // "fmt" -) +type Filter struct { + +} func validateBrackets(src string) int { count := 0 @@ -55,12 +55,14 @@ func validatePointerBalance(src string) int { for _, c := range src { if c == '[' || c == ']' { break - } else if c == '+' { + } else if c == '>' { pointer_index++ max_index = max(max_index, pointer_index) - } else if c == '-' { + } else if c == '<' { pointer_index-- - return -1 + if pointer_index < 0 { + return -1 + } } } return max_index diff --git a/src/linter_test.go b/src/linter_test.go new file mode 100644 index 0000000..634b3e5 --- /dev/null +++ b/src/linter_test.go @@ -0,0 +1,88 @@ +package main + +import ( + "testing" +) + +func TestValidateBrackets(t *testing.T) { + tests := []struct { + input string + expected int + }{ + {"[][][]", 1}, + {"[[[]]]", 1}, + {"[[[][]]]", 1}, + {"[", 0}, + {"]", 0}, + {"][", 0}, + {"[]", 1}, + } + + for _, test := range tests { + result := validateBrackets(test.input) + if result != test.expected { + t.Errorf("validateBrackets(%q) = %v; expected %v", test.input, result, test.expected) + } + } +} + +func TestValidateOperators(t *testing.T) { + tests := []struct { + input string + expected int + }{ + {"+-<>-+.,[]", -1}, + {"+-<>-+.,()", 8}, + {"hello", 0}, + } + + for _, test := range tests { + result := validateOperators(test.input) + if result != test.expected { + t.Errorf("validateOperators(%q) = %v; expected %v", test.input, result, test.expected) + } + } +} + +func TestValidateLoopDepth(t *testing.T) { + tests := []struct { + input string + expected int + }{ + {"+++---", 0}, + {"+++[->+<]", 1}, + {"[[[", -1}, + {"[]", 1}, + {"[[][]]", 2}, + {"[[[]][]]", 3}, + {"[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]", 22}, + } + + for _, test := range tests { + result := validateLoopDepth(test.input) + if result != test.expected { + t.Errorf("validateLoopDepth(%q) = %v; expected %v", test.input, result, test.expected) + } + } +} + +func TestValidatePointerBalance(t *testing.T) { + tests := []struct { + input string + expected int + }{ + {">>><<<", 3}, + {"<<<>>>", -1}, + {">>>>>>", 6}, + {">>>>[]", 4}, + {"<<<<[]", -1}, + {"><><[]", 1}, + } + + for _, test := range tests { + result := validatePointerBalance(test.input) + if result != test.expected { + t.Errorf("validatePointerBalance(%q) = %v; expected %v", test.input, result, test.expected) + } + } +} diff --git a/src/main.go b/src/main.go index d4bb753..c2cb47d 100644 --- a/src/main.go +++ b/src/main.go @@ -31,39 +31,4 @@ func main() { save(file, firstArray, secondArray) load(file) - - fmt.Println() - - fmt.Println(validateBrackets("[][][]")) - fmt.Println(validateBrackets("[[[]]]")) - fmt.Println(validateBrackets("[[[][]]]")) - fmt.Println(validateBrackets("[")) - fmt.Println(validateBrackets("]")) - fmt.Println(validateBrackets("][")) - fmt.Println(validateBrackets("[]")) - - fmt.Println() - - fmt.Println(validateOperators("+-<>-+.,[]")) - fmt.Println(validateOperators("+-<>-+.,()")) - fmt.Println(validateOperators("hello")) - - fmt.Println() - - fmt.Println(validateLoopDepth("+++---")) - fmt.Println(validateLoopDepth("+++[->+<]")) - fmt.Println(validateLoopDepth("[[[")) - fmt.Println(validateLoopDepth("[]")) - fmt.Println(validateLoopDepth("[[][]]")) - fmt.Println(validateLoopDepth("[[[]][]]")) - fmt.Println(validateLoopDepth("[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]")) - - fmt.Println() - - fmt.Println(validatePointerBalance("+++---")) - fmt.Println(validatePointerBalance("---+++")) - fmt.Println(validatePointerBalance("++++++")) - fmt.Println(validatePointerBalance("++++[]")) - fmt.Println(validatePointerBalance("----[]")) - fmt.Println(validatePointerBalance("+-+-[]")) } diff --git a/src/serialization.go b/src/persistence.go similarity index 83% rename from src/serialization.go rename to src/persistence.go index 8264722..0433b97 100644 --- a/src/serialization.go +++ b/src/persistence.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "encoding/binary" "os" ) @@ -56,8 +55,5 @@ func load(filepath string) ([]byte, []byte, error) { } data2Array = data2Array[4+data1ArraySize:] - fmt.Printf("Π Π°Π·ΠΌΠ΅Ρ€ ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ массива: %d\n", data1ArraySize) - fmt.Printf("ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ массив: %v\n", data1Array) - fmt.Printf("Π’Ρ‚ΠΎΡ€ΠΎΠΉ массив: %v\n", data2Array) return data1Array, data2Array, nil } \ No newline at end of file diff --git a/src/persistence_test.go b/src/persistence_test.go new file mode 100644 index 0000000..0869ddf --- /dev/null +++ b/src/persistence_test.go @@ -0,0 +1,47 @@ +package main + +import ( + "bytes" + "encoding/binary" + "os" + "testing" +) + +func TestSaveAndLoad(t *testing.T) { + file := "test.bfc" + firstArray := []byte{0x01, 0x02, 0x03, 0x04, 0x05} + secondArray := []byte{0xAA, 0xBB, 0xCC} + + save(file, firstArray, secondArray) + + if _, err := os.Stat(file); os.IsNotExist(err) { + t.Errorf("Π€Π°ΠΉΠ» %s Π½Π΅ Π±Ρ‹Π» создан", file) + } + + load(file) + + os.Remove(file) +} + +func TestSaveContent(t *testing.T) { + file := "test_content.bfc" + firstArray := []byte{1, 2, 3} + secondArray := []byte{10, 20} + + save(file, firstArray, secondArray) + + data, err := os.ReadFile(file) + if err != nil { + t.Fatalf("НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΠΏΡ€ΠΎΡ‡ΠΈΡ‚Π°Ρ‚ΡŒ Ρ„Π°ΠΉΠ»: %v", err) + } + + sizeBytes := make([]byte, 4) + binary.BigEndian.PutUint32(sizeBytes, uint32(len(firstArray))) + expected := append(sizeBytes, firstArray...) + expected = append(expected, secondArray...) + if !bytes.Equal(data, expected) { + t.Errorf("Π‘ΠΎΠ΄Π΅Ρ€ΠΆΠΈΠΌΠΎΠ΅ Ρ„Π°ΠΉΠ»Π°: %v; оТидалось: %v", data, expected) + } + + os.Remove(file) +} diff --git a/src/settings.go b/src/settings.go new file mode 100644 index 0000000..db740a3 --- /dev/null +++ b/src/settings.go @@ -0,0 +1,73 @@ +package main + +import ( + "encoding/json" + "os" +) + +type Config struct { + Unicode bool `json:"unicode"` + MemoryCells int `json:"memory_cells"` + LoadDump string `json:"load_dump"` + SaveDump string `json:"save_dump"` + Sources []string `json:"soΠ³rces"` + Compiled string `json:"compiled"` + Lint []LintRule `json:"lint"` +} + +type LintRule struct { + Name string `json:"name"` + Level string `json:"level"` + Expected string `json:"expected"` +} + +func createDefaultConfig() *Config { + return &Config{ + Unicode: false, + MemoryCells: 30000, + LoadDump: "data_in.bin", + SaveDump: "data_out.bin", + Sources: []string{"example/default.bf"}, + Compiled: "bin/default.bfc", + Lint: []LintRule{ + {Name: "brackets", Level: "error", Expected: "=1"}, + {Name: "operators", Level: "warning", Expected: "=1"}, + {Name: "loop_depth", Level: "warning", Expected: "<=100"}, + {Name: "loop_depth", Level: "error", Expected: "<=255"}, + {Name: "pointer_balance", Level: "error", Expected: "<0"}, + {Name: "pointer_balance", Level: "warning", Expected: ">30000"}, + }, + } +} + +func saveConfig(filename string, config *Config) error { + data, err := json.MarshalIndent(config, "", " ") + if err != nil { + return err + } + return os.WriteFile(filename, data, 0644) +} + +func loadConfig(filename string) (*Config, error) { + if _, err := os.Stat(filename); os.IsNotExist(err) { + config := createDefaultConfig() + err := saveConfig(filename, config) + if err != nil { + return nil, err + } + return config, errors.New("\"brainfuck.json\" not found. Used default config") + } + + data, err := os.ReadFile(filename) + if err != nil { + return nil, err + } + + var config Config + err = json.Unmarshal(data, &config) + if err != nil { + return nil, err + } + + return &config, nil +} \ No newline at end of file