Skip to content

Debugger step-into, uninitialized-value errors, and misc fixes - #27

Merged
ChrisMayfield merged 16 commits into
mainfrom
manual-testing
Jul 22, 2026
Merged

Debugger step-into, uninitialized-value errors, and misc fixes#27
ChrisMayfield merged 16 commits into
mainfrom
manual-testing

Conversation

@ChrisMayfield

Copy link
Copy Markdown
Member

Summary

  • Debugger: step-into support for user function calls (useCodeDebugger, debugger.ts, VariableFrames)
  • Interpreter semantics: declared-but-unassigned variables/fields and Praxis /* ... */ placeholders now error on read instead of silently defaulting to 0/false/null — a placeholder standing alone as a statement (e.g. a missing loop-body line) is still a no-op
  • Java: require a Main class with a main method, like standard Java; add main-class unwrapping
  • Praxis: require parentheses on if/while/for headers; canonicalize assignment arrow output to
  • CSP: accept != as a not-equal operator variant
  • Comments: attach comments to top-level class/function declarations; drop headerComments, attach file-top comments to the first statement instead
  • Editor/UI: Demo toolbar button for per-language feature demos, confirm before Demo/Example replaces non-blank code, draggable Blocks translation pane, tweaked example programs
  • Misc: npm audit fix (adds a chromedriver/adm-zip override), updated demo programs, docs, and specs to match

Test plan

  • npx tsc --noEmit — clean
  • npm run test:run — 552 passed, 4 skipped
  • npm run test-browser (Selenium csv/praxly.test.csv regression suite) — 90 passed, 0 failed

🤖 Generated with Claude Code

victor-hugo-dc and others added 16 commits July 16, 2026 12:28
Emitters now generate ← instead of ASCII <- for Praxis and CSP, matching
the languages' authoritative pseudocode notation (specs already documented
this but emitted <-). Parsers still accept <- and ⟵ as input variants; CSP
additionally now accepts ⟵, mirroring what Praxis already allowed. Updated
demo programs, sample catalog entries, and the CSP CodeMirror grammar
(regenerated) to match.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The CSP grammar (highlighting) and spec already documented != as an
accepted ASCII alternate for ≠, but the actual lexer/parser never
implemented it — ! wasn't even in the lexer's recognized character set,
so it threw "Unexpected character". Wires it up to match the existing
docs.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Loads examples/demo.* for the currently selected source language via
Vite ?raw imports, reusing the same files the round-trip/examples/blocks
test suites already read, so the content isn't duplicated anywhere.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Java no longer accepts bare top-level statements as an implicit main(). The
parser now requires public class Main { public static void main(String[] args)
{ ... } }, matching real javac, so code written in Praxly compiles as-is if
copied into another Java toolchain. Also adds real `import` statement parsing
(consumed and discarded), since the emitter already emits imports that the
parser previously only tolerated via silent error recovery.

The CSP emitter gained the same "unwrap Java's Main class" logic the JS/
Python/Praxis emitters already had, since Java source can no longer produce
flat top-level statements for it to iterate directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…as errors, not defaults

A declared-but-unassigned variable or field (Java int x;, Python bare x: int,
JS let x;, Praxis bare int x) previously evaluated to a type-appropriate
default (0/false/null) instead of erroring, so reading it silently proceeded.
It's now a distinct "uninitialized" sentinel: reading, incrementing, or
compound-assigning it before a real assignment throws a runtime error,
mirroring Java's compile-time definite-assignment check (enforced dynamically
here since Praxly has no static analysis pass).

Praxis's `/* ... */` placeholder gets the same treatment for consistency:
assigning one to a variable leaves it uninitialized (error on later read), and
using one directly (e.g. `if (/* cond */)`) is an immediate error, instead of
silently defaulting to 0 and letting `if (0)` run without complaint.

Translation/emission is unaffected — emitters still lower a placeholder or a
bare declaration's synthesized default to the same output text as before; only
interpretation of that AST changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Praxis previously accepted `if`/`while`/`do-while`/`repeat-until`/`for`
headers without parentheses even though the spec always shows them,
silently parsing malformed input like `for i <- 0; i < 5; i <- i + 1`.
Missing header parens now throw a PraxisSyntaxError that bypasses the
parser's live-typing error recovery, surfacing as a real syntax error
on Run — the same way Python's UnsupportedFeatureError and Java's
JavaEntryPointError already do.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mirrors the existing language-switch confirm dialog so a full editor
isn't silently overwritten when loading a demo or example program.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…first statement

Program no longer special-cases the file-top comment block; it now travels
as the leading statement's leadingComments like any other comment run, so
emitters no longer need a separate emitProgram entry point.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…rations

ClassDeclaration/FunctionDeclaration were already in comments.ts's
ATTACHABLE set, but two things silently dropped their comments:
parsers never gave these nodes a `loc`, so attachComments had nothing
to match them against, and each emitter's visitProgram called
visitClassDeclaration/visitFunctionDeclaration directly instead of
through visitStatement, which is what actually emits leadingComments/
trailingComment.

Fixed both: every parser's top-level dispatch now tags class/function
declarations with a loc (Python's nested block-level function
declarations too), and every emitter routes top-level classes/
functions through visitStatement.

Giving ClassDeclaration/FunctionDeclaration a loc also unlocked a
latent bug in insertBlankLines, which had never previously touched
top-level blank lines between classes since they lacked loc: the
Java emitter counted those newly-inserted BlankLine nodes as "real"
main-body content and wrapped an empty synthetic `public class Main`
around them. Fixed by ignoring BlankLine nodes in that check.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ChrisMayfield
ChrisMayfield merged commit 3f8e748 into main Jul 22, 2026
1 check passed
@ChrisMayfield
ChrisMayfield deleted the manual-testing branch July 22, 2026 16:05
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.

2 participants