cleanup main parse loop... still needs work

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-08-01 20:31:12 +03:00
parent dd74fb1444
commit 74ae4ffd1c

100
argv.js
View File

@ -907,6 +907,7 @@ object.Constructor('Parser', {
script.length - parsed.scriptName.length) script.length - parsed.scriptName.length)
// helpers... // helpers...
// XXX should this pass the error as-is to the API???
var handleError = function(reason, arg, rest){ var handleError = function(reason, arg, rest){
arg = arg || reason.arg arg = arg || reason.arg
rest = rest || reason.rest rest = rest || reason.rest
@ -953,7 +954,7 @@ object.Constructor('Parser', {
// nested parsers... // nested parsers...
res === module.STOP res === module.STOP
&& parsed.stop(arg, rest) && parsed.stop(arg, rest)
// XXX revise -- do we need to re-handle errors??? // handle passive/returned errors...
res instanceof module.ParserError res instanceof module.ParserError
&& handleError(res, arg, rest) && handleError(res, arg, rest)
return res } return res }
@ -978,27 +979,35 @@ object.Constructor('Parser', {
try{ try{
// parse/interpret the arguments and call handlers... // parse/interpret the arguments and call handlers...
var values = new Set() var values = new Map(
parsed.optionsWithValue()
.map(function([k, a, d, handler]){
return [handler, k[0]] }))
var seen = new Set() var seen = new Set()
var unhandled = parsed.unhandled = [] var unhandled = parsed.unhandled = []
while(rest.length > 0){ while(rest.length > 0 || (values.size || values.length) > 0){
var arg = rest.shift() // explicitly passed options...
// non-string stuff in arg list... if(rest.length > 0){
if(typeof(arg) != typeof('str')){ var arg = rest.shift()
unhandled.push(arg) // non-string stuff in arg list...
continue } if(typeof(arg) != typeof('str')){
// NOTE: opts and commands do not follow the same path here unhandled.push(arg)
// because options if unidentified need to be split into continue }
// single letter options and commands to not... // options / commands...
var [type, dfl] = opt_pattern.test(arg) ? // NOTE: opts and commands do not follow the same path here
['opt', OPTION_PREFIX +'*'] // because options if unidentified need to be split into
: parsed.isCommand(arg) ? // single letter options and commands to not...
['cmd', COMMAND_PREFIX +'*'] var [type, dfl] = opt_pattern.test(arg) ?
: ['unhandled'] ['opt', OPTION_PREFIX +'*']
// options / commands... : parsed.isCommand(arg) ?
if(type != 'unhandled'){ ['cmd', COMMAND_PREFIX +'*']
: ['unhandled']
if(type == 'unhandled'){
unhandled.push(arg)
continue }
// quote '-*' / '@*'... // quote '-*' / '@*'...
arg = arg.replace(/^(.)\*$/, '$1\\*') arg = arg.replace(/^(.)\*$/, '$1\\*')
// get handler... // get handler...
var handler = parsed.handler(arg)[1] var handler = parsed.handler(arg)[1]
// handle merged options... // handle merged options...
@ -1012,39 +1021,32 @@ object.Constructor('Parser', {
if(handler == null){ if(handler == null){
throw ParserError(`Unknown ${ type == 'opt' ? 'option' : 'command:' } $ARG`, arg) } throw ParserError(`Unknown ${ type == 'opt' ? 'option' : 'command:' } $ARG`, arg) }
// mark handler... // mark/unmark handlers...
;(handler.env || 'default' in handler) values instanceof Set
&& values.add(handler) && values.delete(handler)
seen.add(handler) seen.add(handler)
var res = runHandler(handler, arg, rest) // implicit options -- with .env and or .default set...
} else {
values instanceof Map
&& console.log('>>>>>', values)
values = values instanceof Map ?
[...values]
: values
var [handler, arg] = values.shift() }
// handle stop conditions...
if(res === module.STOP var res = runHandler(handler, arg, rest)
|| res instanceof module.ParserError){
return nested ? // handle stop conditions...
res if(res === module.STOP
: parsed } || res instanceof module.ParserError){
// finish arg processing now... return nested ?
if(res === module.THEN){ res
break } : parsed }
continue } // finish arg processing now...
// unhandled... if(res === module.THEN){
unhandled.push(arg) } break } }
// call value handlers with .env or .default values that were
// not explicitly called yet...
// XXX THEN or STOP returned from runHandler(..) in here will
// not stop execution -- should it???
parsed.optionsWithValue()
.forEach(function([k, a, d, handler]){
values.has(handler)
|| (((typeof(process) != 'undefined'
&& handler.env in process.env)
|| handler.default)
&& seen.add(handler)
&& runHandler(handler,
[k[0], handler.default],
rest)) })
// check and report required options... // check and report required options...
var missing = parsed var missing = parsed
@ -1061,12 +1063,10 @@ object.Constructor('Parser', {
// re-throw the error... // re-throw the error...
if(!(err instanceof module.ParserError)){ if(!(err instanceof module.ParserError)){
throw err } throw err }
// report local errors... // report local errors...
// NOTE: non-local errors are threaded as return values... // NOTE: non-local errors are threaded as return values...
parsed.printError(err) parsed.printError(err)
handleError(err, err.arg, rest) handleError(err, err.arg, rest)
return nested ? return nested ?
err err
: parsed } : parsed }