@@ -3,10 +3,12 @@ package org.mozartoz.bootcompiler
3
3
import java .io .{ Console => _ , _ }
4
4
5
5
import scala .collection .mutable .ListBuffer
6
- import scala .collection . immutable . PagedSeq
6
+ import scala .util . parsing . input . PagedSeqReader
7
7
import scala .util .parsing .combinator ._
8
8
import scala .util .parsing .input ._
9
- import scala .util .parsing .json ._
9
+
10
+ import scopt .{ OParser , OParserSetup , DefaultOParserSetup }
11
+ import spray .json ._
10
12
11
13
import oz ._
12
14
import parser ._
@@ -38,34 +40,39 @@ case class Config(
38
40
/** Entry point for the Mozart2 bootstrap compiler */
39
41
object Main {
40
42
/** Executes the Mozart2 bootstrap compiler */
41
- def main (args : Array [String ]) {
43
+ def main (args : Array [String ]): Unit = {
42
44
// Define command-line options
43
45
val optParser = new scopt.OptionParser [Config ](" bootcompiler" ) {
44
46
head(" bootcompiler" , " 2.0.x" )
45
- opt[Unit ](" baseenv" ) action {
46
- (_, c) => c.copy(mode = Config .Mode .BaseEnv )
47
- } text(" switch to base environment mode" )
48
- opt[String ]('o' , " output" ) action {
49
- (v, c) => c.copy(outputStream =
50
- () => new BufferedOutputStream (new FileOutputStream (v)))
51
- } text(" output file" )
52
- opt[String ]('m' , " module" ) action {
53
- (v, c) => c.copy(moduleDefs = v :: c.moduleDefs)
54
- } text(" module definition file or directory" )
55
- opt[String ]('b' , " base" ) action {
56
- (v, c) => c.copy(baseDeclsFileName = v)
57
- } text(" path to the base declarations file" )
58
- opt[String ]('D' , " define" ) action {
59
- (v, c) => c.copy(defines = c.defines + v)
60
- } text(" add a symbol to the conditional defines" )
61
- arg[String ](" <file>" ) action {
62
- (v, c) => c.copy(fileName = v)
63
- } text(" input file" )
47
+
48
+ opt[Unit ](" baseenv" )
49
+ .action((_, c) => c.copy(mode = Config .Mode .BaseEnv ))
50
+ .text(" switch to base environment mode" )
51
+
52
+ opt[String ]('o' , " output" )
53
+ .action((v, c) =>
54
+ c.copy(outputStream = () => new BufferedOutputStream (new FileOutputStream (v))))
55
+ .text(" output file" )
56
+
57
+ opt[String ]('m' , " module" )
58
+ .action((v, c) => c.copy(moduleDefs = v :: c.moduleDefs))
59
+ .text(" module definition file or directory" )
60
+
61
+ opt[String ]('b' , " base" )
62
+ .action((v, c) => c.copy(baseDeclsFileName = v))
63
+ .text(" path to the base declarations file" )
64
+
65
+ opt[String ]('D' , " define" )
66
+ .action((v, c) => c.copy(defines = c.defines + v))
67
+ .text(" add a symbol to the conditional defines" )
68
+
69
+ arg[String ](" <file>" )
70
+ .action((v, c) => c.copy(fileName = v))
71
+ .text(" input file" )
64
72
}
65
73
66
74
// Parse the options
67
- optParser.parse(args, Config ()) map { config =>
68
- // OK, we're good to go
75
+ optParser.parse(args, Config ()).foreach({ config =>
69
76
try {
70
77
config.mode match {
71
78
case Config .Mode .Module =>
@@ -80,15 +87,11 @@ object Main {
80
87
th.printStackTrace()
81
88
sys.exit(2 )
82
89
}
83
- } getOrElse {
84
- // Bad command-line arguments
85
- optParser.showUsage
86
- sys.exit(1 )
87
- }
90
+ })
88
91
}
89
92
90
93
/** Performs the Module mode */
91
- private def mainModule (config : Config ) {
94
+ private def mainModule (config : Config ): Unit = {
92
95
import config ._
93
96
94
97
val (program, _) = createProgram(moduleDefs, Some (baseDeclsFileName))
@@ -103,7 +106,7 @@ object Main {
103
106
}
104
107
105
108
/** Performs the BaseEnv mode */
106
- private def mainBaseEnv (config : Config ) {
109
+ private def mainBaseEnv (config : Config ): Unit = {
107
110
import config ._
108
111
109
112
val (program, bootModules) = createProgram(moduleDefs, None , true )
@@ -120,8 +123,10 @@ object Main {
120
123
}
121
124
122
125
/** Creates a new Program */
123
- private def createProgram (moduleDefs : List [String ],
124
- baseDeclsFileName : Option [String ], isBaseEnvironment : Boolean = false ) = {
126
+ private def createProgram (
127
+ moduleDefs : List [String ],
128
+ baseDeclsFileName : Option [String ],
129
+ isBaseEnvironment : Boolean = false ): (Program , Map [String , Expression ]) = {
125
130
val program = new Program (isBaseEnvironment)
126
131
val bootModules = loadModuleDefs(program, moduleDefs)
127
132
@@ -140,8 +145,10 @@ object Main {
140
145
* @param reader input reader
141
146
* @return The statement AST
142
147
*/
143
- private def parseStatement (reader : PagedSeqReader , file : File ,
144
- defines : Set [String ]) =
148
+ private def parseStatement (
149
+ reader : PagedSeqReader ,
150
+ file : File ,
151
+ defines : Set [String ]): Statement =
145
152
new ParserWrapper ().parseStatement(reader, file, defines)
146
153
147
154
/** Parses an Oz expression from a reader
@@ -153,7 +160,7 @@ object Main {
153
160
* @return The expression AST
154
161
*/
155
162
private def parseExpression (reader : PagedSeqReader , file : File ,
156
- defines : Set [String ]) =
163
+ defines : Set [String ]): Expression =
157
164
new ParserWrapper ().parseExpression(reader, file, defines)
158
165
159
166
/** Utility wrapper for an [[org.mozartoz.bootcompiler.parser.OzParser ]]
@@ -165,11 +172,11 @@ object Main {
165
172
private val parser = new OzParser ()
166
173
167
174
def parseStatement (reader : PagedSeqReader , file : File ,
168
- defines : Set [String ]) =
175
+ defines : Set [String ]): Statement =
169
176
processResult(parser.parseStatement(reader, file, defines))
170
177
171
178
def parseExpression (reader : PagedSeqReader , file : File ,
172
- defines : Set [String ]) =
179
+ defines : Set [String ]): Expression =
173
180
processResult(parser.parseExpression(reader, file, defines))
174
181
175
182
/** Processes a parse result
@@ -200,7 +207,7 @@ object Main {
200
207
*
201
208
* @param fileName name of the file to be read
202
209
*/
203
- private def readerForFile (fileName : String ) = {
210
+ private def readerForFile (fileName : String ): PagedSeqReader = {
204
211
new PagedSeqReader (PagedSeq .fromReader(
205
212
new BufferedReader (new FileReader (fileName))))
206
213
}
@@ -211,8 +218,6 @@ object Main {
211
218
* @param moduleDefs list of files that define builtin modules
212
219
*/
213
220
private def loadModuleDefs (prog : Program , moduleDefs : List [String ]) = {
214
- JSON .globalNumberParser = (_.toInt)
215
-
216
221
val result = new scala.collection.mutable.HashMap [String , Expression ]
217
222
218
223
for (moduleDef <- moduleDefs) {
@@ -235,53 +240,58 @@ object Main {
235
240
}
236
241
237
242
/** Loads one builtin module definition */
238
- private def loadModuleDef (prog : Program , moduleDef : File ) = {
239
- class CC [T ] {
240
- def unapply (a : Any ): Option [T ] = Some (a.asInstanceOf [T ])
243
+ private def loadModuleDef (prog : Program , moduleDef : File ): List [(String , Record )] = {
244
+ case class JsParameter (val kind : String )
245
+
246
+ case class JsBuiltin (
247
+ val name : String ,
248
+ val inlineable : Boolean ,
249
+ val inlineOpCode : Option [Int ],
250
+ val params : List [JsParameter ]
251
+ )
252
+
253
+ case class JsModule (
254
+ val name : String ,
255
+ val builtins : List [JsBuiltin ]
256
+ )
257
+
258
+ object ModuleJsonProtocol extends DefaultJsonProtocol {
259
+ implicit val parameterJsonFormat : RootJsonFormat [JsParameter ] = jsonFormat1(JsParameter )
260
+ implicit val builtinJsonFormat : RootJsonFormat [JsBuiltin ] = jsonFormat4(JsBuiltin )
261
+ implicit val moduleJsonFormat : RootJsonFormat [JsModule ] = jsonFormat2(JsModule )
241
262
}
242
263
243
- object M extends CC [Map [String , Any ]]
244
- object L extends CC [List [Any ]]
245
- object S extends CC [String ]
246
- object D extends CC [Double ]
247
- object B extends CC [Boolean ]
264
+ import ModuleJsonProtocol ._
265
+
266
+ val jsModule : JsModule =
267
+ readFileToString(moduleDef)
268
+ .parseJson
269
+ .convertTo[JsModule ]
248
270
249
- val modules = JSON .parseFull(readFileToString(moduleDef)).toList
271
+ val exportFields = new ListBuffer [ RecordField ]
250
272
251
273
for {
252
- M (module) <- modules
253
- S (modName) = module(" name" )
254
- L (builtins) = module(" builtins" )
274
+ jsBuiltin <- jsModule.builtins
255
275
} yield {
256
- val exportFields = new ListBuffer [RecordField ]
257
-
258
- for {
259
- M (bi) <- builtins
260
- S (biName) = bi(" name" )
261
- B (inlineable) = bi(" inlineable" )
262
- L (params) = bi(" params" )
263
- } {
264
- val inlineAs =
265
- if (inlineable) Some (bi(" inlineOpCode" ).asInstanceOf [Int ])
266
- else None
267
-
268
- val paramKinds = for {
269
- M (param) <- params
270
- S (paramKind) = param(" kind" )
271
- } yield {
272
- Builtin .ParamKind .withName(paramKind)
273
- }
276
+ val inlineAs : Option [Int ] =
277
+ if (jsBuiltin.inlineable) jsBuiltin.inlineOpCode
278
+ else None
279
+
280
+ val paramKinds = for {
281
+ jsParam <- jsBuiltin.params
282
+ } yield {
283
+ Builtin .ParamKind .withName(jsParam.kind)
284
+ }
274
285
275
- val builtin = new Builtin (
276
- modName, biName , paramKinds, inlineAs)
286
+ val builtin = new Builtin (
287
+ jsModule.name, jsBuiltin.name , paramKinds, inlineAs)
277
288
278
- prog.builtins.register(builtin)
289
+ prog.builtins.register(builtin)
279
290
280
- exportFields += RecordField (
281
- Constant (OzAtom (biName)), Constant (OzBuiltin (builtin)))
282
- }
291
+ exportFields += RecordField (
292
+ Constant (OzAtom (builtin.name)), Constant (OzBuiltin (builtin)))
283
293
284
- val moduleURL = " x-oz://boot/" + modName
294
+ val moduleURL = " x-oz://boot/" + jsModule.name
285
295
val moduleExport = Record (Constant (OzAtom (" export" )), exportFields.toList)
286
296
287
297
moduleURL -> moduleExport
@@ -293,7 +303,7 @@ object Main {
293
303
* @param prog program to compile
294
304
* @param fileName top-level file that is being processed
295
305
*/
296
- private def compile (prog : Program , fileName : String ) {
306
+ private def compile (prog : Program , fileName : String ): Unit = {
297
307
applyTransforms(prog)
298
308
299
309
if (prog.hasErrors) {
@@ -311,7 +321,7 @@ object Main {
311
321
}
312
322
313
323
/** Applies the successive transformation phases to a program */
314
- private def applyTransforms (prog : Program ) {
324
+ private def applyTransforms (prog : Program ): Unit = {
315
325
Namer (prog)
316
326
DesugarFunctor (prog)
317
327
DesugarClass (prog)
@@ -328,7 +338,7 @@ object Main {
328
338
* @param file file to read
329
339
* @return the contents of the file
330
340
*/
331
- private def readFileToString (file : File ) = {
341
+ private def readFileToString (file : File ): String = {
332
342
val source = io.Source .fromFile(file)
333
343
try source.mkString
334
344
finally source.close()
@@ -339,7 +349,7 @@ object Main {
339
349
* @param file file to read
340
350
* @return the lines in the file
341
351
*/
342
- private def readFileLines (file : File ) = {
352
+ private def readFileLines (file : File ): List [ String ] = {
343
353
val source = io.Source .fromFile(file)
344
354
try source.getLines().toList
345
355
finally source.close()
0 commit comments