testing the limits...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2020-07-15 04:36:48 +03:00
parent 2a8f7eaf1c
commit 1e05c6eaa6
2 changed files with 129 additions and 9 deletions

36
argv.js
View File

@ -45,7 +45,7 @@ module.ERROR =
// afterCallback(name)
// -> func
//
// afterCallback(name, pre-action, post-action)
// afterCallback(name, pre_action, post_action)
// -> func
//
//
@ -53,6 +53,13 @@ module.ERROR =
// -> this
// -> res
//
// pre_action(...args)
// -> false
// -> ...
//
// post_action(...args)
// -> ...
//
var afterCallback = function(name, pre, post){
var attr = '__after_'+ name
return function(...args){
@ -179,6 +186,7 @@ var afterCallback = function(name, pre, post){
// NOTE: essentially this parser is a very basic stack language...
// XXX can we implement the whole thing directly as a stack language???
//
// XXX should a flag have more than one value???
// XXX can we add more prefixes, like '+' and the like???
// ...add prefix handlers???
// XXX should -help should work for any command?
@ -206,7 +214,8 @@ object.Constructor('Parser', {
// NOTE: we only care about differentiating an option from a command
// here by design...
optionInputPattern: /^--?(.*)$/,
commandInputPattern: /^([a-zA-Z*].*)$/,
//commandInputPattern: /^([.0-9a-zA-Z*].*)$/,
commandInputPattern: /^([^-].*)$/,
// instance stuff...
@ -303,10 +312,12 @@ object.Constructor('Parser', {
handler: function(key){
// clear arg value...
key = key.split(/=/).shift()
// option or command?
// normalize option/command name...
key = this.optionInputPattern.test(key) ?
key.replace(this.optionInputPattern, this.optionPrefix+'$1')
: key.replace(this.commandInputPattern, this.commandPrefix+'$1')
key.replace(this.optionInputPattern, this.optionPrefix+'$1')
: !key.startsWith(this.commandPrefix) ?
key.replace(this.commandInputPattern, this.commandPrefix+'$1')
: key
var seen = new Set()
while(key in this
&& typeof(this[key]) == typeof('str')){
@ -680,15 +691,20 @@ object.Constructor('Parser', {
handler
: (handler.handler
|| defaultHandler(handler)))
.call(parsed, rest, arg,
// XXX should we pass unhandled explicitly???
// ...if yes then we do not need to splice it back in below...
.call(parsed,
rest,
arg,
...(value != null ?
[value]
: []))
// add nested parser result parsed...
// XXX should this be done also for .STOP / .ERROR / ... ???
handler instanceof Parser
&& parsed.handlerDefault(handler, rest, arg, res)
if(handler instanceof Parser){
parsed.unhandled.splice(parsed.unhandled.length, 0, ...res.unhandled)
parsed.handlerDefault(handler, rest, arg, res) }
res === module.STOP
&& parsed.stop(arg, rest)
@ -721,6 +737,10 @@ object.Constructor('Parser', {
var unhandled = parsed.unhandled = []
while(rest.length > 0){
var arg = rest.shift()
// non-string stuff in arg list...
if(typeof(arg) != typeof('str')){
unhandled.push(arg)
continue }
// NOTE: opts and commands do not follow the same path here
// because options if unidentified need to be split into
// single letter options and commands to not...

102
test.js
View File

@ -109,6 +109,105 @@ argv.Parser({
var lang =
module.lang =
argv.Parser({
// helpers...
push: function(...items){
this.unhandled.splice(this.unhandled.length, 0, ...items)
return this },
exec: function(...items){
this.rest.splice(0, 0, ...items)
return this },
pre_ns: argv.Parser({
}),
// XXX do not like the split namespaces....
ns: {
'[': [ 'blockto', '[:]' ],
'(': [ 'blockto', ')', 'exec' ],
'quote': [ 'quotenn', '0', '1' ],
},
'@*': function(code, value){
this.unhandled.push(...(
// type-convert...
/^[+-]?[0-9]+$/.test(value) ?
[parseInt(value)]
: /^[+-]?[0-9.]+$/.test(value) ?
[parseFloat(value)]
// call user macros...
: value in this.ns ?
(this.exec(...this.ns[value]), [])
// unhandled...
: [value])) },
// XXX hanck...
'@quotenn': function(code){
var skip = code.shift()
var quote = code.shift()
this.push(...code.splice(skip, quote)) },
// XXX this needs blocks to be already made...
// :: ( | name code -- | )
'@::': function(code){
this.ns[code.shift()] = code.shift() },
// XXX revise...
// groupb ( B | .. B -- | [ .. ])
// groupb ( A:B | .. A .. B .. B -- | [ .. [ .. ] .. ])
'@blockto': function(code, do_pack, value){
value = value || code.shift()
value = value instanceof Array ?
value
: value.split(':')
var [f, t] = value.length == 1 ?
[undefined, ...value]
: value
var pack = []
var cur = code.shift()
while(code.length > 0 && cur != t){
cur = cur == f ?
this['@blockto'](code, false, value)
: cur
pack.push(cur)
cur = code.shift() }
do_pack !== false
&& code.unshift(pack)
return pack },
'@exec': function(code){
var c = this.unhandled.pop()
code.splice(0, 0, ...(c instanceof Array ? c : [c])) },
'@exit': '-',
'@dup': function(){
this.push(...this.unhandled.slice(-1)) },
'@dup2': function(){
this.push(...this.unhandled.slice(-2)) },
'@print': function(){
this.print(this.unhandled.pop()) },
'@add': function(){
var [b, a] = [this.unhandled.pop(), this.unhandled.pop()]
this.unhandled.push(a + b) },
'@sub': function(){
var [b, a] = [this.unhandled.pop(), this.unhandled.pop()]
this.unhandled.push(a - b) },
'@mul': function(){
var [b, a] = [this.unhandled.pop(), this.unhandled.pop()]
this.unhandled.push(a * b) },
'@div': function(){
var [b, a] = [this.unhandled.pop(), this.unhandled.pop()]
this.unhandled.push(a / b) },
})
.then(function(){
this.print('>>>', this.unhandled) })
/*
console.log(' ->', p(['test', '--verbose', 'a', 'b', 'c']))
@ -127,7 +226,8 @@ p(['test', '-h'])
typeof(__filename) != 'undefined'
&& __filename == (require.main || {}).filename
&& console.log(p())
//&& console.log(p())
&& console.log(lang())