Skip to content

Commit fb9fccb

Browse files
committed
Simplify name handling
1 parent 34f3308 commit fb9fccb

File tree

1 file changed

+39
-65
lines changed

1 file changed

+39
-65
lines changed

library/src/scala/annotation/newMain.scala

Lines changed: 39 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -62,45 +62,26 @@ final class newMain extends MainAnnotation[FromString, Any]:
6262
import newMain._
6363
import MainAnnotation._
6464

65-
private inline val argMarker = "--"
66-
private inline val shortArgMarker = "-"
67-
6865
private val longArgRegex = "--[a-zA-Z][a-zA-Z0-9]+".r
6966
private val shortArgRegex = "-[a-zA-Z]".r
7067

7168
extension (param: Parameter)
7269
private def aliasNames: Seq[String] =
73-
param.annotations.collect{ case a: Alias => a.aliases }.flatten
74-
75-
private def longAliases: Seq[String] =
76-
param.aliasNames.filter(_.size > 1).map(longNameWithMarker)
77-
78-
private def shortAliases: Seq[String] =
79-
param.aliasNames.filter(_.size == 1).map(shortNameWithMarker)
80-
81-
private def isLongName(name: String): Boolean =
82-
name.length > 1
83-
84-
private def isShortName(name: String): Boolean =
85-
name.length == 1
70+
param.annotations.collect{ case a: Alias => a.aliases.map(getNameWithMarker) }.flatten
8671

8772
private def getNameWithMarker(name: String): String =
88-
if isLongName(name) then argMarker + name
89-
else if isShortName(name) then shortArgMarker + name
73+
if name.length > 1 then s"--$name"
74+
else if name.length == 1 then s"-$name"
9075
else assert(false, "invalid name")
9176

