From 4bd0ab1354acfafb9675bd17a6851b9eedee45b6 Mon Sep 17 00:00:00 2001 From: Julian Noble Date: Mon, 27 Jul 2026 00:52:07 +1000 Subject: [PATCH] argparsingtest 1.2.0: parse_args/argparse timing wrappers, plus a sandwich calling style compare's tables listed parse_args and argparse under "not loaded:" on the one runtime carrying both - bin/runtime/win32-ix86/tclsh8.6.10-luck-test2.exe (argparse 0.61, parse_args 0.5.1). Neither was missing. Both sat in optional_externals, the probe-only list whose entries can never be better than not_wrappable, and compare bucketed not_wrappable into the same footer line as not_loaded - so a package that was present and working read as absent. Timing wrappers now exist for both, and they move out of optional_externals into the style rosters under a new {optional } marker that generalises the former hardcoded argp case: loaded when the package was present at module load, not_loaded otherwise. getopt and cmdr stay probe-only. compare now reports not_wrappable separately - a "no timing wrapper:" table line, and a not_wrappable key in the dict and json forms - so the two conditions cannot be conflated again. Availability is per-runtime and the two do not travel together (surveyed 2026-07-26): the 32-bit luck-test2 kit has both, the native Tcl 9.0.3 install has argparse only, punk902z and punk91 have parse_args only, punk905 has neither. The tests constrain them separately for that reason. Style support was measured rather than assumed. argparse reaches tk style only via -mixed (its default mode rejects leading positionals as excess arguments) and its switches need an explicit -argument in the element spec or their values fall through as positionals. parse_args cannot consume leading positionals at all, so tkstyle parse_args is unsupported. Both wrappers call their library by fully qualified name: the procs deliberately share the package name, so an unqualified call would resolve to the wrapper itself - infinite recursion in argparse's case. The fourth calling style, sandwich, is 2 mandatory leading positionals, THEN the 10 keyed options, THEN 3 mandatory trailing positionals. The 2/3 split is asymmetric on purpose - an even split could be satisfied by a parser that merely halves the positional block. All three candidates support a valueless flag, so the argvec exercises -join as a solo flag alongside the -flag value pairs. Wrappers: manual_switch, punkargs, punkargs_by_id, punkargs_parsecache, opt and argparse, returning {{p1 p2} {p3 p4 p5} optsdict} - grouped rather than the flat {p1 p2 opts} of the other positional styles, because positionals now sit on both sides of the options. punk::args and opt model that arrangement - @leaders/@opts/@values are three separate sections, and tcl::OptProc fills positional slots in declaration order - and both reject options placed ahead of the leaders, as does the hand-rolled baseline. argparse reaches the style only through -mixed, which permits switches ANYWHERE, so it parses the argvec correctly without being able to enforce it: the identical spec also accepts all five positionals trailing. It is timed for the parse, not credited with expressing the constraint, and both halves of that are pinned by tests (sandwich_strictness, sandwich_argparse_is_permissive) rather than left as a silent difference. Its flag convention differs too, opts being reported in each parser's natural form: a supplied bare flag yields an empty-string value and an omitted one is absent from the dict, where the others report -join as 1 or 0. cmdline, tepam, argp and parse_args are unsupported N/A rows in this style, each verified to fail on its argvec. cmdline is the one worth naming: cmdline::getoptions returns WITHOUT error having parsed nothing at all - every option left at its default and the whole argument list untouched - so a check that only looks for a raised error would wrongly credit it. Verification: 25/25 pass under the 32-bit runtime with no skips, which is the only configuration that exercises every new test; 23 pass + 2 skip under native Tcl 9.0.3, where parse_args is absent. first_call times the new parsers in fresh child interps, confirming these binary extensions load a second time in-process. Built artifacts are not in this commit - modules/ is git-ignored. modules/ argparsingtest-1.2.0.tm was deployed via 'make.tcl modules' so the dev shell can see it: a plain 'package require argparsingtest' there resolves a deployed stable version in preference to the 999999.0a1.0 source module, so source edits are invisible until built. Claude-Session: https://claude.ai/code/session_01Q82VuBXzgeKsAwMYHrbpP1 Assisted-by: harness=claude; primary-model=claude-opus-5[1m]; api-location=anthropic.com --- src/modules/argparsingtest-999999.0a1.0.tm | 773 +++++++++++++++++- src/modules/argparsingtest-buildversion.txt | 9 +- .../argparsingtest/argparsingtest.test | 152 +++- .../argparsingtest_compare.test | 14 +- 4 files changed, 897 insertions(+), 51 deletions(-) diff --git a/src/modules/argparsingtest-999999.0a1.0.tm b/src/modules/argparsingtest-999999.0a1.0.tm index db32eaad..767ae26e 100644 --- a/src/modules/argparsingtest-999999.0a1.0.tm +++ b/src/modules/argparsingtest-999999.0a1.0.tm @@ -123,16 +123,25 @@ namespace eval argparsingtest { # title - table section heading used by compare # argvec - default timing argument vector for the style # roster - parser proc name -> marker, where marker is one of: - # always - proc unconditionally defined in argparsingtest::