This repository was archived by the owner on Jul 27, 2023. It is now read-only.
forked from RustPython/Parser
-
Notifications
You must be signed in to change notification settings - Fork 2
Lex Jupyter Magic in assignment value position #30
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
757be6e
Lex Jupyter Magic in assignment value position
dhruvmanila 1f98fe2
Emit `Newline` and handle indentation for Magic commands
dhruvmanila 71c2aa9
Test Magic command token in assignment value
dhruvmanila 7a222ad
Revert "Emit `Newline` and handle indentation for Magic commands"
dhruvmanila 3dfb8f4
Use a boolean flag for "Is last token an `Equal`"?
dhruvmanila File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -175,6 +175,8 @@ pub struct Lexer<T: Iterator<Item = char>> { | |
pending: Vec<Spanned>, | ||
// The current location. | ||
location: TextSize, | ||
// Is the last token an equal sign? | ||
last_token_is_equal: bool, | ||
// Lexer mode. | ||
mode: Mode, | ||
} | ||
|
@@ -233,6 +235,7 @@ where | |
pending: Vec::with_capacity(5), | ||
location: start, | ||
window: CharWindow::new(input), | ||
last_token_is_equal: false, | ||
mode, | ||
}; | ||
// Fill the window. | ||
|
@@ -945,15 +948,19 @@ where | |
} | ||
} | ||
'%' => { | ||
let tok_start = self.get_pos(); | ||
self.next_char(); | ||
if let Some('=') = self.window[0] { | ||
self.next_char(); | ||
let tok_end = self.get_pos(); | ||
self.emit((Tok::PercentEqual, TextRange::new(tok_start, tok_end))); | ||
if self.mode == Mode::Jupyter && self.nesting == 0 && self.last_token_is_equal { | ||
self.lex_and_emit_magic_command(); | ||
} else { | ||
let tok_end = self.get_pos(); | ||
self.emit((Tok::Percent, TextRange::new(tok_start, tok_end))); | ||
let tok_start = self.get_pos(); | ||
self.next_char(); | ||
if let Some('=') = self.window[0] { | ||
self.next_char(); | ||
let tok_end = self.get_pos(); | ||
self.emit((Tok::PercentEqual, TextRange::new(tok_start, tok_end))); | ||
} else { | ||
let tok_end = self.get_pos(); | ||
self.emit((Tok::Percent, TextRange::new(tok_start, tok_end))); | ||
} | ||
} | ||
} | ||
'|' => { | ||
|
@@ -1025,17 +1032,21 @@ where | |
} | ||
} | ||
'!' => { | ||
let tok_start = self.get_pos(); | ||
self.next_char(); | ||
if let Some('=') = self.window[0] { | ||
self.next_char(); | ||
let tok_end = self.get_pos(); | ||
self.emit((Tok::NotEqual, TextRange::new(tok_start, tok_end))); | ||
if self.mode == Mode::Jupyter && self.nesting == 0 && self.last_token_is_equal { | ||
self.lex_and_emit_magic_command(); | ||
} else { | ||
return Err(LexicalError { | ||
error: LexicalErrorType::UnrecognizedToken { tok: '!' }, | ||
location: tok_start, | ||
}); | ||
let tok_start = self.get_pos(); | ||
self.next_char(); | ||
if let Some('=') = self.window[0] { | ||
self.next_char(); | ||
let tok_end = self.get_pos(); | ||
self.emit((Tok::NotEqual, TextRange::new(tok_start, tok_end))); | ||
} else { | ||
return Err(LexicalError { | ||
error: LexicalErrorType::UnrecognizedToken { tok: '!' }, | ||
location: tok_start, | ||
}); | ||
} | ||
} | ||
} | ||
'~' => { | ||
|
@@ -1292,6 +1303,7 @@ where | |
|
||
// Helper function to emit a lexed token to the queue of tokens. | ||
fn emit(&mut self, spanned: Spanned) { | ||
self.last_token_is_equal = matches!(spanned.0, Tok::Equal); | ||
self.pending.push(spanned); | ||
} | ||
} | ||
|
@@ -1669,6 +1681,85 @@ mod tests { | |
) | ||
} | ||
|
||
#[test] | ||
fn test_jupyter_magic_assignment() { | ||
let source = r" | ||
pwd = !pwd | ||
foo = %timeit a = b | ||
bar = %timeit a % 3 | ||
baz = %matplotlib \ | ||
inline" | ||
Comment on lines
+1687
to
+1691
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All of the valid positions for magic command token in terms of an assignment statement. |
||
.trim(); | ||
let tokens = lex_jupyter_source(source); | ||
assert_eq!( | ||
tokens, | ||
vec![ | ||
Tok::Name { | ||
name: "pwd".to_string() | ||
}, | ||
Tok::Equal, | ||
Tok::MagicCommand { | ||
value: "pwd".to_string(), | ||
kind: MagicKind::Shell, | ||
}, | ||
Tok::Newline, | ||
Tok::Name { | ||
name: "foo".to_string() | ||
}, | ||
Tok::Equal, | ||
Tok::MagicCommand { | ||
value: "timeit a = b".to_string(), | ||
kind: MagicKind::Magic, | ||
}, | ||
Tok::Newline, | ||
Tok::Name { | ||
name: "bar".to_string() | ||
}, | ||
Tok::Equal, | ||
Tok::MagicCommand { | ||
value: "timeit a % 3".to_string(), | ||
kind: MagicKind::Magic, | ||
}, | ||
Tok::Newline, | ||
Tok::Name { | ||
name: "baz".to_string() | ||
}, | ||
Tok::Equal, | ||
Tok::MagicCommand { | ||
value: "matplotlib inline".to_string(), | ||
kind: MagicKind::Magic, | ||
}, | ||
Tok::Newline, | ||
] | ||
) | ||
} | ||
|
||
fn assert_no_jupyter_magic(tokens: &[Tok]) { | ||
for tok in tokens { | ||
match tok { | ||
Tok::MagicCommand { .. } => panic!("Unexpected magic command token: {:?}", tok), | ||
_ => {} | ||
} | ||
} | ||
} | ||
|
||
#[test] | ||
fn test_jupyter_magic_not_an_assignment() { | ||
let source = r" | ||
# Other magic kinds are not valid here (can't test `foo = ?str` because '?' is not a valid token) | ||
foo = /func | ||
foo = ;func | ||
foo = ,func | ||
|
||
(foo == %timeit a = b) | ||
(foo := %timeit a = b) | ||
def f(arg=%timeit a = b): | ||
pass" | ||
.trim(); | ||
Comment on lines
+1748
to
+1758
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These aren't valid: parenthesized, any token other than |
||
let tokens = lex_jupyter_source(source); | ||
assert_no_jupyter_magic(&tokens); | ||
} | ||
|
||
#[test] | ||
fn test_numbers() { | ||
let source = "0x2f 0o12 0b1101 0 123 123_45_67_890 0.2 1e+2 2.1e3 2j 2.2j"; | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.