@@ -538,19 +538,28 @@ where
538
538
}
539
539
}
540
540
541
- fn lex_and_emit_magic_command ( & mut self ) {
541
+ fn lex_and_emit_magic_command ( & mut self ) -> bool {
542
542
let kind = match self . window [ ..2 ] {
543
543
[ Some ( c1) , Some ( c2) ] => {
544
544
MagicKind :: try_from ( [ c1, c2] ) . map_or_else ( |_| MagicKind :: try_from ( c1) , Ok )
545
545
}
546
546
// When the escape character is the last character of the file.
547
547
[ Some ( c) , None ] => MagicKind :: try_from ( c) ,
548
- _ => return ,
548
+ _ => return false ,
549
549
} ;
550
550
if let Ok ( kind) = kind {
551
+ // If the magic prefix is not followed by a valid identifier start
552
+ // we don't lex it as a magic command.
553
+ if let Some ( c) = self . window [ usize:: from ( kind. prefix_len ( ) ) ] {
554
+ if !self . is_identifier_start ( c) {
555
+ return false ;
556
+ }
557
+ }
551
558
let magic_command = self . lex_magic_command ( kind) ;
552
559
self . emit ( magic_command) ;
560
+ return true ;
553
561
}
562
+ false
554
563
}
555
564
556
565
/// Lex a string literal.
@@ -705,7 +714,9 @@ where
705
714
}
706
715
// https://github.com/ipython/ipython/blob/635815e8f1ded5b764d66cacc80bbe25e9e2587f/IPython/core/inputtransformer2.py#L345
707
716
Some ( '%' | '!' | '?' | '/' | ';' | ',' ) if self . mode == Mode :: Jupyter => {
708
- self . lex_and_emit_magic_command ( ) ;
717
+ if !self . lex_and_emit_magic_command ( ) {
718
+ break ;
719
+ }
709
720
}
710
721
Some ( '\x0C' ) => {
711
722
// Form feed character!
@@ -948,9 +959,15 @@ where
948
959
}
949
960
}
950
961
'%' => {
951
- if self . mode == Mode :: Jupyter && self . nesting == 0 && self . last_token_is_equal {
952
- self . lex_and_emit_magic_command ( ) ;
962
+ let lexed_magic_command = if self . mode == Mode :: Jupyter
963
+ && self . nesting == 0
964
+ && self . last_token_is_equal
965
+ {
966
+ self . lex_and_emit_magic_command ( )
953
967
} else {
968
+ false
969
+ } ;
970
+ if !lexed_magic_command {
954
971
let tok_start = self . get_pos ( ) ;
955
972
self . next_char ( ) ;
956
973
if let Some ( '=' ) = self . window [ 0 ] {
@@ -1032,9 +1049,15 @@ where
1032
1049
}
1033
1050
}
1034
1051
'!' => {
1035
- if self . mode == Mode :: Jupyter && self . nesting == 0 && self . last_token_is_equal {
1036
- self . lex_and_emit_magic_command ( ) ;
1052
+ let lexed_magic_command = if self . mode == Mode :: Jupyter
1053
+ && self . nesting == 0
1054
+ && self . last_token_is_equal
1055
+ {
1056
+ self . lex_and_emit_magic_command ( )
1037
1057
} else {
1058
+ false
1059
+ } ;
1060
+ if !lexed_magic_command {
1038
1061
let tok_start = self . get_pos ( ) ;
1039
1062
self . next_char ( ) ;
1040
1063
if let Some ( '=' ) = self . window [ 0 ] {
@@ -1736,9 +1759,8 @@ baz = %matplotlib \
1736
1759
1737
1760
fn assert_no_jupyter_magic ( tokens : & [ Tok ] ) {
1738
1761
for tok in tokens {
1739
- match tok {
1740
- Tok :: MagicCommand { .. } => panic ! ( "Unexpected magic command token: {:?}" , tok) ,
1741
- _ => { }
1762
+ if let Tok :: MagicCommand { .. } = tok {
1763
+ panic ! ( "Unexpected magic command token: {:?}" , tok)
1742
1764
}
1743
1765
}
1744
1766
}
@@ -1751,6 +1773,10 @@ foo = /func
1751
1773
foo = ;func
1752
1774
foo = ,func
1753
1775
1776
+ # Magic prefix is not followed by a valid identifier start
1777
+ % timeit
1778
+ foo = % timeit
1779
+
1754
1780
(foo == %timeit a = b)
1755
1781
(foo := %timeit a = b)
1756
1782
def f(arg=%timeit a = b):
0 commit comments