Add tests and fix validators

This commit is contained in:
2025-10-30 12:46:36 +03:00
parent 2471375f80
commit 2f416adb00
11 changed files with 261 additions and 74 deletions

View File

@@ -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

42
brainfuck.json Normal file
View 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"
}
]
}

View File

@@ -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
View File

@@ -0,0 +1 @@
package main

1
src/lexer_test.go Normal file
View File

@@ -0,0 +1 @@
package main

View File

@@ -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

88
src/linter_test.go Normal file
View 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)
}
}
}

View File

@@ -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("+-+-[]"))
}

View File

@@ -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
}

47
src/persistence_test.go Normal file
View 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
View 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
}