Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
dc1152b
Pages hold only the part of the nav tree that shows on opening; asset…
KubaO Oct 4, 2026
5b39949
BUGS: file lset-long-codegen-error, lset-variant-array-element-noop.
KubaO Oct 5, 2026
efaf288
Online pages hold the whole nav tree again and the online tree has no…
KubaO Oct 5, 2026
292eb54
WIP.Harness.md: a program that starts a compiler can connect to it; t…
KubaO Oct 5, 2026
6ca5717
WIP.md: the pointer to WIP.Harness.md says why the harness drives the…
KubaO Oct 5, 2026
a4f4163
Help add-in serves the documentation offline: HelpServer, a Winsock s…
KubaO Oct 5, 2026
5227956
BETA 997 fixed 14 filed bugs: verified, their reproducers removed, an…
KubaO Oct 5, 2026
b494670
Pages state what twinBASIC does now: history of earlier builds remove…
KubaO Oct 5, 2026
4efc4ec
BUGS: a [RunAfterBuild] Sub does not run, and nothing says so, when a…
KubaO Oct 5, 2026
1d888bf
Attributes.md: a WARNING on RunAfterBuild, which does not run, and no…
KubaO Oct 5, 2026
f7f11c0
#2442 fixed in BETA 997: packages lane tests a package with no Packag…
KubaO Oct 5, 2026
01a5beb
Open defect callouts name BETA 997, where every automatic reproducer …
KubaO Oct 5, 2026
e164b73
help lane: the late-bound member list is read once it has stopped cha…
KubaO Oct 5, 2026
3dbd52b
Four lane-checked defect callouts name BETA 997 (package import untic…
KubaO Oct 5, 2026
4c809d7
tbbuild reads the project container before it starts an IDE, and exit…
KubaO Oct 5, 2026
119b9a4
BUGS: two calling conventions accepted, raiseEvent TypeError, on* pro…
KubaO Oct 5, 2026
2d80be4
Boolean \ String and Mod give Boolean, as in VB6 (#2439 not a bug); V…
KubaO Oct 5, 2026
fca1f58
#2439 closed as not a bug: its reproducer folder deleted
KubaO Oct 5, 2026
396af8d
No reproducer needs a person at the IDE: bug_repro verify gains lane …
KubaO Oct 5, 2026
7549227
Concurrent harness runs share one registry put-back: the first record…
KubaO Oct 5, 2026
a9bbbb5
Build is pressed through pressBuild, which waits for the page's licen…
KubaO Oct 5, 2026
2e086fc
fast-dict-onebuf and fast-array-onebuf no longer name shims long dele…
KubaO Oct 5, 2026
dee07ae
Shim comments state their motivation without fast-dict-array, a shim …
KubaO Oct 5, 2026
15eddea
perf/README no longer lists --fast-refs, --fast-dict-iter, --fast-par…
KubaO Oct 5, 2026
ad2ca04
check_pdf_shims_equiv fails a patched member missing from its shim's …
KubaO Oct 5, 2026
1f6d504
MDIForm's BackColor stores a value that is not a colour as the other …
KubaO Oct 5, 2026
97cc667
BUGS entry and reproducer: a [RunAfterBuild] Sub does not run when it…
KubaO Oct 5, 2026
b39a373
MDIForm: the forecolor reproducer's MDIForm gets a FormDesignerId of …
KubaO Oct 5, 2026
88d4edd
tbrun refuses, exit 2 before an IDE starts, a probe whose [RunAfterBu…
KubaO Oct 5, 2026
a55f5c8
tbrun's --compiler-options reaches the project: it read values["compi…
KubaO Oct 5, 2026
dc9b566
search_quality reads its --compare file before the evaluation and ref…
KubaO Oct 5, 2026
04a6005
check_examples refuses a --port whose lanes (base + jobs - 1) would p…
KubaO Oct 5, 2026
87799b1
build_corpus refuses a --dest inside the tree it mirrors, unless the …
KubaO Oct 5, 2026
3043851
FAQ and Window > Language: the IDE ships 19 language packs in its loc…
KubaO Oct 5, 2026
f25eb6c
BETA 984/985 on 997: Checks attributes (True) override the project se…
KubaO Oct 5, 2026
db1c1d7
IUnknown and IConnectionPoint state nominal behaviour without a build…
KubaO Oct 5, 2026
d4eb981
Two silent overflow defects on 997, with reproducers and VB6 sides: L…
KubaO Oct 5, 2026
7e0a15c
Where twinBASIC and VB6 differ on Single and Double overflow, the pag…
KubaO Oct 5, 2026
06d298a
Callout rule: where twinBASIC and VB6 differ, say what VB6 does, chec…
KubaO Oct 5, 2026
3051662
BETA 997: ShiftRotateLeft, ShiftRotateRight, ShiftUnsignedRight, Byte…
KubaO Oct 6, 2026
746f570
WebView2 headers collection pages state 997's enumerator and its four…
KubaO Oct 6, 2026
4192f10
Eight defects of 997's array constants, Math intrinsics and LLVM conv…
KubaO Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ indexer/.packages/
# docs/assets/fonts/ -- only the archives are throwaway.
/.font-cache/

# The help add-in's documentation archive is built by scripts/build_help_archive.mjs
# from docs/_site-offline, and is too large to commit.
/add-in/Resources/HELP/

# A bug reproducer's zip is only for attaching to its GitHub issue (see
# BUGS-TO-REPORT.md); the .twinproj beside it is committed.
/bugs/**/*.zip
760 changes: 678 additions & 82 deletions BUGS-TO-REPORT.md

Large diffs are not rendered by default.

21 changes: 12 additions & 9 deletions WIP.ExamplesBuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,14 @@ All are forced by putting unrelated samples in one compilation unit:
- **`Sub Main` comes from the template, and a fence may bring its own as well.** Two
`Public Sub Main`s in different modules compile, so the WinServicesLib `Module Startup`
samples build as written. (A *build* adds a rule; see [`--build` and `--llvm`](#--build-and---llvm-what-a-compile-does-not-ask).)
- **A generated module must not share a name with the project.** `project.name = "ProbeWS"`
beside `Module ProbeWS` makes `[RunAfterBuild]`'s `ProbeWS.ProbeWS.Probe` ambiguous, and
the IDE refuses it at *execution* time, so the build is green and nothing runs.
- **No generated module may be named like the project, in any letter case.** With
`project.name = "ProbeWS"`, a `Module ProbeWS` or a `Module probews` stops the
`[RunAfterBuild]` Sub from running, even when it is empty and the Sub is in another module.
Nothing reports it: the build is green, and the DEBUG CONSOLE ends at `[BUILD] Executing
'<project>.<module>.<Sub>'...` (BETA 995 and 997; the BUGS-TO-REPORT.md entry with the
reproducer `bugs/module-named-like-project/`). The tool names each project `DocSamples<n>`
and every module it generates `tbx...`, so the two cannot meet; a sample that declared
`Module DocSamples3` would.

**What collides is narrower than it looks, and guessing it wide is expensive.** Two
generated modules may each declare `Public Function Foo`, `Public Type Rec` and `Public Const
Expand Down Expand Up @@ -746,12 +751,10 @@ that fails only the second is one LLVM cannot generate code for.
reads the DEBUG CONSOLE, which nothing removes an entry from, and exits 4 naming the file
the compiler died parsing. **Treat any tooling that infers "finished" from "stopped
changing" as suspect on this compiler.**
- **A two-line syntax skeleton crashes the compiler**, and it is in the corpus:
`Interface <name> Extends <base-interface>` / `End Interface`, in
`Reference/Attributes.md`. The placeholder name does it, given any `Extends` clause:
`Extends IBase` crashes it too. Recorded in [BUGS-TO-REPORT.md](BUGS-TO-REPORT.md). The
classifier refuses a `<placeholder>` as a declaration name, so it takes an explicit
`slot=` to reach the compiler with one.
- **The classifier refuses a `<placeholder>` as a declaration name**, so a syntax skeleton
such as `Interface <name> Extends <base-interface>` / `End Interface` (in
`Reference/Attributes.md`) takes an explicit `slot=` to reach the compiler. Through BETA
995 that skeleton crashed the compiler (twinbasic/twinbasic#2453, fixed in 997).
- **`project.buildPath` must be an explicit file.** The default `${SourcePath}\Build\...`
template opens a native Save dialog, which on the private desktop is invisible and
unreachable, so the build silently never happens --- and the WebView2 renderer stays
Expand Down
79 changes: 64 additions & 15 deletions WIP.Harness.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,9 +216,10 @@ other 193 are refused at every site.
one form able to pass never compiled is inconclusive, not refused, and the same holds for a
run cut short.

**It found a compiler crash the documentation never would:** a bare `[PopulateFrom]` on an
Enum kills the compiler, at all three Enum sites; the tool isolated it by halving to one
probe beside the canaries. It is in [BUGS-TO-REPORT.md](BUGS-TO-REPORT.md).
**It finds compiler crashes the documentation never would:** a crash in a batch is
isolated by halving down to one probe beside the canaries, which is how a bare
`[PopulateFrom]` on an Enum was found to kill the compiler (twinbasic/twinbasic#2450, fixed
in BETA 997).

**Read the report's "accepted at most sites" section before believing an acceptance.**
`[Description]` is taken at 53 of 61 sites and `[Hidden]` and `[Restricted]` at 42: either
Expand All @@ -245,8 +246,23 @@ override that, and one of the two is needed for an install kept anywhere else. *
path is hardcoded**, here or anywhere in the tooling: an install path contains a username.

`--json` gives the same thing as one object and `--keep` leaves the IDE running. Exit codes
are 0 clean, 1 the project has errors, 2 the harness failed, 3 the compile never settled, 4
the project crashes the compiler.
are 0 clean, 1 the project has errors, 2 the harness failed or the project file cannot be read,
3 the compile never settled, 4 the project crashes the compiler.

**A project file the IDE cannot read is refused before an IDE starts.** `tbbuild` reads the
container with impexp's reader (`checkProject`, in
[scripts/lib/tb-project.mjs](scripts/lib/tb-project.mjs)) and exits 2 within a moment,
naming the file and the fault. Without that, BETA 995 gave exit 0, a clean compile with no
rows, after the whole `--timeout` (66 s at `--timeout 60`) for an empty file, a file cut off
halfway and a file with its first byte changed, and exit 3 for a text file. The IDE answers
such a file with a message box, which nobody can see or answer on the private desktop. The
status bar never settles, and a wait that ends at its deadline is read as a compile with no
diagnostics, because `waitForCompile` does not report that it ran out of time. Only the
container is checked: a file that reads as a project and that the IDE still cannot load is
not covered. `launchOnDesktop`'s `dialogs: "close"` can record a box, but only by pressing OK
on it, `launchIde` does not ask for it, and the job it matches boxes against is absent under
`--keep`. Making `waitForCompile` say that it ran out of time would cover every such wedge,
and is not done.

**`--show` / `--hide`, and `TBBUILD_SHOW` for a whole session.** Hidden is the default. Its
cost shows only when something goes wrong: a wedged IDE on a private desktop is invisible to
Expand Down Expand Up @@ -434,27 +450,29 @@ other thirty their run.

### Why it drives the WebView rather than the compiler directly

The obvious improvement is to cut the browser out --- the compiler has websockets, so why go
through a UI at all? **It cannot be done, and the reason is structural.**
The obvious improvement is to cut the browser out: the compiler has websockets, so why go
through a UI at all? **It can be done, and the harness does not do it yet.**

The IDE is three processes, and their command lines say how they relate:

| process | command line | role |
|---|---|---|
| `twinBASIC.exe` | `<project.twinproj>` | shell; hosts the WebView2, and the only one given the project |
| `twinBASIC_win32.exe` | `--ide=<shell pid>` | serves `ide/` over HTTP on an ephemeral port |
| `twinBASIC_win32_noDEP.exe` | `--compiler=<opaque token>` | the compiler; the page talks to it over websockets |
| `twinBASIC_win32_noDEP.exe` | `--compiler=<window handle>` | the compiler; the page talks to it over websockets |

The page's websockets carry everything the window shows about a compile, the diagnostics and
their counts included.

**But what a connection needs, its address and its key, is minted inside the WebView**, by
host objects the shell gives its page --- reachable only from a page the shell has loaded.
Starting the compiler directly is no way round it either: `--compiler=` is not a port but
an opaque handle the shell hands it. So a proxy between the WebView and the HTTP server is
possible --- the page and its scripts come over plain HTTP, and a patched `main2.js` could
be served --- but it would not remove the WebView, it would only change what runs inside it.
The thing you would want to delete is the thing that mints the connection.
**The compiler chooses its own address and key, and tells the process that started it.** So
a program that starts a compiler itself can connect to it, and `--compiler=` need not name a
real window for a compile or a build (BETA 995).

What stands in the way is the work the page does over those connections. It loads the
project, gives the compiler every package the project needs, answers what the compiler asks,
and works out when a compile has finished. A client without the WebView has to do all of
that itself, in a protocol that is the IDE's own and may change with any beta, while the IDE
always speaks its own build's. So the harness drives the IDE.

Watching the page's traffic is another matter: CDP shows it to the harness with no key, and
the wait for a compile ends on it (*How the wait for the compile ends*, above). The
Expand Down Expand Up @@ -517,6 +535,19 @@ Rules it follows:

- **`element.click()` on `#buildIcon` does nothing.** It is a plain DIV behind the IDE's own
pointer handling and needs real `Input.dispatchMouseEvent` presses at its centre.
- **Build is pressed through `pressBuild` (`tb-ide.mjs`), which waits up to 60 s for the
page globals `licenceIsSet` to be true and `lockUICount` to be 0.** `tbBuild_Start` waits
only about five seconds for the compiler to answer the licence key's validation, which
`afterSocketsAreConnected` resets on every compiler connection, and then writes "[BUILD]
failed due to licence error" and builds nothing. `#appOverlay` is a transparent element
over the whole page, shown while `lockUICount` is above zero: by every modal dialog, the
"Compiling..." and project-loading progress dialogs among them, and by an open menu. A press
then fails with "its centre is covered by #appOverlay" (both were seen once each in a full
`bug_repro verify`). A licence still unset after the wait throws; an overlay still up is
left to `click`, which names it.
- **A click that fails saves a picture of the page** (`pagePicture` in `tb-click.mjs`, CDP
`Page.captureScreenshot`, which works on the private desktop) under `%TEMP%\tb-click\`, and
its error names the file.
- **Read the console's backing array, not the pane.** The DEBUG CONSOLE is a
`createListView()`, which keeps only the rows that fit in the DOM, so scraping its
`innerText` returns the *tail* of a long probe and looks exactly like a complete capture
Expand Down Expand Up @@ -763,6 +794,22 @@ variable left set in a shell would switch tidying off for good. Under `--keep` n
tidied, because the kept IDE is still writing. `shutdownIde` waits for the IDE's process to
be gone before anything is tidied, because `taskkill` only asks.

**The last of several runs puts back for all of them.** Two runs at once --- two `ide_test`,
a `tbrun` beside a lane run, another session's --- cannot each put back on their own. An IDE
holds the recent list in memory and writes all of it back when it opens a project, so a run
whose IDE is still open writes the other run's entries back after that run removed them (two
`ide_test` runs failed with exit 3 this way, each naming the other's lane folder). So the runs
share one record in `%TEMP%\tb-registry\<key>`, read and written one run at a time under its
`busy` folder: the first run to start records the recent list, the association and the theme
(`base.json`); every run adds its folders and named projects (`<pid>-<n>.json`); a run that
ends while another is running marks its record finished, puts nothing back and gets `{
deferred: [pids] }` from `finishTidy`, which the lane runner reports instead of checking the
lists; and the last run to end puts back for all, a named project from its oldest record. A
record whose process died unfinished is swept by folder when the next run starts alone, and
its record of the theme and recent list is dropped, since it may be days old.
`check_tb_registry.mjs` plays out both. `tbbuild --keep` takes no part, so its IDE can still
write the lists after the last run has put them back.

**Why .NET through PowerShell and not `reg.exe`.** Node has no registry API. `reg.exe`
prints value names in the console code page when its output is piped, so a path containing a
character outside that code page (an accented user name in `%TEMP%` is enough) comes back
Expand Down Expand Up @@ -1197,6 +1244,8 @@ leave the registry alone, and `finishTidy` once the last has ended. Then it chec
than trusts: no project-state or recent-list entry may name a lane's folder, a second sweep
of the remembered build targets must find none, and the add-ins' settings must be as
recorded. Any failure is exit code 3, which wins over a lane's failure (1): the registry is what to repair.
While another harness run is still running, the lists and targets are that run's to put back
and are not checked; the report line says which pid.

**An add-in's own settings are the runner's too.** `SaveSetting` writes under
`HKCU\Software\VB and VBA Program Settings\<app>`, the same key as any installed copy of the
Expand Down
Loading
Loading