Skip to content

Forth - #2947

Merged
nesbox merged 31 commits into
nesbox:mainfrom
luginf:forth
Sep 18, 2026
Merged

Forth#2947
nesbox merged 31 commits into
nesbox:mainfrom
luginf:forth

Conversation

@luginf

@luginf luginf commented May 31, 2026

Copy link
Copy Markdown
Contributor

adding Forth langages to TIC-80 (using pforth)

@luginf

luginf commented May 31, 2026 •

Copy link
Copy Markdown
Contributor Author

(made with the help of Claude code)

luginf added 6 commits May 31, 2026 18:43
pforth cell_t = uintptr_t, so the pre-compiled dictionary is
cell-size-dependent (64-bit on x86-64, 32-bit on WASM). Loading a
64-bit dictionary in a 32-bit runtime corrupts all addresses and
freezes the HTML player.

- cmake/pfdicdat_32.h: new 32-bit dictionary (generated with gcc -m32)
- cmake/forth.cmake: select pfdicdat_32.h when CMAKE_SIZEOF_VOID_P == 4
@ddelemeny

Copy link
Copy Markdown
Contributor

Note: OP had the courtesy to open a discussion (#2938) regarding the project's AI contribution policy before vibe-coding this payload.

Resolving the policy matter should probably be considered a prerequisite to reviewing this PR.

@MineRobber9000 MineRobber9000 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know enough about pforth to critique the actual implementation of the API, but there are definitely some spots in here that I am concerned about.

Comment thread cmake/forth.cmake Outdated
message(STATUS "Forth: copying bundled ${_PFORTH_DICDAT_BUNDLED} to ${PFORTH_DICDAT}")
configure_file(${_PFORTH_DICDAT_BUNDLED} ${PFORTH_DICDAT} COPYONLY)
else()
message(STATUS "Forth: pfdicdat.h not found — bootstrapping pforth to generate it...")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can use pforth to bootstrap the pfdicdat.h generation, why are we bundling a version of this data anyways? What happens if pforth updates in a way that adds more stuff to the dictionary, and now our bundled data is out of date?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MineRobber9000 that's a good question. I've initially let it generate the pfdicdat.h and pfdicdat_32.h from pforth but there was a problem with some targets (nintendo3D and rpi) do I've included those headers but it's not ideal.

It should be fixed now. I've tested the nintendo 3DS build and it's working fine.

image

Comment thread demos/forthdemo.fth Outdated
\ license: MIT License
\ script: forth
\
\ -- TIC-80 Forth API --------------------------------------------------

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You don't need to leave this API reference in the code.

Comment thread demos/forthdemo.fth Outdated
;

\ -- Demo 2 : sprite + arrow keys -------------------------------------
: demo02

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the only one you actually need to have. The others are all just clutter that a user would have to delete before starting their own game.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. I've removed all that, including the API references and additional examples. Do you think it should be better to include such informations in an additional file in the demos/ folder under a new name, or leave this to the wiki, or even somewhere else? I see in the demos folder some lua samples like fire.lua or tetris.lua so I don't know

Comment thread demos/forthdemo.fth Outdated

: BOOT
96 px ! 24 py !
S" Forth BOOT" 12 TRACE

@MineRobber9000 MineRobber9000 Jun 1, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove this, no other language does this. (EDIT: to clarify, since GH shows a seemingly random collection of lines and not the one you explicitly select in the interface, this is referring to tracing "Forth BOOT" in the BOOT callback.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok. I've just kept the BOOT procedure for initialising the variables, and kept the "demo01" word outside of the TIC loop, so people can just comment the demo and start creating new words.

Comment thread src/api/forth_io.c Outdated
@@ -0,0 +1,129 @@
// MIT License

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also go in forth.c. In general, all languages should be one C file apiece; the only exception are the Lua languages (Lua, MoonScript, Yue, and Fennel), since they all share the same plumbing underneath and only differ in how they're initialized.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it has been merged into the forth.c

luginf added 4 commits June 2, 2026 18:37
removing cmake/pfdicdat.h and cmake/pfdicdat_32.h from tree
updating cmake/forth.cmake for bootstraping pfdicdat
@luginf
luginf requested a review from MineRobber9000 June 2, 2026 19:03
@MineRobber9000

Copy link
Copy Markdown
Contributor

How did you manage to chmod +x the whole repo?

@luginf

luginf commented Jun 2, 2026 •

Copy link
Copy Markdown
Contributor Author

How did you manage to chmod +x the whole repo?

oops, long story short I needed to edit some files from another (local) account (on my computer). I can try to revert the 755 to 644 if you wish, but that will trigger a new build for nothing.

@MineRobber9000

MineRobber9000 commented Jun 3, 2026 •

Copy link
Copy Markdown
Contributor

You definitely should undo it. I can't review the PR in this state since I'd have to scroll through basically every file in the repo just to see what you actually changed.

@luginf

luginf commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

You definitely should undo it. I can't review the PR in this state since I'd have to scroll through basically every file in the repo just to see what you actually changed.

Ok, i've fixed it, I'm just working on another problem (wrong/misleading message during a stack underflow) and I'll commit that ASAP

fix "stack underflow" message
Comment thread demos/forthdemo.fth Outdated
Comment on lines +16 to +28
: demo01
0 BTN IF py @ 1- py ! THEN
1 BTN IF py @ 1+ py ! THEN
2 BTN IF px @ 1- px ! THEN
3 BTN IF px @ 1+ px ! THEN
13 CLS
1 px @ py @ 14 3 0 0 2 2 SPR
S" Hello Forth!" 84 84 15 FALSE 1 FALSE PRINT DROP
;

: TIC
demo01
;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
: demo01
0 BTN IF py @ 1- py ! THEN
1 BTN IF py @ 1+ py ! THEN
2 BTN IF px @ 1- px ! THEN
3 BTN IF px @ 1+ px ! THEN
13 CLS
1 px @ py @ 14 3 0 0 2 2 SPR
S" Hello Forth!" 84 84 15 FALSE 1 FALSE PRINT DROP
;
: TIC
demo01
;
: TIC
0 BTN IF py @ 1- py ! THEN
1 BTN IF py @ 1+ py ! THEN
2 BTN IF px @ 1- px ! THEN
3 BTN IF px @ 1+ px ! THEN
13 CLS
1 px @ py @ 14 3 0 0 2 2 SPR
S" Hello Forth!" 84 84 15 FALSE 1 FALSE PRINT DROP
;

If the user wants to write their own code, they'll probably want to just delete the whole demo code, so having it be a separate word is just clutter.

Comment thread src/api/forth.c Outdated
@MineRobber9000

Copy link
Copy Markdown
Contributor

Also, you forgot to install gcc-multilib in the Android task, which is why that build is failing.

luginf pushed a commit to luginf/TIC-80 that referenced this pull request Jun 4, 2026
- Remove references to committed cmake/pfdicdat.h and pfdicdat_32.h
  (deleted in PR nesbox#2947 forth branch)
- Document that cmake/forth.cmake now always regenerates pfdicdat.h at
  configure time via file(REMOVE) + bootstrap
- Add critical warning: a stale 32-bit dict in a 64-bit binary causes
  a silent segfault when selecting "new forth" (root cause documented)
- Update platform/cell-size matrix (WASM/3DS/RPI = 32-bit)
- Remove now-outdated manual regeneration instructions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@luginf
luginf requested a review from MineRobber9000 June 4, 2026 20:53
Comment thread src/api/forth.c Outdated
Comment thread src/api/forth.c Outdated
Comment thread assets.bat
Comment thread assets.bat
luginf and others added 5 commits June 5, 2026 08:25
Co-authored-by: minerobber <milesrobert374@gmail.com>
Co-authored-by: minerobber <milesrobert374@gmail.com>
Co-authored-by: minerobber <milesrobert374@gmail.com>
Co-authored-by: minerobber <milesrobert374@gmail.com>

@MineRobber9000 MineRobber9000 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

luginf and others added 5 commits June 22, 2026 12:32
MiniScript arrived first, so the conflicts were adjacency again: the language
list in src/script.c, the sources in core.cmake, the includes in CMakeLists,
and the submodule list, which now carries both runtimes. Both sides are kept
everywhere.
The merge left the two additions nested inside one another, which the compiler
read as an unterminated conditional. The file is main's again with the Forth
blocks beside MiniScript's, in both the extern list and the script array; a
native build of the merge links.
@nesbox

nesbox commented Sep 18, 2026

Copy link
Copy Markdown
Owner

Merged main in (MiniScript landed first). The conflicts were adjacency again: the language list in script.c, the sources in core.cmake, the includes in CMakeLists and the submodule list; both sides kept. My first pass nested the two script.c blocks inside one another and the compiler read that as an unterminated conditional — the file is main's again with the Forth blocks beside MiniScript's in both the extern list and the script array, and a native build of the merge links.\n\nOn the CI side: the release lists are not touched here either, and that is ours to grow — forth and miniscript in one pass, before the next release, as the owner asked. Your two build.yml changes look right and unrelated to languages: gcc-multilib for the nintendo host toolchain, and --parallel 3 on the macOS release job, which is that runner's core count.

@nesbox nesbox left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read the binding and the wiring. The runtime arrives as a submodule of upstream pforth, cmake/forth.cmake names the kernel sources and takes the no-IO build with TIC-80's own shim, and the script registers as forth with .fth — the release lists are ours to grow, as with MiniScript. Worth saying plainly: the tick has no time bound, so a runaway Forth loop hangs the client exactly as a runaway Lua or JS loop does; that is the house behaviour and MiniScript is the exception, not Forth the deficiency. The two build.yml changes are unrelated to languages and both check out.

@nesbox
nesbox merged commit bbf0e01 into nesbox:main Sep 18, 2026
11 checks passed
nesbox added a commit that referenced this pull request Sep 18, 2026
Why: the table lists every runtime the build carries, and the two languages
#2992 and #2947 added were simply absent from it — nothing else in the client
was told what version they are. Neither vendor keeps its version where the
older ten keep theirs, which is why this was left out of the stub-list pass:
MiniScript's is in the map its own `version` intrinsic returns
(vendor/miniscript2/generated/CoreIntrinsics.g.cpp; `hostVersion` beside it is
the embedding application's, not the runtime's) and pForth's is
PFORTH_VERSION_NAME in vendor/pforth/csrc/pf_guts.h.

The name column grows to ten characters for "miniscript", which was the one
name wider than the field — without it that row's version lands a column to
the right of every other.

Verified by running it: `tic80 --cli --cmd="help version"` prints
"forth      pForth 2.2.0" and "miniscript MiniScript 2.0" among the rest.

Co-authored-by: Claude Code <noreply@anthropic.com>
@luginf

luginf commented Sep 18, 2026

Copy link
Copy Markdown
Contributor Author

@nesbox thank you very much, and also to @MineRobber9000 for the assistance!

luginf pushed a commit to luginf/TIC-80 that referenced this pull request Sep 28, 2026
Collapses the fork's 54 commits since the upstream/main merge-base
into one. Note: the actual Forth work is already in upstream/main
(nesbox#2947, squash-merged as bbb0e012), so this commit's
real diff is small: fork-local additions that never went upstream
(CLAUDE.md project docs, .claude/skills.md, .gitignore, a
vendor/miniscript2 bump, a build/html/index.html tweak).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants