Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ec4a2c23d7 | |||
| 33cb2782ac | |||
|
ed6f463897
|
|||
|
d5647758d0
|
|||
|
1a7226eef1
|
|||
|
4bfcf72240
|
|||
|
6ba8a59c5e
|
|||
|
bb2d896e4b
|
|||
|
3183908012
|
|||
|
ed99d38534
|
|||
|
36fa1285b4
|
|||
|
8ef0b253b2
|
|||
|
61e08812e3
|
|||
|
a0ac978541
|
|||
|
f9742ed5a5
|
|||
|
350deb3a45
|
|||
|
8a02674af5
|
@@ -17,7 +17,7 @@ jobs:
|
|||||||
# Not recursive, deliberately. The top-level build needs
|
# Not recursive, deliberately. The top-level build needs
|
||||||
# deps/libakerror and deps/libakstdlib, via add_subdirectory, and
|
# deps/libakerror and deps/libakstdlib, via add_subdirectory, and
|
||||||
# nothing else: the golden corpus and the Commodore font now live in
|
# nothing else: the golden corpus and the Commodore font now live in
|
||||||
# this repository (tests/reference/ and assets/fonts/), so
|
# this repository (tests/language/ and assets/fonts/), so
|
||||||
# deps/basicinterpret is no longer a build dependency at all.
|
# deps/basicinterpret is no longer a build dependency at all.
|
||||||
# It does *not* need deps/libakgl, which is guarded behind
|
# It does *not* need deps/libakgl, which is guarded behind
|
||||||
# AKBASIC_WITH_AKGL and defaults OFF -- and recursing into it would
|
# AKBASIC_WITH_AKGL and defaults OFF -- and recursing into it would
|
||||||
@@ -62,11 +62,9 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cmake -S . -B build
|
cmake -S . -B build
|
||||||
cmake --build build --parallel 2
|
cmake --build build --parallel 2
|
||||||
# The suite is 78 cases: 41 golden files byte-compared against the Go
|
# The suite is 112 cases: 65 language files with sibling expectations,
|
||||||
# reference's own corpus (checked in at tests/reference/, see its README),
|
# 43 unit tests, 3 embedding examples, and docs_examples.
|
||||||
# 9 local golden cases for verbs the reference never implemented, 25 unit
|
# Some unit tests assert the *correct* contract for known defects (TODO.md
|
||||||
# tests, 2 embedding examples, and 1 known-failing test that asserts the
|
|
||||||
# *correct* contract for defects carried over from the reference (TODO.md
|
|
||||||
# section 6). A green run therefore does not mean defect-free -- see
|
# section 6). A green run therefore does not mean defect-free -- see
|
||||||
# AKBASIC_KNOWN_FAILING_TESTS.
|
# AKBASIC_KNOWN_FAILING_TESTS.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ scripting engine for game authors.
|
|||||||
| [the issue tracker](https://source.starfort.tech/andrew/akbasic/issues) | **Outstanding defects and gaps.** Labelled by kind and blast radius; `status::grooming` means the scope is not settled yet |
|
| [the issue tracker](https://source.starfort.tech/andrew/akbasic/issues) | **Outstanding defects and gaps.** Labelled by kind and blast radius; `status::grooming` means the scope is not settled yet |
|
||||||
| [`TODO.md`](TODO.md) | The record: settled design decisions, the deviation register, defects already fixed, and the reasoning behind the measurements. §0.1 first — it retires the byte-for-byte fidelity constraint several later sections were written on |
|
| [`TODO.md`](TODO.md) | The record: settled design decisions, the deviation register, defects already fixed, and the reasoning behind the measurements. §0.1 first — it retires the byte-for-byte fidelity constraint several later sections were written on |
|
||||||
| [`README.md`](README.md) | What the project is and why, for somebody who has not seen it |
|
| [`README.md`](README.md) | What the project is and why, for somebody who has not seen it |
|
||||||
| [`docs/`](docs/README.md) | The language itself: eighteen chapters, verb and function reference. [Chapter 14](docs/14-architecture.md) is the interpreter's architecture — the step loop, the pools, the two kinds of error, and how to debug it. [Chapter 15](docs/15-error-codes.md) is the error-code appendix. [Chapters 17](docs/17-tutorial-breakout.md) and [18](docs/18-tutorial-breakout-artwork.md) are tutorials that build the games in `examples/breakout/` |
|
| [`docs/`](docs/README.md) | The language itself: twenty-one chapters, verb and function reference. [Chapter 14](docs/14-architecture.md) is the interpreter's architecture — the step loop, the pools, the two kinds of error, and how to debug it. [Chapter 15](docs/15-error-codes.md) is the error-code appendix. [Chapters 17](docs/17-tutorial-breakout.md) and [18](docs/18-tutorial-breakout-artwork.md) are tutorials that build the games in `examples/breakout/`; [Chapters 20](docs/20-tutorial-galaga.md) and [21](docs/21-tutorial-galaga-enemies.md) build the embedding host in `examples/galaga/` |
|
||||||
| `deps/libakerror/AGENTS.md` | The `ATTEMPT`/`CLEANUP`/`PROCESS`/`HANDLE`/`FINISH` protocol, authoritatively |
|
| `deps/libakerror/AGENTS.md` | The `ATTEMPT`/`CLEANUP`/`PROCESS`/`HANDLE`/`FINISH` protocol, authoritatively |
|
||||||
| `deps/libakerror/UPGRADING.md` | 1.0.0's status registry. Required before writing an error code |
|
| `deps/libakerror/UPGRADING.md` | 1.0.0's status registry. Required before writing an error code |
|
||||||
| `deps/<library>/AGENTS.md` | Per-repo rules. Read the relevant one **before editing a submodule** |
|
| `deps/<library>/AGENTS.md` | Per-repo rules. Read the relevant one **before editing a submodule** |
|
||||||
@@ -57,9 +57,9 @@ repeating where you will see them:
|
|||||||
`include/akgl/SDL_GameControllerDB.h`. Change the template or the generator script.
|
`include/akgl/SDL_GameControllerDB.h`. Change the template or the generator script.
|
||||||
- **Do not reformat code you are not otherwise changing.** Several files mix tabs and spaces
|
- **Do not reformat code you are not otherwise changing.** Several files mix tabs and spaces
|
||||||
and there is no repo-wide formatter; style conversions get their own commit.
|
and there is no repo-wide formatter; style conversions get their own commit.
|
||||||
- **Do not edit `tests/reference/`.** Those expectations came from the Go implementation and
|
- **Keep `tests/language/` editable.** Its `.bas` programs and sibling `.txt` expectations
|
||||||
are never edited to suit this interpreter. A deliberate divergence goes in
|
are changed together when behavior changes. Record deliberate language decisions in
|
||||||
`tests/reference/README.md`'s divergence table and `docs/13-differences.md`.
|
`TODO.md` or `docs/13-differences.md`.
|
||||||
- **Open an issue for outstanding work; do not add it to `TODO.md`.**
|
- **Open an issue for outstanding work; do not add it to `TODO.md`.**
|
||||||
<https://source.starfort.tech/andrew/akbasic/issues>, or `tea issues create --repo
|
<https://source.starfort.tech/andrew/akbasic/issues>, or `tea issues create --repo
|
||||||
andrew/akbasic`. Name the file and line, the functional consequence, and what closing it would
|
andrew/akbasic`. Name the file and line, the functional consequence, and what closing it would
|
||||||
|
|||||||
128
CMakeLists.txt
128
CMakeLists.txt
@@ -268,6 +268,69 @@ if(AKBASIC_BUILD_EXAMPLES)
|
|||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# The galaga example: a C game on libakgl with the interpreter embedded as its
|
||||||
|
# enemy-behavior engine. Chapters 20 and 21 build it from an empty file, so it
|
||||||
|
# is compiled and run by every AKGL build rather than rotting in a document.
|
||||||
|
# The asset, script and font paths are baked in so the smoke test can launch
|
||||||
|
# from any working directory; --assets and --script override them at runtime.
|
||||||
|
if(AKBASIC_BUILD_EXAMPLES AND AKBASIC_WITH_AKGL)
|
||||||
|
add_executable(akbasic_example_galaga
|
||||||
|
examples/galaga/main.c
|
||||||
|
examples/galaga/script.c
|
||||||
|
examples/galaga/enemies.c
|
||||||
|
examples/galaga/player.c)
|
||||||
|
target_compile_options(akbasic_example_galaga PRIVATE -Wall -Wextra)
|
||||||
|
target_compile_definitions(akbasic_example_galaga PRIVATE
|
||||||
|
GALAGA_ASSET_DIR="${CMAKE_CURRENT_SOURCE_DIR}/examples/galaga/assets"
|
||||||
|
GALAGA_SCRIPT_PATH="${CMAKE_CURRENT_SOURCE_DIR}/examples/galaga/galaga.bas"
|
||||||
|
GALAGA_FONT_PATH="${CMAKE_CURRENT_SOURCE_DIR}/assets/fonts/C64_Pro_Mono-STYLE.ttf")
|
||||||
|
target_link_libraries(akbasic_example_galaga PRIVATE akbasic akgl
|
||||||
|
SDL3::SDL3 SDL3_ttf::SDL3_ttf SDL3_image::SDL3_image)
|
||||||
|
akbasic_instrument(akbasic_example_galaga)
|
||||||
|
# Ten seconds of scripted play under the headless drivers: the script boots,
|
||||||
|
# a wave enters and forms, the autoplay pilot shoots at it, and the program
|
||||||
|
# tears down and exits 0. A tutorial that stops working fails here rather
|
||||||
|
# than in front of a reader.
|
||||||
|
_add_test(NAME example_galaga COMMAND akbasic_example_galaga --frames 600 --autoplay)
|
||||||
|
_set_tests_properties(example_galaga PROPERTIES TIMEOUT 120
|
||||||
|
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_AUDIODRIVER=dummy;SDL_RENDER_DRIVER=software")
|
||||||
|
|
||||||
|
# The boundary's round-trip test: links the real script.c and the real
|
||||||
|
# galaga.bas, and fails the moment the two sides of the interop disagree.
|
||||||
|
add_executable(akbasic_example_galaga_interop
|
||||||
|
examples/galaga/interop_test.c
|
||||||
|
examples/galaga/script.c)
|
||||||
|
target_compile_options(akbasic_example_galaga_interop PRIVATE -Wall -Wextra)
|
||||||
|
target_compile_definitions(akbasic_example_galaga_interop PRIVATE
|
||||||
|
GALAGA_SCRIPT_PATH="${CMAKE_CURRENT_SOURCE_DIR}/examples/galaga/galaga.bas")
|
||||||
|
target_link_libraries(akbasic_example_galaga_interop PRIVATE akbasic akgl
|
||||||
|
SDL3::SDL3 m)
|
||||||
|
akbasic_instrument(akbasic_example_galaga_interop)
|
||||||
|
_add_test(NAME example_galaga_interop COMMAND akbasic_example_galaga_interop)
|
||||||
|
_set_tests_properties(example_galaga_interop PROPERTIES TIMEOUT 120)
|
||||||
|
|
||||||
|
# Regenerating the game figures in docs/ is a deliberate act, never part of
|
||||||
|
# a build, for the same reason docs_screenshots is: the PNGs are checked in.
|
||||||
|
# Wall-clock dt makes each regeneration differ by a few pixels of starfield,
|
||||||
|
# so expect a binary diff every time this runs; commit one only when the
|
||||||
|
# content changed on purpose. (docs_galaga_figures, not docs_game_figures:
|
||||||
|
# the libakgl submodule already owns that target name.)
|
||||||
|
add_custom_target(docs_galaga_figures
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E env SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy
|
||||||
|
SDL_RENDER_DRIVER=software
|
||||||
|
$<TARGET_FILE:akbasic_example_galaga> --frames 40
|
||||||
|
--screenshot "${CMAKE_CURRENT_SOURCE_DIR}/docs/images/galaga-title.png"
|
||||||
|
--screenshot-frame 30
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E env SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy
|
||||||
|
SDL_RENDER_DRIVER=software
|
||||||
|
$<TARGET_FILE:akbasic_example_galaga> --autoplay --frames 370
|
||||||
|
--screenshot "${CMAKE_CURRENT_SOURCE_DIR}/docs/images/galaga-wave.png"
|
||||||
|
--screenshot-frame 360
|
||||||
|
DEPENDS akbasic_example_galaga
|
||||||
|
COMMENT "Regenerating the galaga figures in docs/images"
|
||||||
|
VERBATIM)
|
||||||
|
endif()
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Tests.
|
# Tests.
|
||||||
#
|
#
|
||||||
@@ -448,7 +511,7 @@ if(AKBASIC_WITH_AKGL)
|
|||||||
# against.
|
# against.
|
||||||
#
|
#
|
||||||
# **A byte comparison of a rendered PNG is a deliberate bet**, the same bet
|
# **A byte comparison of a rendered PNG is a deliberate bet**, the same bet
|
||||||
# tests/reference/ already makes about golden output: that the dummy video
|
# the language corpus makes about golden output: that the dummy video
|
||||||
# driver and the software renderer are reproducible. They are, run to run and
|
# driver and the software renderer are reproducible. They are, run to run and
|
||||||
# build to build. What is untested is an SDL upgrade that shifts one pixel of
|
# build to build. What is untested is an SDL upgrade that shifts one pixel of
|
||||||
# a diagonal, and the answer to that is to regenerate the figures in the same
|
# a diagonal, and the answer to that is to regenerate the figures in the same
|
||||||
@@ -531,63 +594,20 @@ if(AKBASIC_WILL_FAIL_TESTS OR AKBASIC_KNOWN_FAILING_TESTS)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# The reference's own corpus, byte-compared against the sibling .txt. One CTest
|
# The editable language corpus. One CTest case per .bas so a failure names the
|
||||||
# case per .bas so a failure names the file.
|
# file. Each program is paired with a sibling .txt expectation; see
|
||||||
|
# tests/language/README.md for the editing rule.
|
||||||
#
|
#
|
||||||
# It used to be driven in place out of deps/basicinterpret, on the reasoning that
|
# The corpus includes programs carried over from the deprecated Go implementation
|
||||||
# copying a submodule's corpus guarantees drift. That reasoning was sound and it
|
# and cases written for this interpreter. Their provenance is useful when
|
||||||
# has been overruled deliberately: the Go dependency is being deprecated, and a
|
# investigating a regression, but it does not make any case immutable.
|
||||||
# build that cannot run its acceptance suite without cloning the implementation
|
|
||||||
# it replaced is not finished. The copy is byte-identical to
|
|
||||||
# basicinterpreter@d76162c and tests/reference/README.md records
|
|
||||||
# where it came from and what the drift now costs.
|
|
||||||
file(GLOB_RECURSE AKBASIC_GOLDEN_CASES
|
|
||||||
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/tests/reference"
|
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/reference/*.bas"
|
|
||||||
)
|
|
||||||
|
|
||||||
foreach(_case IN LISTS AKBASIC_GOLDEN_CASES)
|
|
||||||
string(REGEX REPLACE "^tests/" "" _name "${_case}")
|
|
||||||
string(REGEX REPLACE "\\.bas$" "" _name "${_name}")
|
|
||||||
string(REPLACE "/" "_" _name "${_name}")
|
|
||||||
_add_test(
|
|
||||||
NAME golden_${_name}
|
|
||||||
COMMAND ${CMAKE_COMMAND}
|
|
||||||
-DBASIC=$<TARGET_FILE:basic>
|
|
||||||
-DCASE=${CMAKE_CURRENT_SOURCE_DIR}/tests/reference/${_case}
|
|
||||||
-P ${CMAKE_CURRENT_SOURCE_DIR}/tests/golden.cmake
|
|
||||||
)
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
if(AKBASIC_GOLDEN_CASES)
|
|
||||||
set(AKBASIC_GOLDEN_NAMES)
|
|
||||||
foreach(_case IN LISTS AKBASIC_GOLDEN_CASES)
|
|
||||||
string(REGEX REPLACE "^tests/" "" _name "${_case}")
|
|
||||||
string(REGEX REPLACE "\\.bas$" "" _name "${_name}")
|
|
||||||
string(REPLACE "/" "_" _name "${_name}")
|
|
||||||
list(APPEND AKBASIC_GOLDEN_NAMES golden_${_name})
|
|||||||