@@ -136,6 +136,17 @@ pub enum MacResult {
136
136
MRAny ( @AnyMacro ) ,
137
137
MRDef ( MacroDef ) ,
138
138
}
139
+ impl MacResult {
140
+ /// Create an empty expression MacResult; useful for satisfying
141
+ /// type signatures after emitting a non-fatal error (which stop
142
+ /// compilation well before the validity (or otherwise)) of the
143
+ /// expression are checked.
144
+ pub fn dummy_expr ( ) -> MacResult {
145
+ MRExpr ( @ast:: Expr {
146
+ id : ast:: DUMMY_NODE_ID , node : ast:: ExprLogLevel , span : codemap:: DUMMY_SP
147
+ } )
148
+ }
149
+ }
139
150
140
151
pub enum SyntaxExtension {
141
152
// #[deriving] and such
@@ -364,10 +375,27 @@ impl<'a> ExtCtxt<'a> {
364
375
_ => self . bug ( "tried to pop without a push" )
365
376
}
366
377
}
378
+ /// Emit `msg` attached to `sp`, and stop compilation immediately.
379
+ ///
380
+ /// `span_err` should be strongly prefered where-ever possible:
381
+ /// this should *only* be used when
382
+ /// - continuing has a high risk of flow-on errors (e.g. errors in
383
+ /// declaring a macro would cause all uses of that macro to
384
+ /// complain about "undefined macro"), or
385
+ /// - there is literally nothing else that can be done (however,
386
+ /// in most cases one can construct a dummy expression/item to
387
+ /// substitute; we never hit resolve/type-checking so the dummy
388
+ /// value doesn't have to match anything)
367
389
pub fn span_fatal ( & self , sp : Span , msg : & str ) -> ! {
368
390
self . print_backtrace ( ) ;
369
391
self . parse_sess . span_diagnostic . span_fatal ( sp, msg) ;
370
392
}
393
+
394
+ /// Emit `msg` attached to `sp`, without immediately stopping
395
+ /// compilation.
396
+ ///
397
+ /// Compilation will be stopped in the near future (at the end of
398
+ /// the macro expansion phase).
371
399
pub fn span_err ( & self , sp : Span , msg : & str ) {
372
400
self . print_backtrace ( ) ;
373
401
self . parse_sess . span_diagnostic . span_err ( sp, msg) ;
@@ -402,53 +430,69 @@ impl<'a> ExtCtxt<'a> {
402
430
}
403
431
}
404
432
405
- pub fn expr_to_str ( cx : & ExtCtxt , expr : @ast:: Expr , err_msg : & str ) -> ( @str , ast:: StrStyle ) {
433
+ /// Extract a string literal from `expr`, emitting `err_msg` if `expr`
434
+ /// is not a string literal. This does not stop compilation on error,
435
+ /// merely emits a non-fatal error and returns None.
436
+ pub fn expr_to_str ( cx : & ExtCtxt , expr : @ast:: Expr ,
437
+ err_msg : & str ) -> Option < ( @str , ast:: StrStyle ) > {
406
438
match expr. node {
407
439
ast:: ExprLit ( l) => match l. node {
408
- ast:: LitStr ( s, style) => ( s, style) ,
409
- _ => cx. span_fatal ( l. span , err_msg)
440
+ ast:: LitStr ( s, style) => return Some ( ( s, style) ) ,
441
+ _ => cx. span_err ( l. span , err_msg)
410
442
} ,
411
- _ => cx. span_fatal ( expr. span , err_msg)
443
+ _ => cx. span_err ( expr. span , err_msg)
412
444
}
445
+ None
413
446
}
414
447
448
+ /// Non-fatally assert that `tts` is empty. Note that this function
449
+ /// returns even when `tts` is non-empty, macros that *need* to stop
450
+ /// compilation should call
451
+ /// `cx.parse_sess.span_diagnostic.abort_if_errors()` (this should be
452
+ /// done as rarely as possible).
415
453
pub fn check_zero_tts ( cx : & ExtCtxt , sp : Span , tts : & [ ast:: TokenTree ] ,
416
454
name : & str ) {
417
455
if tts. len ( ) != 0 {
418
- cx. span_fatal ( sp, format ! ( "{} takes no arguments" , name) ) ;
456
+ cx. span_err ( sp, format ! ( "{} takes no arguments" , name) ) ;
419
457
}
420
458
}
421
459
460
+ /// Extract the string literal from the first token of `tts`. If this
461
+ /// is not a string literal, emit an error and return None.
422
462
pub fn get_single_str_from_tts ( cx : & ExtCtxt ,
423
463
sp : Span ,
424
464
tts : & [ ast:: TokenTree ] ,
425
465
name : & str )
426
- -> @str {
466
+ -> Option < @str > {
427
467
if tts. len ( ) != 1 {
428
- cx. span_fatal ( sp, format ! ( "{} takes 1 argument." , name) ) ;
429
- }
430
-
431
- match tts [ 0 ] {
432
- ast:: TTTok ( _, token:: LIT_STR ( ident) )
433
- | ast :: TTTok ( _ , token :: LIT_STR_RAW ( ident , _ ) ) => cx. str_of ( ident ) ,
434
- _ => cx . span_fatal ( sp , format ! ( "{} requires a string." , name ) ) ,
468
+ cx. span_err ( sp, format ! ( "{} takes 1 argument." , name) ) ;
469
+ } else {
470
+ match tts [ 0 ] {
471
+ ast :: TTTok ( _ , token :: LIT_STR ( ident ) )
472
+ | ast:: TTTok ( _, token:: LIT_STR_RAW ( ident, _ ) ) => return Some ( cx . str_of ( ident ) ) ,
473
+ _ => cx. span_err ( sp , format ! ( "{} requires a string." , name ) ) ,
474
+ }
435
475
}
476
+ None
436
477
}
437
478
479
+ /// Extract comma-separated expressions from `tts`. If there is a
480
+ /// parsing error, emit a non-fatal error and return None.
438
481
pub fn get_exprs_from_tts ( cx : & ExtCtxt ,
439
482
sp : Span ,
440
- tts : & [ ast:: TokenTree ] ) -> ~[ @ast:: Expr ] {
483
+ tts : & [ ast:: TokenTree ] ) -> Option < ~[ @ast:: Expr ] > {
441
484
let mut p = parse:: new_parser_from_tts ( cx. parse_sess ( ) ,
442
485
cx. cfg ( ) ,
443
486
tts. to_owned ( ) ) ;
444
487
let mut es = ~[ ] ;
445
488
while p. token != token:: EOF {
446
489
if es. len ( ) != 0 && !p. eat ( & token:: COMMA ) {
447
- cx. span_fatal ( sp, "expected token: `,`" ) ;
490
+ cx. span_err ( sp, "expected token: `,`" ) ;
491
+ return None ;
448
492
}
449
493
es. push ( p. parse_expr ( ) ) ;
450
494
}
451
- es
495
+ Some ( es )
452
496
}
453
497
454
498
// in order to have some notion of scoping for macros,
0 commit comments