Skip to content

Commit cd9747d

Browse files
committed
Change nomenclature
Change nomenclature from main methods and commands to entry points and wrappers, since the scheme is now more general than just main method generation.
1 parent b9670df commit cd9747d

File tree

1 file changed

+60
-62
lines changed

1 file changed

+60
-62
lines changed

tests/pos/main-method-scheme-generic.scala

Lines changed: 60 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,87 +1,89 @@
11
import annotation.{Annotation, StaticAnnotation}
22
import collection.mutable
33

4-
/** MainAnnotation provides the functionality for a compiler-generated wrapper class.
5-
* It links a compiler-generated main method (call it compiler-main) to a user
6-
* written main method (user-main).
7-
* The protocol of calls from compiler-main is as follows:
4+
/** This class provides a framework for compiler-generated wrappers
5+
* of "entry-point" methods. It routes and transforms parameters and results
6+
* between a compiler-generated wrapper method that has calling conventions
7+
* fixed by a framework and a user-written entry-point method that can have
8+
* flexible argument lists. It allows the wrapper to provide help and usage
9+
* information as well as customised error messages if the actual wrapper arguments
10+
* do not match the expected entry-point parameters.
811
*
9-
* - create a `command` with the command line arguments,
10-
* - for each parameter of user-main, a call to `command.nextArgGetter`,
11-
* or `command.finalArgsGetter` if is a final varargs parameter,
12-
* - a call to `command.run` with the closure of user-main applied to all arguments.
12+
* The protocol of calls from the wrapper method is as follows:
13+
*
14+
* 1. Create a `call` instance with the wrapper argument.
15+
* 2. For each parameter of the entry-point, invoke `call.nextArgGetter`,
16+
* or `call.finalArgsGetter` if is a final varargs parameter.
17+
* 3. Invoke `call.run` with the closure of entry-point applied to all arguments.
1318
*
1419
* The wrapper class has this outline:
1520
*
1621
* object <wrapperClass>:
17-
* def <wrapperMethod>(args: <CommandLineArgs>) =
22+
* @WrapperAnnotation def <wrapperMethod>(args: <WrapperArgs>) =
1823
* ...
1924
*
20-
* Here the `<wrapperClass>` name is the result of an inline call to `wrapperClassName`
21-
* and `<wrapperMethod>` is the result of an inline call to `wrapperMethodName`
22-
*
23-
* The result type of `<main>` is the same as the result type of `run`
24-
* in the concrete implementation of `MainAnnotation`.
25+
* Here `<wrapperClass>` and `<wrapperMethod>` are obtained from an
26+
* inline call to the `wrapperName` method.
2527
*/
26-
trait MainAnnotation extends StaticAnnotation:
28+
trait EntryPointAnnotation extends StaticAnnotation:
2729

28-
/** The class used for argument string parsing. E.g. `scala.util.FromString`,
29-
* but could be something else
30+
/** The class used for argument parsing. E.g. `scala.util.FromString`, if
31+
* arguments are strings, but it could be something else.
3032
*/
3133
type ArgumentParser[T]
3234

3335
/** The required result type of the user-defined main function */
34-
type MainResultType
36+
type EntryPointResult
37+
38+
/** The type of the wrapper argument. E.g., for Java main methods: `Array[String]` */
39+
type WrapperArgs
3540

36-
/** The type of the command line arguments. E.g., for Java main methods: `Array[String]` */
37-
type CommandLineArgs
41+
/** The return type of the generated wrapper. E.g., for Java main methods: `Unit` */
42+
type WrapperResult
3843

39-
/** The return type of the generated command. E.g., for Java main methods: `Unit` */
40-
type CommandResult
44+
/** An annotation type with which the wrapper method is decorated.
45+
* No annotation is generated if the type is left abstract.
46+
*/
47+
type WrapperAnnotation <: Annotation
48+
49+
/** The fully qualified name (relative to enclosing package) to
50+
* use for the static wrapper method.
51+
* @param mainName the fully qualified name of the user-defined main method
52+
*/
53+
inline def wrapperName(mainName: String): String
4154

42-
/** A new command with arguments from `args` */
43-
def command(args: CommandLineArgs): Command
55+
/** A new wrapper call with arguments from `args` */
56+
def call(args: WrapperArgs): Call
4457

45-
/** A class representing a command to run */
46-
abstract class Command:
58+
/** A class representing a wrapper call */
59+
abstract class Call:
4760

