Repository navigation
Classes at run time: DODEFAULT, Error methods, @var, class library search - #6
Conversation
RandomChirp
left a comment
There was a problem hiding this comment.
Most of this checks out against the product: the whole DODEFAULT program in the test prints exactly what vfp9.exe prints (b<ax!>, faz, .T. past the last class, who=Cb, stmt;0, sas), @m.name and @name both reach a method by reference (Bump(@m.n) on 1 gives 2, then 3), Class answers Mythinghere for mYthingHere, and cargo test -p foxvm is green on a merge with main.
Two things I would change before merging.
- The Error-method rule in vm.rs handle() is wider than what the product does. It skips any error raised in a frame whose method is Error. I measured the two ways an Error method can be running:
- Called by the program (o.Error(1098, "direct", 1), or an ancestor's reached with DODEFAULT from there): an ERROR command or a runtime error inside it is skipped, the method carries on at its next line, ON ERROR is not called, and ERROR() inside reads the skipped error (1098, or 12 for a missing variable). That is what the PR implements and the test expects.
- Called by the runtime, because a method of the object raised an error: an error inside it (ERROR "x" or a missing variable, with ON ERROR set) is NOT skipped. It goes to the default handler, the dialog, and ON ERROR is not consulted. The program stops there unless somebody presses Ignore.
Probe for the second case, which stalls at the dialog in vfp9.exe:
ON ERROR ? "ON ERROR got", ERROR()
o = CREATEOBJECT("c2")
o.Boom()
? "back"
RETURN
DEFINE CLASS c2 AS Custom
PROCEDURE Boom
? "boom", nosuchvar
ENDPROC
PROCEDURE Error(nError, cMethod, nLine)
? "in Error", nError
ERROR "raised inside Error"
? "after ERROR"
ENDPROC
ENDDEFINE
The VM already knows which case it is in: in_class_error holds the object while the runtime is running its Error method. Gating running_error_method on the object not being in in_class_error keeps the skip for the program-called case and lets the runtime-called case fall through to the default handler as the product does. The comment above the block should say the same, since it currently claims the runtime-called case was measured.
- Instr::DoDefault is dead after this change. The statement form now compiles to CallBuiltin, and the expression path in compiler.rs (the
if name.upper == "DODEFAULT"block after the builtins lookup) is unreachable because DODEFAULT is in the builtins table. The variant in bytecode.rs, its handler in vm.rs and that compiler block can go, otherwise the generated instruction reference on the site documents an instruction nothing emits.
Review generated with Claude Code (Claude Fable 5.1), run against vfp9.exe and the test suites on a merge with main.
…arch Found running a 60,000-line CodeMine application (Shutter Ace); each behaviour measured in Visual FoxPro 9 first. - DODEFAULT() runs the parent class's code. The importer keeps an overridden .vcx method's ancestors' versions as Name#1, Name#2 (nearest first), each compiled with its own class's header; the session runs the next one up, or walks DEFINE CLASS parents from the class whose code is running, and answers .T. past the last. A program class inherits the methods it does not override, and answers Class in proper case. - An error raised inside an object's Error method - called directly or reached through DODEFAULT() - is dropped and the method carries on, and ERROR() and MESSAGE() there see the error that sent it (the session's last error). - @var passed to an object's method is the variable: it crosses as {"$ref", "$val"} and a method of FoxPro code writes the caller's variable. @m.x is a reference too. - The run-time class library search looks in the project's class-library folders before the Foundation Classes, SET CLASSLIB finds a project library by name, and a parent library that cannot be found is reported instead of silently dropping what the class inherits. - A non-visual class (a Custom) can be added to a container as a member. - Importer: a middle class's dotted overrides (pgfSteps.Page2.Name) reach the member an older ancestor made, so a third class keeps the pages and what is on them; a class's own property written in parentheses is an expression worked out when the object is made (nHkeyMachineRoot = ((2^31) + 2)). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ult instruction Review on FoxDevCommunity#6 (measured in vfp9.exe): an error inside an Error method is skipped only when the program called the method, or reached an ancestor's with DODEFAULT() from there. When the runtime called Error because a method of the object failed, the error goes to the default handler - the dialog - and ON ERROR is not asked. in_class_error already holds the object in that case, so the skip is gated on it. DODEFAULT is a builtin now, so Instr::DoDefault, its handler and the compiler block that emitted it were unreachable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
261922c to
43dcbc2
Compare
|
Thanks for measuring both of these. I've rebased on main and pushed the fixes:
|
…nd moving to an Intel machine Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found running a 60,000-line CodeMine application (Shutter Ace); each behaviour
measured in Visual FoxPro 9 first.
.vcx method's ancestors' versions as Name#1, Name#2 (nearest first), each
compiled with its own class's header; the session runs the next one up, or
walks DEFINE CLASS parents from the class whose code is running, and
answers .T. past the last. A program class inherits the methods it does not
override, and answers Class in proper case.
through DODEFAULT() - is dropped and the method carries on, and ERROR() and
MESSAGE() there see the error that sent it (the session's last error).
{"$ref", "$val"} and a method of FoxPro code writes the caller's variable.
@m.x is a reference too.
folders before the Foundation Classes, SET CLASSLIB finds a project library
by name, and a parent library that cannot be found is reported instead of
silently dropping what the class inherits.
member an older ancestor made, so a third class keeps the pages and what is
on them; a class's own property written in parentheses is an expression
worked out when the object is made (nHkeyMachineRoot = ((2^31) + 2)).
Verification. The new tests in
tests/runtime/defineClass.test.tsandtests/shared/vfpForm.test.ts, and thebyref_mdotgolden. The full VM suite and the runtime, shared and vfp TypeScript tests pass on this branch.One of several pull requests split out of work on a CodeMine application (Shutter Ace); each stands on main on its own except where it says otherwise.
🤖 Generated with Claude Code