Skip to content

Pass Tongues pycheck, remove in-tree transpiler and dist#410

Merged
ldayton merged 39 commits intomainfrom
tongues-pycheck
Mar 15, 2026
Merged

Pass Tongues pycheck, remove in-tree transpiler and dist#410
ldayton merged 39 commits intomainfrom
tongues-pycheck

Conversation

@ldayton
Copy link
Owner

@ldayton ldayton commented Mar 14, 2026

Summary

  • Remove transpiler/ and dist/ directories — Tongues is now installed via Homebrew
  • Remove transpiler-related justfile targets, CI references, and Claude skills
  • Fix all Tongues pycheck errors (149 → 0):
    • Replace ArithNode/CondNode Union aliases with base classes
    • Add type annotations to empty list literals
    • Change peek()/advance() from str | None to str
    • Add isinstance() narrowing for subclass attribute access
    • Fix nullable narrowing with explicit is not None checks
    • Widen covariant return types to Node | None
    • Remove dead _string_to_bytes function
  • Add just pycheck and just check-tongues (requires >= 0.2.1)
  • Raise minimum Python from 3.10 to 3.12
  • Remove fuzzer-agent and fuzzer docs/prompts

ldayton added 12 commits March 14, 2026 16:27
Workaround for Tongues not resolving type aliases used before
their definition (ldayton/Tongues#243). Converts the Union type
aliases into actual base classes that the leaf node types inherit
from, eliminating the forward-reference cycle.
- Delete transpiler/ directory (now lives in ldayton/Tongues)
- Remove src-subset, transpiler-subset, transpiler-test justfile targets
- Remove transpiler path args from backend-transpile/backend-test/backend-coverage
- Remove transpiler-related Claude skills (c-fix, idiomatize, perl-fix)
- Remove transpiler from README project structure
Backends now live in their own repositories.
…ance

- Add to_sexp() to ArithNode and CondNode base classes so Tongues
  can resolve method calls on the base type
- Change peek()/advance() return type from str | None to str,
  returning "" instead of None at end-of-input (all callers already
  guard with at_end())
- Add assert for self._parser is not None before Parser method calls
- Use isinstance() checks instead of .kind string comparisons for
  type narrowing in _format_cond_body, _starts_with_subshell,
  _format_cmdsub_node, and other dispatch sites
- Type cmdsub_parts/procsub_parts as specific list types
- Extract tuple elements to local vars for is-not-None narrowing
- Add assert for _parser before method calls
- Use explicit is not None / != "" instead of truthiness for optionals
- Add missing list type annotations
- Fix covariant return types: parse_* methods return Node | None
- Use isinstance() for type narrowing in _format_cmdsub_node
- Fix redirect list types and _format_redirect narrowing
- Fix result_parts type from tuple to str
- Widen Subshell/BraceGroup redirect types to list[Node]

Remaining 4 errors are Tongues not understanding bytearray operations.
- Delete unused _string_to_bytes function (last pycheck error)
- Add check-tongues justfile target requiring >= 0.2.1
- pycheck depends on check-tongues
@ldayton ldayton changed the title Replace ArithNode/CondNode Union aliases with base classes Pass Tongues pycheck, remove in-tree transpiler and dist Mar 14, 2026
@ldayton ldayton marked this pull request as ready for review March 14, 2026 17:02
ldayton added 16 commits March 14, 2026 19:09
- Remove default from _scan_double_quote(handle_line_continuation=True)
  (sole caller already passes explicitly)
- Remove default from parse_list(newline_as_separator=True), add True
  at all 12 bare call sites

Reduces lowering errors from 3 to 1 (remaining: bytearray.decode, Tongues#250).
Tongues subset does not allow inheriting from concrete classes.
MatchedPairError is now a standalone Exception with its own fields.
Catch sites updated to catch both (ParseError, MatchedPairError).
…able reuse

- Wrap int f-string args with str() for Tongues subset compliance
- Add assert self._parser is not None at 14 additional call sites
- Rename result -> segments in _format_cmdsub_node list branch to
  avoid variable type reuse (list[str] vs str in same function scope)
- List.to_sexp, _to_sexp_with_precedence, _to_sexp_amp_and_higher
- Pipeline.to_sexp, _cmd_sexp
- Word._collect_cmdsubs (split or-chained isinstance into separate branches)
- Word._format_command_substitutions (rename node -> cmdsub/procsub)
- Use nested ifs for Operator.op checks (workaround for pycheck bug
  with isinstance + field compare on same line)

Eliminates all 92 "cannot access field on interface Node" errors.
- ParseError/MatchedPairError: pos=X → positional
- Parser(): extglob= and in_process_sub= → positional
CondNode narrowing, find() workaround, named arg leftovers,
SavedParserState heredoc type
…arrowing)

- _parse_cond_or, _parse_cond_and, _parse_cond_term now return CondNode
- Arith parser methods stay as Node: expansions (ParamExpansion,
  CommandSubstitution, etc.) can appear inside arithmetic contexts,
  so the return type can't be narrowed to ArithNode
…irect types

- Guard CommandSubstitution(cmd) against None from parse_list()
- Restructure parse_pipeline() to narrow Node | None before prefix wrapping
- Guard Negation(inner) against None from recursive parse_pipeline()
- Annotate words: list[Word] = [] in for/select parsers

Dev pycheck: 44 → 30 (remaining 29 are ArithNode narrowing, 1 covariance)
- All Arith* node fields widened from ArithNode to Node (expansions
  like ParamExpansion appear inside arithmetic expressions)
- ArithTernary.if_true/if_false widened to Node | None (empty branches)
- ArithmeticCommand/ConditionalExpr redirects widened to list[Node]
- Guard nullable fields in to_sexp and _collect_cmdsubs

Dev pycheck: 30 → 0
…nullability

- Eliminate variable reuse in _parse_compound_command (separate var per branch)
- Fix last named arg (pos=start in MatchedPairError)
- Add assert for Token nullable return in peek_token
- Widen parse_conditional_expr return to Node | None (covariance)
ldayton added 11 commits March 15, 2026 17:52
The nested for-loop variable `cmd` inside an `elif isinstance` branch
was incorrectly flagged as "used before assignment" by the Tongues
Taytsh checker when transpiling the full file. Extracting the loop
into a helper function avoids the issue.
- Split param None/empty check so param is always str after guard
- Annotate words with explicit type to avoid redefinition ambiguity
- Use separate variable for peek_word result to avoid hoisted optional
@ldayton ldayton merged commit 448db5e into main Mar 15, 2026
1 check passed
@ldayton ldayton deleted the tongues-pycheck branch March 15, 2026 21:55
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.

1 participant