4861
/** The getter for the next argument of type `T` */
4962
def nextArgGetter[T](argName: String, fromString: ArgumentParser[T], defaultValue: Option[T] = None): () => T
5063

5164
/** The getter for a final varargs argument of type `T*` */
5265
def finalArgsGetter[T](argName: String, fromString: ArgumentParser[T]): () => Seq[T]
5366

54-
/** Run `program` if all arguments are valid,
67+
/** Run `entryPoint` if all arguments are valid,
5568
* or print usage information and/or error messages.
56-
* @param program the program to run
57-
* @param mainName the fully qualified name of the user-defined main method
58-
* @param docComment the doc comment of the user-defined main method
69+
* @param entryPointApply the applied entry-point to run
70+
* @param entryPointName the fully qualified name of the entry-point method
71+
* @param docComment the doc comment of the entry-point method
5972
*/
60-
def run(program: => MainResultType, mainName: String, docComment: String): CommandResult
61-
end Command
62-
63-
/** The fully qualified name to use for the static wrapper method
64-
* @param mainName the fully qualified name of the user-defined main method
65-
*/
66-
inline def wrapperName(mainName: String): String
67-
68-
/** An annotation type with which the wrapper method is decorated.
69-
* No annotation is generated if the type is left abstract.
70-
*/
71-
type WrapperAnnotation <: Annotation
72-
73-
end MainAnnotation
73+
def run(entryPointApply: => EntryPointResult, entryPointName: String, docComment: String): WrapperResult
74+
end Call
75+
end EntryPointAnnotation
7476

7577
//Sample main class, can be freely implemented:
7678

77-
class main extends MainAnnotation:
79+
class main extends EntryPointAnnotation:
7880

7981
type ArgumentParser[T] = util.FromString[T]
80-
type MainResultType = Any
81-
type CommandLineArgs = Array[String]
82-
type CommandResult = Unit
82+
type EntryPointResult = Unit
83+
type WrapperArgs = Array[String]
84+
type WrapperResult = Unit
8385

84-
def command(args: Array[String]) = new Command:
86+
def call(args: Array[String]) = new Call:
8587

8688
/** A buffer of demanded argument names, plus
8789
* "?" if it has a default
@@ -133,9 +135,9 @@ class main extends MainAnnotation:
133135
val getters = remainingArgGetters()
134136
() => getters.map(_())
135137

136-
def run(f: => MainResultType, mainName: String, docComment: String): Unit =
138+
def run(entryPointApply: => EntryPointResult, entryPointName: String, docComment: String): Unit =
137139
def usage(): Unit =
138-
val cmd = mainName.dropRight(".main".length)
140+
val cmd = entryPointName.dropRight(".main".length)
139141
val params = argInfos.map(_ + _).mkString(" ")
140142
println(s"Usage: java $cmd $params")
141143

@@ -162,11 +164,9 @@ class main extends MainAnnotation:
162164
if errors.nonEmpty then
163165
for msg <- errors do println(s"Error: $msg")
164166
usage()
165-
else f match
166-
case n: Int if n < 0 => System.exit(-n)
167-
case _ =>
167+
else f
168168
end run
169-
end command
169+
end call
170170

171171
inline def wrapperName(mainName: String): String =
172172
s"${mainName.drop(mainName.lastIndexOf('.') + 1)}.main"
@@ -175,8 +175,6 @@ class main extends MainAnnotation:
175175

176176
end main
177177

178-
class EntryPoint extends Annotation
179-
180178
// Sample main method
181179

182180
object myProgram:
@@ -190,11 +188,11 @@ end myProgram
190188
// Compiler generated code:
191189

192190
object add extends main:
193-
@EntryPoint def main(args: Array[String]) =
194-
val cmd = command(args)
195-
val arg1 = cmd.nextArgGetter[Int]("num", summon[ArgumentParser[Int]])
196-
val arg2 = cmd.nextArgGetter[Int]("inc", summon[ArgumentParser[Int]], Some(1))
197-
cmd.run(myProgram.add(arg1(), arg2()), "add", "Adds two numbers")
191+
def main(args: Array[String]) =
192+
val cll = call(args)
193+
val arg1 = cll.nextArgGetter[Int]("num", summon[ArgumentParser[Int]])
194+
val arg2 = cll.nextArgGetter[Int]("inc", summon[ArgumentParser[Int]], Some(1))
195+
cll.run(myProgram.add(arg1(), arg2()), "add", "Adds two numbers")
198196
end add
199197

200198
/** --- Some scenarios ----------------------------------------

0 commit comments

Comments
 (0)