diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 1792e92..3f182cd 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -8,15 +8,21 @@ jobs: steps: - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: '3.x' - - name: Build programs - run: ./scripts/build_programs.sh + - name: Build programs binaries + run: python ./scripts/build.py - - name: Build examples - run: ./scripts/build_examples.sh + - name: Compile examples + run: python ./scripts/test.py com ./test/ && python ./scripts/test.py com ./examples/ - name: Unit Tests run: go test ./... - - name: Test Examples - run: ./scripts/run_examples.sh + - name: Run tests + run : python ./scripts/test.py run ./test/ + + - name: Run examples + run: python ./scripts/test.py run ./examples/ diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..e08c2c8 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1 @@ +*.copper \ No newline at end of file diff --git a/examples/123.txt b/examples/123.txt new file mode 100644 index 0000000..c44c6ec Binary files /dev/null and b/examples/123.txt differ diff --git a/examples/test/e.txt b/examples/e.txt similarity index 100% rename from examples/test/e.txt rename to examples/e.txt diff --git a/examples/test/euclid.txt b/examples/euclid.txt similarity index 100% rename from examples/test/euclid.txt rename to examples/euclid.txt diff --git a/examples/test/fib.txt b/examples/fib.txt similarity index 100% rename from examples/test/fib.txt rename to examples/fib.txt diff --git a/examples/test/hello.txt b/examples/hello.txt similarity index 100% rename from examples/test/hello.txt rename to examples/hello.txt diff --git a/examples/test/lerpf.txt b/examples/lerpf.txt similarity index 100% rename from examples/test/lerpf.txt rename to examples/lerpf.txt diff --git a/examples/test/memory.txt b/examples/memory.txt similarity index 100% rename from examples/test/memory.txt rename to examples/memory.txt diff --git a/examples/test/rule110.txt b/examples/rule110.txt similarity index 100% rename from examples/test/rule110.txt rename to examples/rule110.txt diff --git a/examples/test/rule30.txt b/examples/rule30.txt similarity index 100% rename from examples/test/rule30.txt rename to examples/rule30.txt diff --git a/examples/test/123.txt b/examples/test/123.txt deleted file mode 100644 index 1e8b314..0000000 --- a/examples/test/123.txt +++ /dev/null @@ -1 +0,0 @@ -6 diff --git a/examples/test/hex.txt b/examples/test/hex.txt deleted file mode 100644 index 47eb669..0000000 --- a/examples/test/hex.txt +++ /dev/null @@ -1 +0,0 @@ -316 diff --git a/examples/test/struct.txt b/examples/test/struct.txt deleted file mode 100644 index 8b13789..0000000 --- a/examples/test/struct.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/scripts/build.py b/scripts/build.py new file mode 100644 index 0000000..cac05f0 --- /dev/null +++ b/scripts/build.py @@ -0,0 +1,15 @@ +import subprocess +import os + +build_dir = "build" +cmd_dir = "cmd" + +executables = ["casm", "deasm", "emulator", "copperdb"] + +if __name__ == "__main__": + if [r.returncode for r in [subprocess.run([ + "go", "build", + "-o", os.path.join(build_dir, ex), + os.path.join(cmd_dir, ex, ex+".go") + ]) for ex in executables] if r.returncode != 0]: + exit(1) \ No newline at end of file diff --git a/scripts/build_examples.sh b/scripts/build_examples.sh deleted file mode 100755 index 8535ae3..0000000 --- a/scripts/build_examples.sh +++ /dev/null @@ -1,12 +0,0 @@ -#! /bin/sh - -set -e - -mkdir -p examples/bin - -examples=$(find examples/ -maxdepth 1 -name "*.casm" -type f) -for e in $examples; do - name=$(basename $e) - name=${name%.casm} - ./build/casm -t copper -o "examples/bin/$name.copper" $e -I stdlib/ -done \ No newline at end of file diff --git a/scripts/build_examples_x86-64_linux.sh b/scripts/build_examples_x86-64_linux.sh deleted file mode 100755 index b405a93..0000000 --- a/scripts/build_examples_x86-64_linux.sh +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/sh - -set -e - -mkdir -p examples/bin - -examples=$(find examples/ -maxdepth 1 -name "*.casm" -type f) -for e in $examples; do - name=$(basename $e) - name=${name%.casm} - ./build/casm -t x86-64linux -o "examples/bin/$name.asm" $e -I stdlib/ - nasm -felf64 "examples/bin/$name.asm" - ld -o "examples/bin/$name" "examples/bin/$name.o" -done \ No newline at end of file diff --git a/scripts/build_programs.bat b/scripts/build_programs.bat deleted file mode 100755 index 806d416..0000000 --- a/scripts/build_programs.bat +++ /dev/null @@ -1,11 +0,0 @@ -@echo off - -set BUILD_DIR=build -set CMD_DIR=cmd - -if not exist "%BUILD_DIR%" mkdir %BUILD_DIR% - -go build -o "%BUILD_DIR%/casm.exe" "%CMD_DIR%/casm/casm.go" -go build -o "%BUILD_DIR%/deasm.exe" "%CMD_DIR%/deasm/deasm.go" -go build -o "%BUILD_DIR%/emulator.exe" "%CMD_DIR%/emulator/emulator.go" -go build -o "%BUILD_DIR%/copperdb.exe" "%CMD_DIR%/copperdb/copperdb.go" diff --git a/scripts/build_programs.sh b/scripts/build_programs.sh deleted file mode 100755 index 248a811..0000000 --- a/scripts/build_programs.sh +++ /dev/null @@ -1,13 +0,0 @@ -#! /bin/sh - -set -e - -BUILD_DIR=build -CMD_DIR=cmd - -mkdir -p $BUILD_DIR - -go build -o $BUILD_DIR/casm $CMD_DIR/casm/casm.go -go build -o $BUILD_DIR/deasm $CMD_DIR/deasm/deasm.go -go build -o $BUILD_DIR/emulator $CMD_DIR/emulator/emulator.go -go build -o $BUILD_DIR/copperdb $CMD_DIR/copperdb/copperdb.go diff --git a/scripts/install_programs.bat b/scripts/install_programs.bat deleted file mode 100644 index 2ba4218..0000000 --- a/scripts/install_programs.bat +++ /dev/null @@ -1,12 +0,0 @@ -@echo off - -set CMD_DIR="cmd" - -go install "%CMD_DIR%/casm/casm.go" -go install "%CMD_DIR%/deasm/deasm.go" -go install "%CMD_DIR%/emulator/emulator.go" -go install "%CMD_DIR%/copperdb/copperdb.go" - -for /f %%i in ('go env GOPATH') do set GOPATH=%%i - -xcopy.exe .\stdlib %GOPATH%\stdlib\ /E /Y /F \ No newline at end of file diff --git a/scripts/install_programs.sh b/scripts/install_programs.sh deleted file mode 100755 index 8c268da..0000000 --- a/scripts/install_programs.sh +++ /dev/null @@ -1,14 +0,0 @@ -#! /bin/sh - -set -e - -CMD_DIR="cmd" - -go install "$CMD_DIR/casm/casm.go" -go install "$CMD_DIR/deasm/deasm.go" -go install "$CMD_DIR/emulator/emulator.go" -go install "$CMD_DIR/copperdb/copperdb.go" - -GOPATH=$(go env GOPATH) - -cp -Rf "./stdlib" "$GOPATH" \ No newline at end of file diff --git a/scripts/record_examples_tests.sh b/scripts/record_examples_tests.sh deleted file mode 100755 index 78258a9..0000000 --- a/scripts/record_examples_tests.sh +++ /dev/null @@ -1,15 +0,0 @@ -#! /bin/sh - -set -e - -mkdir -p examples/test - -bins=$(find examples/bin -maxdepth 1 -name "*.copper" -type f) -for binary in $bins; do - file_name=$(basename $binary) - file_name=${file_name%.copper} - - echo "Record '$binary'" - program_output=$(build/emulator $binary) - echo "$program_output" > "examples/test/$file_name.txt" -done \ No newline at end of file diff --git a/scripts/run_examples.sh b/scripts/run_examples.sh deleted file mode 100755 index 54a5614..0000000 --- a/scripts/run_examples.sh +++ /dev/null @@ -1,18 +0,0 @@ -#! /bin/sh - -set -e - -bins=$(find examples/bin -maxdepth 1 -name "*.copper" -type f) -for binary in $bins; do - file_name=$(basename $binary) - file_name=${file_name%.copper} - - echo "Run '$binary'" - output=$(./build/emulator $binary) - - value=$(cat "examples/test/$file_name.txt") - if [ "$value" != "$output" ]; then - echo "'$binary' produced a different output from what expected" - exit 1 - fi -done \ No newline at end of file diff --git a/scripts/test.py b/scripts/test.py new file mode 100644 index 0000000..ff8bb03 --- /dev/null +++ b/scripts/test.py @@ -0,0 +1,154 @@ +import sys +import os +import subprocess + +emulator_path = "./build/emulator" +casm_path = "./build/casm" + +casm_file_ext = ".casm" +result_file_ext = ".txt" +bin_file_ext = ".copper" + +def compile_folder(folder): + assert os.path.isdir(folder) + + failed = 0 + files = list(filter(lambda p: p.endswith(casm_file_ext), os.listdir(folder))) + for file in files: + if not compile_file(os.path.join(folder, file)): + failed+=1 + print() + print("All tests compiled!") + print(f"Passed: {len(files)-failed}, Failed: {failed}") + if failed != 0: + exit(1) + +def compile_file(file_path): + assert os.path.exists(file_path) + assert os.path.isfile(file_path) + + out_file_path = os.path.splitext(file_path)[0] + bin_file_ext + + result = subprocess.run([ + casm_path, + "-t", "copper", + "-o", out_file_path, + file_path]) + if not result.returncode == 0: + return False + return True + +def run_tests_for_dir(folder): + assert os.path.isdir(folder) + failed = 0 + files = list(filter(lambda p: p.endswith(casm_file_ext), os.listdir(folder))) + for file in files: + if not run_tests_for_file(os.path.join(folder, file)): + failed += 1 + + print() + print("All tests executed!") + print(f"Passed: {len(files)-failed}, Failed: {failed}") + if failed != 0: + exit(1) + +def run_tests_for_file(file_path): + result_file_path = os.path.splitext(file_path)[0] + result_file_ext + bin_file_path = os.path.splitext(file_path)[0] + bin_file_ext + + if not os.path.exists(result_file_path): + print(f"ERROR: file '{result_file_path}' doesn't exist") + exit(1) + if not os.path.exists(bin_file_path): + print(f"ERROR: file '{bin_file_path}' doesn't exist") + exit(1) + + with open(result_file_path, "rb") as result_file: + expected_result = result_file.read() + + actual_result = subprocess.run([emulator_path, bin_file_path], capture_output=True) + if actual_result.returncode != 0 or expected_result != actual_result.stdout: + print(f"ERROR: test '{file_path}' returned a different result from expected") + print(f" status code: {actual_result.returncode}") + print(f" expected: {expected_result.decode('UTF-8')}") + print(f" actual: {actual_result.stdout.decode('UTF-8')}") + return False + return True + +def record_folder_output(folder): + assert os.path.isdir(folder) + [record_file_output(os.path.join(folder, file)) for file in list(filter(lambda p: p.endswith(casm_file_ext), os.listdir(folder)))] + +def record_file_output(file_path): + out_file_path = os.path.splitext(file_path)[0] + result_file_ext + bin_file_path = os.path.splitext(file_path)[0] + bin_file_ext + + if not os.path.exists(bin_file_path): + print(f"ERROR: file '{bin_file_path}' doesn't exist") + exit(1) + + test_result = subprocess.run([emulator_path, bin_file_path], capture_output=True) + if test_result.returncode != 0: + print(f"ERROR: cannot record test '{file_path}' because it failed") + exit(1) + + with open(out_file_path, "wb+") as out_file: + out_file.write(test_result.stdout) + +def expect_arg(argv, program): + if len(argv) == 0: + usage(program) + print("ERROR: expecting a file/folder path afer command") + exit(1) + +def usage(program): + print(f"Usage {program} [OPRIONS] [SUBCOMMAND]") + print("[USAGE]: ") + print(" -h Print this help message.") + print("[SUBCOMMAND]:") + print(f" com Compiles a given file or folder to binary") + print(f" run Run all tests for a given file or folder") + print(f" record Record the outputs of given file or folder") + +if __name__ == "__main__": + program, *argv = sys.argv + + command = "run" + if len(argv) > 0: + command, *argv = argv + + if command == "-h": + usage(program) + exit(0) + elif command == "com": + expect_arg(argv, program) + path, *argv = argv + if os.path.isdir(path): + compile_folder(path) + else: + ok = compile_file(path) + print(f"Test {path} compiled with {'success' if ok else 'failure'}!") + if not ok: + exit(1) + elif command == "run": + expect_arg(argv, program) + path, *argv = argv + if os.path.isdir(path): + run_tests_for_dir(path) + else: + ok = run_tests_for_file(path) + print(f"Test {path} executed with {'success' if ok else 'failure'}!") + if not ok: + exit(1) + elif command == "record": + expect_arg(argv, program) + path, *argv = argv + if os.path.isdir(path): + record_folder_output(path) + else: + record_file_output(path) + else: + usage(program) + print(f"ERROR: unknown command {command}") + exit(1) + diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 0000000..e08c2c8 --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +*.copper \ No newline at end of file diff --git a/examples/operations.casm b/test/arithmetics.casm similarity index 80% rename from examples/operations.casm rename to test/arithmetics.casm index 547a3d7..e29bb47 100644 --- a/examples/operations.casm +++ b/test/arithmetics.casm @@ -3,145 +3,109 @@ integer: push 1 push 2 add - dup print - drop ; add signed integers push -1 push 2 add - dup print - drop ; subtract integers push 2 push 1 sub - dup print - drop ; subtract signed integers push -2 push 1 sub - dup print - drop ; multiply integers push 2 push 1 mul - dup print - drop ; multiply signed integers push -2 push 1 imul - dup print - drop ; divide integers push 3 push 2 div - dup print - drop ; divide signed integers push -2 push 5 idiv - dup print - drop ; modulo integers push 6 push 2 mod - dup print - drop ; modulo signed integers push -8 push 5 imod - dup print - drop floating_point: ; add float push 1.0 push 2.0 fadd - dup print - drop ; add signed float push -1.0 push 2.0 fadd - dup print - drop ; subtract float push 2.0 push 1.0 fsub - dup print - drop ; subtract signed float push -2.0 push 1.0 fsub - dup print - drop ; multiply float push 2.0 push 1.0 fmul - dup print - drop ; multiply signed float push -2.0 push 1.0 fmul - dup print - drop ; divide float push 3.0 push 2.0 fdiv - dup print - drop ; divide signed float push -2.0 push 5.0 fdiv - dup print - drop halt \ No newline at end of file diff --git a/examples/test/operations.txt b/test/arithmetics.txt similarity index 84% rename from examples/test/operations.txt rename to test/arithmetics.txt index ec415aa..6eb0e08 100644 --- a/examples/test/operations.txt +++ b/test/arithmetics.txt @@ -11,8 +11,8 @@ u64: 18446744073709551613, i64: -3, f64: -3.000000 u64: 3, i64: 3, f64: 3.000000 u64: 1, i64: 1, f64: 1.000000 u64: 1, i64: 1, f64: 1.000000 -u64: 18446744073709551613, i64: -3, f64: -3.000000 +u64: 0, i64: -3, f64: -3.000000 u64: 2, i64: 2, f64: 2.000000 -u64: 18446744073709551614, i64: -2, f64: -2.000000 +u64: 0, i64: -2, f64: -2.000000 u64: 1, i64: 1, f64: 1.500000 u64: 0, i64: 0, f64: -0.400000 diff --git a/examples/binop.casm b/test/binop.casm similarity index 100% rename from examples/binop.casm rename to test/binop.casm diff --git a/examples/test/binop.txt b/test/binop.txt similarity index 100% rename from examples/test/binop.txt rename to test/binop.txt diff --git a/examples/boolop.casm b/test/boolop.casm similarity index 100% rename from examples/boolop.casm rename to test/boolop.casm diff --git a/examples/test/boolop.txt b/test/boolop.txt similarity index 100% rename from examples/test/boolop.txt rename to test/boolop.txt diff --git a/examples/files.casm.exclude b/test/files.casm.exclude similarity index 100% rename from examples/files.casm.exclude rename to test/files.casm.exclude diff --git a/examples/funcall.casm b/test/funcall.casm similarity index 100% rename from examples/funcall.casm rename to test/funcall.casm diff --git a/examples/test/funcall.txt b/test/funcall.txt similarity index 100% rename from examples/test/funcall.txt rename to test/funcall.txt diff --git a/examples/hex.casm b/test/hex.casm similarity index 100% rename from examples/hex.casm rename to test/hex.casm diff --git a/test/hex.txt b/test/hex.txt new file mode 100644 index 0000000..ff53165 Binary files /dev/null and b/test/hex.txt differ diff --git a/examples/numbers.casm b/test/numbers.casm similarity index 100% rename from examples/numbers.casm rename to test/numbers.casm diff --git a/examples/test/numbers.txt b/test/numbers.txt similarity index 77% rename from examples/test/numbers.txt rename to test/numbers.txt index 3863420..755f242 100644 --- a/examples/test/numbers.txt +++ b/test/numbers.txt @@ -1,6 +1,6 @@ u64: 1, i64: 1, f64: 1.000000 u64: 2, i64: 2, f64: 2.000000 u64: 18446744073709551611, i64: -5, f64: -5.000000 -u64: 18446744073709551613, i64: -3, f64: -3.200000 +u64: 0, i64: -3, f64: -3.200000 u64: 255, i64: 255, f64: 255.000000 u64: 9, i64: 9, f64: 9.000000 diff --git a/examples/struct.casm b/test/struct.casm similarity index 100% rename from examples/struct.casm rename to test/struct.casm diff --git a/test/struct.txt b/test/struct.txt new file mode 100644 index 0000000..e69de29 diff --git a/examples/syscall.casm.exclude b/test/syscall.casm.exclude similarity index 100% rename from examples/syscall.casm.exclude rename to test/syscall.casm.exclude