|
|
|
@ -8,7 +8,7 @@ |
|
|
|
# (C) 2024 |
|
|
|
# (C) 2024 |
|
|
|
# |
|
|
|
# |
|
|
|
# @@ Meta Begin |
|
|
|
# @@ Meta Begin |
|
|
|
# Application punk::args 0.13.0 |
|
|
|
# Application punk::args 0.14.0 |
|
|
|
# Meta platform tcl |
|
|
|
# Meta platform tcl |
|
|
|
# Meta license <unspecified> |
|
|
|
# Meta license <unspecified> |
|
|
|
# @@ Meta End |
|
|
|
# @@ Meta End |
|
|
|
@ -18,7 +18,7 @@ |
|
|
|
# doctools header |
|
|
|
# doctools header |
|
|
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
|
|
|
# ++ +++ +++ +++ +++ +++ +++ +++ +++ +++ +++ |
|
|
|
#*** !doctools |
|
|
|
#*** !doctools |
|
|
|
#[manpage_begin punkshell_module_punk::args 0 0.13.0] |
|
|
|
#[manpage_begin punkshell_module_punk::args 0 0.14.0] |
|
|
|
#[copyright "2024"] |
|
|
|
#[copyright "2024"] |
|
|
|
#[titledesc {args parsing}] [comment {-- Name section and table of contents description --}] |
|
|
|
#[titledesc {args parsing}] [comment {-- Name section and table of contents description --}] |
|
|
|
#[moddesc {args to nested dict of opts and values}] [comment {-- Description at end of page heading --}] |
|
|
|
#[moddesc {args to nested dict of opts and values}] [comment {-- Description at end of page heading --}] |
|
|
|
@ -6528,6 +6528,31 @@ tcl::namespace::eval punk::args { |
|
|
|
punk::args::define). When -form permits several forms, the form that |
|
|
|
punk::args::define). When -form permits several forms, the form that |
|
|
|
auto-selection settled on is reported here, and a formstatus key is added |
|
|
|
auto-selection settled on is reported here, and a formstatus key is added |
|
|
|
recording each attempted form's outcome (see punk::args::parse_status). |
|
|
|
recording each attempted form's outcome (see punk::args::parse_status). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Multiform failure contract (stable, machine-readable): |
|
|
|
|
|
|
|
when a multi-form candidacy attempt matches no form, the raised error |
|
|
|
|
|
|
|
carries the errorcode |
|
|
|
|
|
|
|
PUNKARGS VALIDATION {noformmatch forms <fidlist> classes <classlist>} |
|
|
|
|
|
|
|
-formerrors <records> -argspecs <spec> |
|
|
|
|
|
|
|
where 'forms' lists the candidate form names ranked best-candidate |
|
|
|
|
|
|
|
first and 'classes' holds one suffix-viability verdict per listed |
|
|
|
|
|
|
|
form (same order) from the vocabulary: |
|
|
|
|
|
|
|
incomplete - VIABLE: every supplied word was validly consumed as |
|
|
|
|
|
|
|
a prefix of that form and parsing stopped only from |
|
|
|
|
|
|
|
exhaustion at end-of-input - appending further |
|
|
|
|
|
|
|
words can still satisfy the form |
|
|
|
|
|
|
|
invalid - NOT viable: something already supplied contradicts |
|
|
|
|
|
|
|
the form - no appended words can satisfy it |
|
|
|
|
|
|
|
-formerrors holds one record per form (same ranked order) with keys |
|
|
|
|
|
|
|
status/failureclass/badarg/message - 'status' is the same verdict. |
|
|
|
|
|
|
|
The verdict is conservative for arguments whose -type is a |
|
|
|
|
|
|
|
multi-member clause: input ending inside such a clause reports |
|
|
|
|
|
|
|
invalid even when the partial clause words match. |
|
|
|
|
|
|
|
Arguments matching several forms cleanly raise errorcode |
|
|
|
|
|
|
|
PUNKARGS VALIDATION {multipleformmatches forms <fidlist>} |
|
|
|
|
|
|
|
Consumers (form narrowing, interactive completion) should select |
|
|
|
|
|
|
|
candidate forms from these channels rather than parsing message |
|
|
|
|
|
|
|
text. |
|
|
|
} |
|
|
|
} |
|
|
|
@form -form {withid withdef} |
|
|
|
@form -form {withid withdef} |
|
|
|
@leaders -min 1 -max 1 |
|
|
|
@leaders -min 1 -max 1 |
|
|
|
@ -6934,7 +6959,10 @@ tcl::namespace::eval punk::args { |
|
|
|
} |
|
|
|
} |
|
|
|
noformmatch { |
|
|
|
noformmatch { |
|
|
|
#G-041 multi-form candidacy: payload is: forms <fids> classes <per-form statuses> |
|
|
|
#G-041 multi-form candidacy: payload is: forms <fids> classes <per-form statuses> |
|
|
|
#incomplete when some candidate form needs only more words |
|
|
|
#G-152: the classes are sound per-form suffix-viability verdicts (candidacy |
|
|
|
|
|
|
|
#confirms each 'incomplete' by a viability-mode re-parse before raising) - |
|
|
|
|
|
|
|
#overall incomplete therefore means at least one form is still satisfiable |
|
|
|
|
|
|
|
#by appending words |
|
|
|
if {"incomplete" in [Dict_getdef $payload classes {}]} { |
|
|
|
if {"incomplete" in [Dict_getdef $payload classes {}]} { |
|
|
|
return incomplete |
|
|
|
return incomplete |
|
|
|
} |
|
|
|
} |
|
|
|
@ -7176,6 +7204,10 @@ tcl::namespace::eval punk::args { |
|
|
|
#G-041: order a formfailures dict (fid -> {status .. failureclass .. badarg .. message ..}) |
|
|
|
#G-041: order a formfailures dict (fid -> {status .. failureclass .. badarg .. message ..}) |
|
|
|
#best-candidate first: literal affinity desc, then incomplete before invalid, then the |
|
|
|
#best-candidate first: literal affinity desc, then incomplete before invalid, then the |
|
|
|
#incoming (declaration) order. Returns the re-ordered dict. |
|
|
|
#incoming (declaration) order. Returns the re-ordered dict. |
|
|
|
|
|
|
|
#order a noformmatch failure's per-form records best-candidate first: leading-literal |
|
|
|
|
|
|
|
#affinity with the supplied words, then status incomplete before invalid, then |
|
|
|
|
|
|
|
#declaration order (stable sort). G-152: status is the confirmed suffix-viability |
|
|
|
|
|
|
|
#verdict, so the class tiebreak ranks still-satisfiable forms above impossible ones. |
|
|
|
proc private::rank_form_failures {argspecs rawargs formfailures} { |
|
|
|
proc private::rank_form_failures {argspecs rawargs formfailures} { |
|
|
|
set scored [list] |
|
|
|
set scored [list] |
|
|
|
dict for {fid finfo} $formfailures { |
|
|
|
dict for {fid finfo} $formfailures { |
|
|
|
@ -7676,7 +7708,14 @@ tcl::namespace::eval punk::args { |
|
|
|
failing its -type check can also surface as |
|
|
|
failing its -type check can also surface as |
|
|
|
an allocation shortfall (missingrequiredvalue) |
|
|
|
an allocation shortfall (missingrequiredvalue) |
|
|
|
- badarg and the per-argument statuses carry |
|
|
|
- badarg and the per-argument statuses carry |
|
|
|
the specifics in both situations. |
|
|
|
the specifics in both situations. For a |
|
|
|
|
|
|
|
single-form parse this is the engine failure |
|
|
|
|
|
|
|
classification, NOT a viability verdict - |
|
|
|
|
|
|
|
read formstatus for that. For a multiform |
|
|
|
|
|
|
|
noformmatch failure incomplete does carry |
|
|
|
|
|
|
|
verdict weight: it means at least one |
|
|
|
|
|
|
|
candidate form is still viable (its |
|
|
|
|
|
|
|
formstatus status is incomplete). |
|
|
|
scheme suggested display scheme: info (ok) | error (failure) |
|
|
|
scheme suggested display scheme: info (ok) | error (failure) |
|
|
|
message empty | the validation failure message |
|
|
|
message empty | the validation failure message |
|
|
|
errorcode empty | the -errorcode of the validation failure with |
|
|
|
errorcode empty | the -errorcode of the validation failure with |
|
|
|
@ -7695,14 +7734,33 @@ tcl::namespace::eval punk::args { |
|
|
|
then incomplete before invalid, then declaration |
|
|
|
then incomplete before invalid, then declaration |
|
|
|
order). |
|
|
|
order). |
|
|
|
formstatus dict keyed by candidate form name - each value a |
|
|
|
formstatus dict keyed by candidate form name - each value a |
|
|
|
dict with at least the key 'status' |
|
|
|
dict with at least the key 'status' and for failed |
|
|
|
(valid | incomplete | invalid) and for failed |
|
|
|
|
|
|
|
candidates failureclass, badarg and message. |
|
|
|
candidates failureclass, badarg and message. |
|
|
|
|
|
|
|
'status' is a per-form suffix-viability verdict |
|
|
|
|
|
|
|
(stable consumer contract): |
|
|
|
|
|
|
|
valid - the supplied words satisfy the form |
|
|
|
|
|
|
|
incomplete - VIABLE: every supplied word was |
|
|
|
|
|
|
|
validly consumed as a prefix of the |
|
|
|
|
|
|
|
form and parsing stopped only from |
|
|
|
|
|
|
|
exhaustion at end-of-input - |
|
|
|
|
|
|
|
appending further words can still |
|
|
|
|
|
|
|
satisfy the form |
|
|
|
|
|
|
|
invalid - NOT viable: something already |
|
|
|
|
|
|
|
supplied contradicts the form - no |
|
|
|
|
|
|
|
appended words can satisfy it |
|
|
|
|
|
|
|
The verdict is conservative for arguments whose |
|
|
|
|
|
|
|
-type is a multi-member clause (e.g |
|
|
|
|
|
|
|
{literal(elseif) expr script}): input ending |
|
|
|
|
|
|
|
inside such a clause reports invalid even when |
|
|
|
|
|
|
|
the partial clause words match. |
|
|
|
Single-form parses report their one form; when |
|
|
|
Single-form parses report their one form; when |
|
|
|
multi-form candidacy ran, every attempted form is |
|
|
|
multi-form candidacy ran, every attempted form is |
|
|
|
reported - partial-arglist consumers (e.g command |
|
|
|
reported - partial-arglist consumers (e.g command |
|
|
|
completion/hinting) can read per-form |
|
|
|
completion/hinting, cmdhelp form narrowing) can |
|
|
|
compatibility from this key. |
|
|
|
select the still-satisfiable form(s) from this |
|
|
|
|
|
|
|
key. The raising parse exposes the same verdicts |
|
|
|
|
|
|
|
in its noformmatch errorcode - see |
|
|
|
|
|
|
|
punk::args::parse. |
|
|
|
receivednames received argument names normalized to definition |
|
|
|
receivednames received argument names normalized to definition |
|
|
|
argument names (opt aliases folded to their |
|
|
|
argument names (opt aliases folded to their |
|
|
|
-alias|-name optionset) |
|
|
|
-alias|-name optionset) |
|
|
|
@ -7848,7 +7906,17 @@ tcl::namespace::eval punk::args { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
default { |
|
|
|
default { |
|
|
|
set formstatus [dict create $fid [dict create status $status failureclass $failureclass badarg $badarg message $r]] |
|
|
|
#G-152: formstatus statuses are suffix-viability verdicts. The overall |
|
|
|
|
|
|
|
#status above keeps the engine failure classification (it drives the |
|
|
|
|
|
|
|
#display scheme), but the per-form record must not report 'incomplete' |
|
|
|
|
|
|
|
#unless the supplied words are a valid prefix of the form - confirm by |
|
|
|
|
|
|
|
#a viability-mode re-parse exactly as multiform candidacy does. |
|
|
|
|
|
|
|
set formverdict $status |
|
|
|
|
|
|
|
if {$formverdict eq "incomplete" |
|
|
|
|
|
|
|
&& [catch {private::get_dict_form $spec_dict $fid $arglist 1}]} { |
|
|
|
|
|
|
|
set formverdict invalid |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
set formstatus [dict create $fid [dict create status $formverdict failureclass $failureclass badarg $badarg message $r]] |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
#the -argspecs payload (the whole resolved spec) is display machinery - too bulky |
|
|
|
#the -argspecs payload (the whole resolved spec) is display machinery - too bulky |
|
|
|
@ -9512,8 +9580,21 @@ tcl::namespace::eval punk::args { |
|
|
|
} |
|
|
|
} |
|
|
|
set classinfo [lindex $ecode 2] |
|
|
|
set classinfo [lindex $ecode 2] |
|
|
|
set failureclass [lindex $classinfo 0] |
|
|
|
set failureclass [lindex $classinfo 0] |
|
|
|
|
|
|
|
set formverdict [private::parse_status_classify $failureclass [lrange $classinfo 1 end]] |
|
|
|
|
|
|
|
#G-152: a per-form 'incomplete' is a suffix-viability verdict - it must hold |
|
|
|
|
|
|
|
#only when every supplied word was validly consumed as a prefix of the form |
|
|
|
|
|
|
|
#and the failure is pure exhaustion at end-of-input. The failure class alone |
|
|
|
|
|
|
|
#cannot witness that (count and missing-required classes fire before final |
|
|
|
|
|
|
|
#validation sees the consumed words), so confirm by re-parsing in viability |
|
|
|
|
|
|
|
#mode: exhaustion raises are skipped there while validation of the consumed |
|
|
|
|
|
|
|
#words still applies - a raise means something already supplied contradicts |
|
|
|
|
|
|
|
#the form. |
|
|
|
|
|
|
|
if {$formverdict eq "incomplete" |
|
|
|
|
|
|
|
&& [catch {private::get_dict_form $argspecs $fid $rawargs 1}]} { |
|
|
|
|
|
|
|
set formverdict invalid |
|
|
|
|
|
|
|
} |
|
|
|
dict set formfailures $fid [dict create\ |
|
|
|
dict set formfailures $fid [dict create\ |
|
|
|
status [private::parse_status_classify $failureclass [lrange $classinfo 1 end]]\ |
|
|
|
status $formverdict\ |
|
|
|
failureclass $failureclass\ |
|
|
|
failureclass $failureclass\ |
|
|
|
badarg [Dict_getdef [lrange $ecode 3 end] -badarg ""]\ |
|
|
|
badarg [Dict_getdef [lrange $ecode 3 end] -badarg ""]\ |
|
|
|
message [lindex [split $fresult \n] 0]\ |
|
|
|
message [lindex [split $fresult \n] 0]\ |
|
|
|
@ -9547,7 +9628,16 @@ tcl::namespace::eval punk::args { |
|
|
|
set classes [lmap finfo [dict values $formfailures] {dict get $finfo status}] |
|
|
|
set classes [lmap finfo [dict values $formfailures] {dict get $finfo status}] |
|
|
|
set msg "Bad arguments for %caller%. No form of the command matches the supplied arguments. Candidate forms: $candidate_fids" |
|
|
|
set msg "Bad arguments for %caller%. No form of the command matches the supplied arguments. Candidate forms: $candidate_fids" |
|
|
|
dict for {fid finfo} $formfailures { |
|
|
|
dict for {fid finfo} $formfailures { |
|
|
|
append msg \n " form '$fid': [dict get $finfo message]" |
|
|
|
#G-152: visibly distinguish forms still satisfiable by appending words |
|
|
|
|
|
|
|
#(status incomplete - the confirmed suffix-viability verdict) from |
|
|
|
|
|
|
|
#forms nothing appended can satisfy. Keep the "form '<fid>':" prefix |
|
|
|
|
|
|
|
#intact - consumers/tests anchor on it. |
|
|
|
|
|
|
|
if {[dict get $finfo status] eq "incomplete"} { |
|
|
|
|
|
|
|
set verdicttag "(viable - needs more arguments)" |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
set verdicttag "(not viable)" |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
append msg \n " form '$fid': $verdicttag [dict get $finfo message]" |
|
|
|
} |
|
|
|
} |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list noformmatch forms $candidate_fids classes $classes] -argspecs $argspecs -formerrors $formfailures]] $msg |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list noformmatch forms $candidate_fids classes $classes] -argspecs $argspecs -formerrors $formfailures]] $msg |
|
|
|
} |
|
|
|
} |
|
|
|
@ -9562,7 +9652,23 @@ tcl::namespace::eval punk::args { |
|
|
|
#body, extracted verbatim from get_dict when multi-form candidacy landed (G-041). |
|
|
|
#body, extracted verbatim from get_dict when multi-form candidacy landed (G-041). |
|
|
|
#argspecs is a RESOLVED spec dict (get_dict resolves the deflist in its caller's |
|
|
|
#argspecs is a RESOLVED spec dict (get_dict resolves the deflist in its caller's |
|
|
|
#context before selecting forms - nothing here touches the caller's frame). |
|
|
|
#context before selecting forms - nothing here touches the caller's frame). |
|
|
|
proc private::get_dict_form {argspecs fid rawargs} { |
|
|
|
# |
|
|
|
|
|
|
|
#viabilitycheck (G-152): when 1, run as a suffix-viability probe - the question |
|
|
|
|
|
|
|
#answered is not "do these arguments satisfy the form" but "are these arguments a |
|
|
|
|
|
|
|
#valid PREFIX of the form" (could appending further words still satisfy it). The |
|
|
|
|
|
|
|
#probe suppresses exactly the raises that represent pure exhaustion at |
|
|
|
|
|
|
|
#end-of-input (below-minimum count checks and missing-required checks, each |
|
|
|
|
|
|
|
#guarded by position conditions ensuring appended words could actually reach the |
|
|
|
|
|
|
|
#missing element, and an option's value lying beyond the supplied words) and lets |
|
|
|
|
|
|
|
#every other raise stand - including the final validation of the words actually |
|
|
|
|
|
|
|
#consumed, which is the soundness backstop: a probe raise means something already |
|
|
|
|
|
|
|
#supplied contradicts the form. Callers only test raised-vs-returned; the |
|
|
|
|
|
|
|
#returned dict of a probe run is partial and must be discarded. |
|
|
|
|
|
|
|
#Known conservatism (documented in the parse/parse_status contracts): input |
|
|
|
|
|
|
|
#ending INSIDE a multi-member type clause raises (clause allocation cannot |
|
|
|
|
|
|
|
#affirm the partial words) - such prefixes report non-viable even when the |
|
|
|
|
|
|
|
#partial clause words match. |
|
|
|
|
|
|
|
proc private::get_dict_form {argspecs fid rawargs {viabilitycheck 0}} { |
|
|
|
#puts "-arg_info->$arg_info" |
|
|
|
#puts "-arg_info->$arg_info" |
|
|
|
set flagsreceived [list] ;#for checking if required flags satisfied |
|
|
|
set flagsreceived [list] ;#for checking if required flags satisfied |
|
|
|
set solosreceived [list] |
|
|
|
set solosreceived [list] |
|
|
|
@ -10564,6 +10670,15 @@ tcl::namespace::eval punk::args { |
|
|
|
tcl::dict::set arg_checks $a $OPT_CHECKS_DEFAULTS |
|
|
|
tcl::dict::set arg_checks $a $OPT_CHECKS_DEFAULTS |
|
|
|
#assert -type value has llength 1 (multitype clauses not allowed for opts) |
|
|
|
#assert -type value has llength 1 (multitype clauses not allowed for opts) |
|
|
|
if {[tcl::dict::get $argstate $a -type] ne "none"} { |
|
|
|
if {[tcl::dict::get $argstate $a -type] ne "none"} { |
|
|
|
|
|
|
|
if {$viabilitycheck && $i == $maxidx} { |
|
|
|
|
|
|
|
#G-152 viability probe: the adhoc option's value lies beyond |
|
|
|
|
|
|
|
#the supplied words - pure end-of-input exhaustion. End the |
|
|
|
|
|
|
|
#opts scan; the unfinished flag stays unassigned (required |
|
|
|
|
|
|
|
#checks are position-guarded in probe mode). |
|
|
|
|
|
|
|
set arglist [lrange $remaining_rawargs 0 $i-1] |
|
|
|
|
|
|
|
set post_values {} |
|
|
|
|
|
|
|
break |
|
|
|
|
|
|
|
} |
|
|
|
if {[tcl::dict::get $argstate $a -multiple]} { |
|
|
|
if {[tcl::dict::get $argstate $a -multiple]} { |
|
|
|
tcl::dict::lappend opts $a $flagval |
|
|
|
tcl::dict::lappend opts $a $flagval |
|
|
|
if {$a ni $multisreceived} { |
|
|
|
if {$a ni $multisreceived} { |
|
|
|
@ -11172,14 +11287,29 @@ tcl::namespace::eval punk::args { |
|
|
|
} |
|
|
|
} |
|
|
|
#----------------------------------------------------- |
|
|
|
#----------------------------------------------------- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#G-152 viability probe: a below-minimum count is pure end-of-input exhaustion - |
|
|
|
|
|
|
|
#satisfiable by appending words - only while the parse position can still reach |
|
|
|
|
|
|
|
#that section: the leaders section only when nothing was consumed beyond it (no |
|
|
|
|
|
|
|
#option words, no value words - appended words land after those and cannot fill |
|
|
|
|
|
|
|
#a leader); the trailing values always (values end the argument list and the |
|
|
|
|
|
|
|
#loops above consumed every supplied word). The probe skips those raises so |
|
|
|
|
|
|
|
#final validation can pass verdict on the words actually consumed. |
|
|
|
|
|
|
|
#Above-maximum counts are contradictions in any mode. |
|
|
|
|
|
|
|
if {$viabilitycheck} { |
|
|
|
|
|
|
|
set skip_leadershortfall [expr {![llength $flagsreceived] && ![llength $values]}] |
|
|
|
|
|
|
|
set skip_valueshortfall 1 |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
set skip_leadershortfall 0 |
|
|
|
|
|
|
|
set skip_valueshortfall 0 |
|
|
|
|
|
|
|
} |
|
|
|
if {$leadermax == -1} { |
|
|
|
if {$leadermax == -1} { |
|
|
|
#only check min |
|
|
|
#only check min |
|
|
|
if {$num_leaders < $leadermin} { |
|
|
|
if {$num_leaders < $leadermin && !$skip_leadershortfall} { |
|
|
|
set msg "Bad number of leading values for %caller%. Got $num_leaders leaders. Expected at least $leadermin" |
|
|
|
set msg "Bad number of leading values for %caller%. Got $num_leaders leaders. Expected at least $leadermin" |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list leadingvaluecount $num_leaders min $leadermin max $leadermax] -argspecs $argspecs]] $msg |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list leadingvaluecount $num_leaders min $leadermin max $leadermax] -argspecs $argspecs]] $msg |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if {$num_leaders < $leadermin || $num_leaders > $leadermax} { |
|
|
|
if {($num_leaders < $leadermin && !$skip_leadershortfall) || $num_leaders > $leadermax} { |
|
|
|
if {$leadermin == $leadermax} { |
|
|
|
if {$leadermin == $leadermax} { |
|
|
|
set msg "Bad number of leading values for %caller%. Got $num_leaders leaders. Expected exactly $leadermin" |
|
|
|
set msg "Bad number of leading values for %caller%. Got $num_leaders leaders. Expected exactly $leadermin" |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list leadingvaluecount $num_leaders min $leadermin max $leadermax] -argspecs $argspecs]] $msg |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list leadingvaluecount $num_leaders min $leadermin max $leadermax] -argspecs $argspecs]] $msg |
|
|
|
@ -11192,12 +11322,12 @@ tcl::namespace::eval punk::args { |
|
|
|
|
|
|
|
|
|
|
|
if {$valmax == -1} { |
|
|
|
if {$valmax == -1} { |
|
|
|
#only check min |
|
|
|
#only check min |
|
|
|
if {$num_values < $valmin} { |
|
|
|
if {$num_values < $valmin && !$skip_valueshortfall} { |
|
|
|
set msg "Bad number of trailing values for %caller%. Got $num_values values. Expected at least $valmin" |
|
|
|
set msg "Bad number of trailing values for %caller%. Got $num_values values. Expected at least $valmin" |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list trailingvaluecount $num_values min $valmin max $valmax] -argspecs $argspecs]] $msg |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list trailingvaluecount $num_values min $valmin max $valmax] -argspecs $argspecs]] $msg |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
if {$num_values < $valmin || $num_values > $valmax} { |
|
|
|
if {($num_values < $valmin && !$skip_valueshortfall) || $num_values > $valmax} { |
|
|
|
if {$valmin == $valmax} { |
|
|
|
if {$valmin == $valmax} { |
|
|
|
set msg "Bad number of trailing values for %caller%. Got $num_values values. Expected exactly $valmin" |
|
|
|
set msg "Bad number of trailing values for %caller%. Got $num_values values. Expected exactly $valmin" |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list trailingvaluecount $num_values min $valmin max $valmax] -argspecs $argspecs]] $msg |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list trailingvaluecount $num_values min $valmin max $valmax] -argspecs $argspecs]] $msg |
|
|
|
@ -11230,14 +11360,30 @@ tcl::namespace::eval punk::args { |
|
|
|
# error "Required value missing for [Get_caller]. missing values $missing marked with -optional false - so must be present" |
|
|
|
# error "Required value missing for [Get_caller]. missing values $missing marked with -optional false - so must be present" |
|
|
|
#} |
|
|
|
#} |
|
|
|
#for now (2024-06) punk::lib::ldiff is a better compromise across normal/safe interps e.g 0.7/0.8us |
|
|
|
#for now (2024-06) punk::lib::ldiff is a better compromise across normal/safe interps e.g 0.7/0.8us |
|
|
|
if {[llength $LEADER_REQUIRED]} { |
|
|
|
#G-152 viability probe: a missing required argument is pure end-of-input |
|
|
|
|
|
|
|
#exhaustion - satisfiable by appending words - only while the parse position |
|
|
|
|
|
|
|
#can still reach its argument class: a required leader only when no option or |
|
|
|
|
|
|
|
#value words followed the leaders; a required option only while no value words |
|
|
|
|
|
|
|
#have begun and no eopts marker (--) has closed the options; a required value |
|
|
|
|
|
|
|
#always (values end the argument list). The probe skips those raises in that |
|
|
|
|
|
|
|
#situation; otherwise the absence stands as a contradiction even in probe mode. |
|
|
|
|
|
|
|
if {$viabilitycheck} { |
|
|
|
|
|
|
|
set skip_leadermissing [expr {![llength $flagsreceived] && ![llength $values]}] |
|
|
|
|
|
|
|
set skip_optionmissing [expr {![llength $values] && "--" ni $flagsreceived}] |
|
|
|
|
|
|
|
set skip_valuemissing 1 |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
set skip_leadermissing 0 |
|
|
|
|
|
|
|
set skip_optionmissing 0 |
|
|
|
|
|
|
|
set skip_valuemissing 0 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if {[llength $LEADER_REQUIRED] && !$skip_leadermissing} { |
|
|
|
if {[llength [set missing [punk::args::system::punklib_ldiff $LEADER_REQUIRED $leadernames_received]]]} { |
|
|
|
if {[llength [set missing [punk::args::system::punklib_ldiff $LEADER_REQUIRED $leadernames_received]]]} { |
|
|
|
set msg "Required leader missing for %caller%. missing values: '$missing' marked with -optional false - so must be present" |
|
|
|
set msg "Required leader missing for %caller%. missing values: '$missing' marked with -optional false - so must be present" |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list leadermissing $missing received $leadernames_received] -argspecs $argspecs]] $msg |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list leadermissing $missing received $leadernames_received] -argspecs $argspecs]] $msg |
|
|
|
#arg_error "Required leader missing for [Get_caller]. missing values: '$missing' marked with -optional false - so must be present" $argspecs |
|
|
|
#arg_error "Required leader missing for [Get_caller]. missing values: '$missing' marked with -optional false - so must be present" $argspecs |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if {[llength $OPT_REQUIRED]} { |
|
|
|
if {[llength $OPT_REQUIRED] && !$skip_optionmissing} { |
|
|
|
#broken e.g |
|
|
|
#broken e.g |
|
|
|
#punk::args::define {@id -id ::spud} @opts {-x -parsekey -coord -optional 0} {-y -parsekey -coord -optional 0} |
|
|
|
#punk::args::define {@id -id ::spud} @opts {-x -parsekey -coord -optional 0} {-y -parsekey -coord -optional 0} |
|
|
|
#error is: |
|
|
|
#error is: |
|
|
|
@ -11259,7 +11405,7 @@ tcl::namespace::eval punk::args { |
|
|
|
#arg_error "Required option missing for [Get_caller]. missing flags: '$missing' are marked with -optional false - so must be present " $argspecs |
|
|
|
#arg_error "Required option missing for [Get_caller]. missing flags: '$missing' are marked with -optional false - so must be present " $argspecs |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if {[llength $VAL_REQUIRED]} { |
|
|
|
if {[llength $VAL_REQUIRED] && !$skip_valuemissing} { |
|
|
|
if {[llength [set missing [punk::args::system::punklib_ldiff $VAL_REQUIRED $valnames_received]]]} { |
|
|
|
if {[llength [set missing [punk::args::system::punklib_ldiff $VAL_REQUIRED $valnames_received]]]} { |
|
|
|
set msg "Required value missing for %caller%. missing values: '$missing' marked with -optional false - so must be present" |
|
|
|
set msg "Required value missing for %caller%. missing values: '$missing' marked with -optional false - so must be present" |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list valuemissing $missing received $valnames_received] -argspecs $argspecs]] $msg |
|
|
|
return -options [list -code error -errorcode [list PUNKARGS VALIDATION [list valuemissing $missing received $valnames_received] -argspecs $argspecs]] $msg |
|
|
|
@ -14113,7 +14259,7 @@ package provide punk::args [tcl::namespace::eval punk::args { |
|
|
|
tcl::namespace::path {::punk::args::lib ::punk::args::system} |
|
|
|
tcl::namespace::path {::punk::args::lib ::punk::args::system} |
|
|
|
variable pkg punk::args |
|
|
|
variable pkg punk::args |
|
|
|
variable version |
|
|
|
variable version |
|
|
|
set version 0.13.0 |
|
|
|
set version 0.14.0 |
|
|
|
}] |
|
|
|
}] |
|
|
|
return |
|
|
|
return |
|
|
|
|
|
|
|
|