// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
///|
fn positional_args(args : Array[Arg]) -> Array[Arg] {
[
for arg in args if arg.info is PositionalInfo(_) => arg
]
}
///|
fn next_positional(positionals : Array[Arg], collected : Array[String]) -> Arg? {
let target = collected.length()
let total = target + 1
for idx, arg in positionals; cursor = 0 {
if cursor >= total {
break None
}
let remaining = total - cursor
let take = if arg.multiple {
let (min, max) = arg_min_max(arg)
let reserve = remaining_positional_min(positionals, idx + 1)
let mut take = remaining - reserve
if take < 0 {
take = 0
}
match max {
Some(max_count) if take > max_count => take = max_count
_ => ()
}
if take < min {
take = min
}
if take > remaining {
take = remaining
}
take
} else if remaining > 0 {
1
} else {
0
}
if take > 0 && target < cursor + take {
break Some(arg)
}
continue cursor + take
} nobreak {
None
}
}
///|
fn should_parse_as_positional(
arg : String,
positionals : Array[Arg],
collected : Array[String],
long_index : Map[String, Arg],
short_index : Map[Char, Arg],
) -> Bool {
if !arg.has_prefix("-") || arg == "-" {
return false
}
let next = match next_positional(positionals, collected) {
Some(v) => v
None => return false
}
let next_allow = match next.info {
FlagInfo(_) => false
OptionInfo(allow_hyphen_values~, ..)
| PositionalInfo(allow_hyphen_values~, ..) => allow_hyphen_values
}
let allow = next_allow || is_negative_number(arg)
if !allow {
return false
}
if arg.has_prefix("--") {
let (name, _) = split_long(arg)
return long_index.get_from_string(name) is None
}
let short = arg.get_char(1)
match short {
Some(ch) => short_index.get(ch) is None
None => true
}
}
///|
fn is_negative_number(arg : String) -> Bool {
if arg.length() < 2 {
return false
}
guard arg is ['-', .. rest] else { return false }
for ch in rest {
if ch is ('0'..='9') {
continue
} else {
break false
}
} nobreak {
true
}
}