← board

nilpy: unit-qualified class construction

Repro

import tkinter as tk
root = tk.Tk_()                                  # a FUNCTION: works
v = tk.StringVar()                               # error: expected expression
f = tk.Frame(root, highlightthickness=0)         # error: unexpected token

Both failures reproduce with the real module name too (tkinter.StringVar()), so this is about QUALIFICATION, not about the alias.

Why

The NilPy ctor intercept in ParseFactor (parser.inc, "ClassName(args) in ANY expression position is construction") fires only when the class name is the CURRENT token and the very next token is (. With a qualifier the cursor sits on the unit name, so the whole thing falls through to the Pascal qualified-call path, which knows how to resolve a qualified PROC (that is why tk.Tk_() works) but not how to construct a class — and it certainly does not do NilPy keyword arguments.

Shape

Extend the intercept: when the tokens are ident . ident (, the first ident is not a symbol and does name a unit or alias (FindUnitOrAlias), and the second names a class type, consume the qualifier and hand off to PyClassCreate exactly as the unqualified form does. Unit scope is flat, so the class resolves by bare name once the prefix is consumed — the qualifier only has to stop being a parse error.

Why it matters

tk.Frame(...), tk.Canvas(...), tk.StringVar() are how real tkinter code is written, and songformatter's settings.py and convertrawtext.py both use the qualified spelling throughout. The façade itself is already in ([[feature-nilpy-tkinter-facade]]); this is what stands between it and the application's actual source.

Gate

make test-nilpy green with a .npy case covering a qualified ctor with and without keyword arguments, --tier quick, self-host byte-identical.

Landed (2026-07-27)

The intercept in ParseFactor grew a second form: ident . ident ( where the first ident is not a symbol and names a unit or alias (FindUnitOrAlias) and the second names a class — consume the qualifier, then the ordinary PyClassCreateExpr. Keyword arguments come along free, since it is the same construction path as the unqualified spelling.

test/test_nilpy_qualified_ctor.npy (cp.ConfigParser() through an alias, then methods on it), plus the qualified-with-kwargs form (tk.Canvas(f, background="white", width=50)) in the compile-only examples/tk/tkinter_facade.npy.