Add tests and fix validators
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Brainfuck **!DRAFT!** 🚧
|
# Brainfuck **!DRAFT!** 🚧
|
||||||
|
|
||||||
Интерпретатор для brainfuck, насписаный на golang с линтером и дополнительными функциями
|
Интерпретатор с фазой компиляции для brainfuck, насписаный на golang с линтером и дополнительными функциями
|
||||||
|
|
||||||
> [!WARNING]
|
> [!WARNING]
|
||||||
> This is a WIP project, anything can be changed and/or broken without any notification beforehand
|
> This is a WIP project, anything can be changed and/or broken without any notification beforehand
|
||||||
|
|||||||
42
brainfuck.json
Normal file
42
brainfuck.json
Normal file
@@ -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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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'
|
|
||||||
|
|
||||||
1
src/lexer.go
Normal file
1
src/lexer.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package main
|
||||||
1
src/lexer_test.go
Normal file
1
src/lexer_test.go
Normal file
@@ -0,0 +1 @@
|
|||||||
|
package main
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
type Filter struct {
|
||||||
// "fmt"
|
|
||||||
)
|
}
|
||||||
|
|
||||||
func validateBrackets(src string) int {
|
func validateBrackets(src string) int {
|
||||||
count := 0
|
count := 0
|
||||||
@@ -55,12 +55,14 @@ func validatePointerBalance(src string) int {
|
|||||||
for _, c := range src {
|
for _, c := range src {
|
||||||
if c == '[' || c == ']' {
|
if c == '[' || c == ']' {
|
||||||
break
|
break
|
||||||
} else if c == '+' {
|
} else if c == '>' {
|
||||||
pointer_index++
|
pointer_index++
|
||||||
max_index = max(max_index, pointer_index)
|
max_index = max(max_index, pointer_index)
|
||||||
} else if c == '-' {
|
} else if c == '<' {
|
||||||
pointer_index--
|
pointer_index--
|
||||||
return -1
|
if pointer_index < 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return max_index
|
return max_index
|
||||||
88
src/linter_test.go
Normal file
88
src/linter_test.go
Normal file
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
35
src/main.go
35
src/main.go
@@ -31,39 +31,4 @@ func main() {
|
|||||||
|
|
||||||
save(file, firstArray, secondArray)
|
save(file, firstArray, secondArray)
|
||||||
load(file)
|
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("+-+-[]"))
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
@@ -56,8 +55,5 @@ func load(filepath string) ([]byte, []byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
data2Array = data2Array[4+data1ArraySize:]
|
data2Array = data2Array[4+data1ArraySize:]
|
||||||
fmt.Printf("Размер первого массива: %d\n", data1ArraySize)
|
|
||||||
fmt.Printf("Первый массив: %v\n", data1Array)
|
|
||||||
fmt.Printf("Второй массив: %v\n", data2Array)
|
|
||||||
return data1Array, data2Array, nil
|
return data1Array, data2Array, nil
|
||||||
}
|
}
|
||||||
47
src/persistence_test.go
Normal file
47
src/persistence_test.go
Normal file
@@ -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)
|
||||||
|
}
|
||||||
73
src/settings.go
Normal file
73
src/settings.go
Normal file
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user