Skip to content

Add SPC and POS print functions - #123

Merged
scottdensmore merged 1 commit into
mainfrom
scottdensmore/feat/spc-pos-functions
Aug 19, 2026
Merged

Add SPC and POS print functions#123
scottdensmore merged 1 commit into
mainfrom
scottdensmore/feat/spc-pos-functions

Conversation

@scottdensmore

Copy link
Copy Markdown
Owner

Closes #121.

Behavior

SPC( and POS( are standard Microsoft 8K BASIC functions that were not reserved words. They lexed as ordinary identifiers, which made them implicit array references that auto-dimensioned and returned 0.

Before

$ printf '10 PRINT "A";SPC(5);"B"\n20 PRINT "AB";: PRINT POS(0)\n' > /tmp/p.bas
$ ./bin/go-basic /tmp/p.bas
A0B
AB0

After

$ ./bin/go-basic /tmp/p.bas
A     B
AB2

Composed with TAB, showing POS reads the same column that TAB and the comma zones write:

$ printf '10 PRINT "COL";TAB(20);POS(0)\n' > /tmp/q.bas
$ ./bin/go-basic /tmp/q.bas
COL                 20

Design notes

  • SPC returns a print-list directive rendered as a run of spaces, mirroring how TAB already works. A=SPC(5) is therefore a type error, exactly as A=TAB(5) already was.
  • POS returns a plain number, so it works anywhere an expression is allowed, not only inside PRINT. This asymmetry is correct Microsoft behavior and is now stated in the language reference.
  • A negative SPC count is a runtime error, mirroring TAB position cannot be negative.
  • Both truncate their argument toward zero, consistent with array subscripts.
  • POS requires a numeric argument and ignores its value. Microsoft ignores it too; requiring it to be numeric keeps the no-silent-coercion rule.

Risk

No program in the pinned corpus uses SPC or POS — as a function or as a bare identifier:

grep -rnoiE '\b(SPC|POS)\b' .cache/basic-computer-games/5301155192d91d74d337899cecc59dbda59c4c17/   # 0 matches, 210 .bas files

So reserving the names changes no existing transcript. Corpus smoke still passes all 112 byte-distinct variants.

Follow-up filed, not fixed here

#122TAB(200000000) allocates 206 MB of padding, measured. That is pre-existing in TAB, and SPC deliberately mirrors it rather than introducing a one-sided guard, so both should be bounded together.

Commands run

Full CI gate, all green on the committed state:

make corpus-smoke   PASS   all 112 byte-distinct variants passed
make fmt-check      PASS
make vet            PASS
make coverage-check PASS   coverage 83.0% meets 80.0% minimum
make fuzz           PASS
make build          PASS
make release-check  PASS   VERSION=ci
make lint           PASS
make vuln           PASS

Tests added: TestLexerRecognizesSpcAndPos, TestEvaluatorEmitsSpcSpacingAndReportsPosColumn (covers SPC(n), SPC(0), POS at column 0, after a semicolon-suppressed PRINT, after a comma zone, and composed with TAB), plus negative spc, spc argument count, and pos argument count rows in TestEvaluatorReportsRuntimeErrors.

🤖 Generated with Claude Code

SPC( and POS( are standard Microsoft 8K BASIC functions that were not
reserved words, so they lexed as ordinary identifiers and became implicit
array references. PRINT "A";SPC(5);"B" auto-dimensioned an array and
printed A0B instead of emitting five spaces.

Reserve both names, parse them as call expressions, and evaluate them in
the PRINT item path alongside TAB. SPC yields a print-list directive that
renders as a run of spaces; POS returns the current output column as a
number, so it also works outside PRINT. A negative SPC count is a runtime
error, mirroring TAB.

No program in the pinned corpus uses either name as a function or a bare
identifier, so reserving them changes no existing transcript.

Closes #121

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@scottdensmore
scottdensmore merged commit 4b151c9 into main Aug 19, 2026
3 checks passed
@scottdensmore
scottdensmore deleted the scottdensmore/feat/spc-pos-functions branch August 19, 2026 05:28
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.

Reserve SPC( and POS( as 8K BASIC functions

1 participant