Port the standalone SDL frontend, and give the sink a line editor
An AKGL build of `basic` was a terminal program with unused SDL linked into it. It now opens the reference's 800x600 window, draws BASIC output in the Commodore font, pumps events, lets you type at it, and still mirrors every byte to stdout. The stdout mirror is a composing sink rather than a second write inside the interpreter, and lives in the core library where it needs no SDL. The line editor waits for a typed line by borrowing one frame at a time from the host, so nothing blocks and nothing owns an event loop it should not. The whole golden corpus now runs through the SDL binary as well as the stdio one, byte for byte. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -133,6 +133,7 @@ set(AKBASIC_SOURCES
|
||||
src/runtime_input.c
|
||||
src/scanner.c
|
||||
src/sink_stdio.c
|
||||
src/sink_tee.c
|
||||
src/symtab.c
|
||||
src/value.c
|
||||
src/variable.c
|
||||
@@ -170,6 +171,16 @@ if(AKBASIC_WITH_AKGL)
|
||||
target_compile_options(akbasic_akgl PRIVATE -Wall -Wextra)
|
||||
target_link_libraries(akbasic_akgl PUBLIC akbasic akgl)
|
||||
akbasic_instrument(akbasic_akgl)
|
||||
|
||||
# The SDL host, in its own target so the separation goal 3 rests on is visible
|
||||
# in the build graph and not only in a comment: akbasic is the interpreter,
|
||||
# akbasic_akgl is the adaptors that draw through somebody else's renderer, and
|
||||
# this is the one thing in the repository that creates a window. A game
|
||||
# embedding the interpreter links the first two and not this.
|
||||
add_library(akbasic_frontend src/frontend_akgl.c)
|
||||
target_compile_options(akbasic_frontend PRIVATE -Wall -Wextra)
|
||||
target_link_libraries(akbasic_frontend PUBLIC akbasic_akgl)
|
||||
akbasic_instrument(akbasic_frontend)
|
||||
endif()
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -179,8 +190,14 @@ add_executable(basic src/main.c)
|
||||
target_compile_options(basic PRIVATE -Wall -Wextra)
|
||||
target_link_libraries(basic PRIVATE akbasic)
|
||||
if(AKBASIC_WITH_AKGL)
|
||||
target_link_libraries(basic PRIVATE akbasic_akgl)
|
||||
target_compile_definitions(basic PRIVATE AKBASIC_HAVE_AKGL=1)
|
||||
target_link_libraries(basic PRIVATE akbasic_frontend)
|
||||
# The reference's own font, at the reference's own size. Its main.go opens
|
||||
# "./fonts/C64_Pro_Mono-STYLE.ttf", which only ever resolved from its own
|
||||
# source directory; compiled in, it resolves from anywhere, and AKBASIC_FONT
|
||||
# overrides it at runtime for an installed copy.
|
||||
target_compile_definitions(basic PRIVATE
|
||||
AKBASIC_HAVE_AKGL=1
|
||||
AKBASIC_FONT_PATH="${CMAKE_CURRENT_SOURCE_DIR}/deps/basicinterpret/fonts/C64_Pro_Mono-STYLE.ttf")
|
||||
endif()
|
||||
akbasic_instrument(basic)
|
||||
|
||||
@@ -229,6 +246,7 @@ set(AKBASIC_TESTS
|
||||
runtime_verbs
|
||||
scanner_tokens
|
||||
sink_stdio
|
||||
sink_tee
|
||||
symtab
|
||||
value_arithmetic
|
||||
value_bitwise
|
||||
@@ -276,6 +294,24 @@ if(AKBASIC_WITH_AKGL)
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests"
|
||||
TIMEOUT 60
|
||||
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_AUDIODRIVER=dummy")
|
||||
|
||||
# The frontend suite. Separate from the one above because it tests the *host*
|
||||
# rather than the adaptors -- it is the only test that links akbasic_frontend,
|
||||
# and the only one that opens a window and pumps events. It uses the
|
||||
# reference's own Commodore font, because proving the drawn text is in that
|
||||
# font is part of what TODO.md section 3 asks for.
|
||||
add_executable(akbasic_test_akgl_frontend tests/akgl_frontend.c)
|
||||
target_compile_options(akbasic_test_akgl_frontend PRIVATE -Wall -Wextra)
|
||||
target_link_libraries(akbasic_test_akgl_frontend PRIVATE akbasic_frontend)
|
||||
target_include_directories(akbasic_test_akgl_frontend PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/tests")
|
||||
target_compile_definitions(akbasic_test_akgl_frontend PRIVATE
|
||||
AKBASIC_TEST_C64_FONT="${CMAKE_CURRENT_SOURCE_DIR}/deps/basicinterpret/fonts/C64_Pro_Mono-STYLE.ttf")
|
||||
akbasic_instrument(akbasic_test_akgl_frontend)
|
||||
_add_test(NAME akgl_frontend COMMAND akbasic_test_akgl_frontend)
|
||||
_set_tests_properties(akgl_frontend PROPERTIES
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests"
|
||||
TIMEOUT 60
|
||||
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_AUDIODRIVER=dummy;SDL_RENDER_DRIVER=software")
|
||||
endif()
|
||||
|
||||
if(AKBASIC_TESTS OR AKBASIC_WILL_FAIL_TESTS OR AKBASIC_KNOWN_FAILING_TESTS)
|
||||
@@ -323,6 +359,13 @@ if(AKBASIC_GOLDEN_CASES)
|
||||
list(APPEND AKBASIC_GOLDEN_NAMES golden_${_name})
|
||||
endforeach()
|
||||
_set_tests_properties(${AKBASIC_GOLDEN_NAMES} PROPERTIES TIMEOUT 30)
|
||||
# An AKGL build of `basic` opens a window, and forty-one of them is not what
|
||||
# anybody running the suite wanted. The dummy driver produces the same stdout,
|
||||
# which is the only thing a golden case compares.
|
||||
if(AKBASIC_WITH_AKGL)
|
||||
_set_tests_properties(${AKBASIC_GOLDEN_NAMES} PROPERTIES
|
||||
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_AUDIODRIVER=dummy;SDL_RENDER_DRIVER=software")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# The local golden corpus, for verbs the reference never implemented.
|
||||
@@ -341,8 +384,21 @@ file(GLOB_RECURSE AKBASIC_LOCAL_CASES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/language/*.bas"
|
||||
)
|
||||
|
||||
#
|
||||
# One family of local cases is driver-specific and has to be. A case named
|
||||
# no_device.bas asserts that a verb needing a device refuses politely when it was
|
||||
# given none, which is true of the stdio driver and deliberately false of the
|
||||
# AKGL one -- attaching the three device backends is the whole point of
|
||||
# AKBASIC_WITH_AKGL, and TODO.md section 8 item 1 asks for exactly that change in
|
||||
# observable behaviour. Skipping them there is not a coverage hole: the refusal
|
||||
# path is asserted directly against the backend records in tests/devices.c, which
|
||||
# both configurations build.
|
||||
#
|
||||
set(AKBASIC_LOCAL_NAMES)
|
||||
foreach(_case IN LISTS AKBASIC_LOCAL_CASES)
|
||||
if(AKBASIC_WITH_AKGL AND _case MATCHES "no_device\\.bas$")
|
||||
continue()
|
||||
endif()
|
||||
string(REGEX REPLACE "^language/" "" _name "${_case}")
|
||||
string(REGEX REPLACE "\\.bas$" "" _name "${_name}")
|
||||
string(REPLACE "/" "_" _name "${_name}")
|
||||
@@ -358,6 +414,10 @@ endforeach()
|
||||
|
||||
if(AKBASIC_LOCAL_NAMES)
|
||||
_set_tests_properties(${AKBASIC_LOCAL_NAMES} PROPERTIES TIMEOUT 30)
|
||||
if(AKBASIC_WITH_AKGL)
|
||||
_set_tests_properties(${AKBASIC_LOCAL_NAMES} PROPERTIES
|
||||
ENVIRONMENT "SDL_VIDEODRIVER=dummy;SDL_AUDIODRIVER=dummy;SDL_RENDER_DRIVER=software")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user