92-
private def longNameWithMarker(name: String): String = argMarker + name
93-
private def shortNameWithMarker(name: String): String = shortArgMarker + name
94-
9577
def command(info: Info, args: Seq[String]): Option[Seq[String]] =
96-
val canonicalNames = CanonicalNames(info)
97-
canonicalNames.checkNames()
98-
if Help.hasHelpArg(canonicalNames, args) then
78+
val names = Names(info)
79+
if Help.shouldPrintDefaultHelp(names, args) then
9980
Help.printUsage(info)
10081
Help.printExplain(info)
10182
None
10283
else
103-
preProcessArgs(info, canonicalNames, args).orElse {
84+
preProcessArgs(info, names, args).orElse {
10485
Help.printUsage(info)
10586
None
10687
}
@@ -122,7 +103,7 @@ final class newMain extends MainAnnotation[FromString, Any]:
122103
def run(execProgram: () => Any): Unit =
123104
if !hasParseErrors then execProgram()
124105

125-
private def preProcessArgs(info: Info, canonicalNames: CanonicalNames, args: Seq[String]): Option[Seq[String]] =
106+
private def preProcessArgs(info: Info, names: Names, args: Seq[String]): Option[Seq[String]] =
126107
var hasError: Boolean = false
127108
def error(msg: String): Unit = {
128109
hasError = true
@@ -142,7 +123,7 @@ final class newMain extends MainAnnotation[FromString, Any]:
142123
case longArgRegex() | shortArgRegex() =>
143124
error(s"missing argument for ${name}")
144125
case value =>
145-
canonicalNames.getName(name) match
126+
names.canonicalName(name) match
146127
case Some(canonicalName) =>
147128
byNameArgs += ((canonicalName, value))
148129
case None =>
@@ -168,7 +149,7 @@ final class newMain extends MainAnnotation[FromString, Any]:
168149
byNameArgsMap.get(param.name) match
169150
case Some(byNameVarargs) => acc ::: byNameVarargs.toList ::: remainingArgs
170151
case None => acc ::: remainingArgs
171-
else byNameArgsMap.get(param.name) match
152+
else byNameArgsMap.get(getNameWithMarker(param.name)) match
172153
case Some(argValues) =>
173154
assert(argValues.nonEmpty, s"${param.name} present in byNameArgsMap, but it has no argument value")
174155
if argValues.length > 1 then
@@ -208,12 +189,12 @@ final class newMain extends MainAnnotation[FromString, Any]:
208189
/** The name of the special argument to display the method's help.
209190
* If one of the method's parameters is called the same, will be ignored.
210191
*/
211-
private inline val helpArg = "help"
192+
private inline val helpArg = "--help"
212193

213194
/** The short name of the special argument to display the method's help.
214195
* If one of the method's parameters uses the same short name, will be ignored.
215196
*/
216-
private inline val shortHelpArg = 'h'
197+
private inline val shortHelpArg = "-h"
217198

218199
private inline val maxUsageLineLength = 120
219200

@@ -222,7 +203,7 @@ final class newMain extends MainAnnotation[FromString, Any]:
222203
for (param <- info.parameters)
223204
yield {
224205
val canonicalName = getNameWithMarker(param.name)
225-
val namesPrint = (canonicalName +: param.longAliases ++: param.shortAliases).mkString("[", " | ", "]")
206+
val namesPrint = (canonicalName +: param.aliasNames).mkString("[", " | ", "]")
226207
val shortTypeName = param.typeName.split('.').last
227208
if param.isVarargs then s"[<$shortTypeName> [<$shortTypeName> [...]]]"
228209
else if param.hasDefault then s"[$namesPrint <$shortTypeName>]"
@@ -276,7 +257,7 @@ final class newMain extends MainAnnotation[FromString, Any]:
276257
println("Arguments:")
277258
for param <- info.parameters do
278259
val canonicalName = getNameWithMarker(param.name)
279-
val otherNames = (param.longAliases ++ param.shortAliases) match {
260+
val otherNames = param.aliasNames match {
280261
case Seq() => ""
281262
case names => names.mkString("(", ", ", ") ")
282263
}
@@ -297,59 +278,52 @@ final class newMain extends MainAnnotation[FromString, Any]:
297278
}
298279
end printExplain
299280

300-
def hasHelpArg(canonicalNames: CanonicalNames, args: Seq[String]): Boolean =
301-
val helpIsOverridden = canonicalNames.getName(argMarker + helpArg).isDefined
302-
val shortHelpIsOverridden = canonicalNames.getShortName(shortArgMarker + shortHelpArg).isDefined
303-
(!helpIsOverridden && args.contains(longNameWithMarker(helpArg))) ||
304-
(!shortHelpIsOverridden && args.contains(shortNameWithMarker(shortHelpArg.toString)))
281+
def shouldPrintDefaultHelp(names: Names, args: Seq[String]): Boolean =
282+
val helpIsOverridden = names.canonicalName(helpArg).isDefined
283+
val shortHelpIsOverridden = names.canonicalName(shortHelpArg).isDefined
284+
(!helpIsOverridden && args.contains(helpArg)) ||
285+
(!shortHelpIsOverridden && args.contains(shortHelpArg))
305286

306287
end Help
307288

308-
private class CanonicalNames(info: Info):
309-
310-
private val namesToCanonicalName: Map[String, String] = info.parameters.flatMap(
311-
param =>
312-
val names = param.longAliases.map(_.drop(2))
313-
val canonicalName = param.name
314-
if isLongName(canonicalName) then (canonicalName +: names).map(_ -> canonicalName)
315-
else names.map(_ -> canonicalName)
316-
).toMap
289+
private class Names(info: Info):
317290

318-
private val shortNamesToCanonicalName: Map[String, String] = info.parameters.flatMap(
319-
param =>
320-
val names = param.shortAliases.map(_.drop(1))
321-
val canonicalName = param.name
322-
if isShortName(canonicalName) then (canonicalName +: names).map(_ -> canonicalName)
323-
else names.map(_ -> canonicalName)
324-
).toMap
291+
checkNames()
325292

326-
def getName(name: String): Option[String] = namesToCanonicalName.get(name.drop(2)).orElse(getShortName(name))
293+
private lazy val namesToCanonicalName: Map[String, String] =
294+
info.parameters.flatMap(param =>
295+
val canonicalName = getNameWithMarker(param.name)
296+
(canonicalName -> canonicalName) +: param.aliasNames.map(_ -> canonicalName)
297+
).toMap
327298

328-
def getShortName(name: String): Option[String] = shortNamesToCanonicalName.get(name.drop(1))
299+
def canonicalName(name: String): Option[String] = namesToCanonicalName.get(name)
329300

330-
override def toString(): String =
331-
s"CanonicalNames($namesToCanonicalName, $shortNamesToCanonicalName)"
301+
override def toString(): String = s"Names($namesToCanonicalName)"
332302

333-
def checkNames(): Unit =
303+
private def checkNames(): Unit =
334304
def checkDuplicateNames() =
335305
val nameAndCanonicalName = info.parameters.flatMap { paramInfo =>
336-
(getNameWithMarker(paramInfo.name) +: paramInfo.longAliases ++: paramInfo.shortAliases).map(_ -> paramInfo.name)
306+
(getNameWithMarker(paramInfo.name) +: paramInfo.aliasNames).map(_ -> paramInfo.name)
337307
}
338-
val nameToCanonicalNames = nameAndCanonicalName.groupMap(_._1)(_._2)
339-
for (name, canonicalNames) <- nameToCanonicalNames if canonicalNames.length > 1 do
308+
val nameToNames = nameAndCanonicalName.groupMap(_._1)(_._2)
309+
for (name, canonicalNames) <- nameToNames if canonicalNames.length > 1 do
340310
throw IllegalArgumentException(s"$name is used for multiple parameters: ${canonicalNames.mkString(", ")}")
341311
def checkValidNames() =
342312
def isValidArgName(name: String): Boolean =
343-
longArgRegex.matches(argMarker + name) || shortArgRegex.matches(shortArgMarker + name)
313+
longArgRegex.matches(s"--$name") || shortArgRegex.matches(s"-$name")
344314
for param <- info.parameters do
345315
if !isValidArgName(param.name) then
346316
throw IllegalArgumentException(s"The following argument name is invalid: ${param.name}")
347-
for alias <- param.aliasNames if !isValidArgName(alias) do
348-
throw IllegalArgumentException(s"The following alias is invalid: $alias")
317+
for annot <- param.annotations do
318+
annot match
319+
case alias: Alias =>
320+
for name <- alias.aliases if !isValidArgName(name) do
321+
throw IllegalArgumentException(s"The following alias is invalid: $name")
322+
case _ =>
349323

350324
checkValidNames()
351325
checkDuplicateNames()
352-
end CanonicalNames
326+
end Names
353327

354328
end newMain
355329

0 commit comments

Comments
 (0)