diff --git a/parser/src/lexer.rs b/parser/src/lexer.rs index defa5e2322..edf21c973c 100644 --- a/parser/src/lexer.rs +++ b/parser/src/lexer.rs @@ -466,8 +466,16 @@ where loop { match self.next_char() { Some('\\') => { - if is_raw { + if self.chr0 == Some(quote_char) { + string_content.push(quote_char); + self.next_char(); + } else if is_raw { string_content.push('\\'); + if let Some(c) = self.next_char() { + string_content.push(c) + } else { + return Err(LexicalError::StringError); + } } else { match self.next_char() { Some('\\') => { @@ -711,7 +719,6 @@ where let tok_start = self.get_pos(); self.next_char(); let tok_end = self.get_pos(); - println!("Emoji: {}", c); return Some(Ok(( tok_start, Tok::Name { @@ -1438,7 +1445,7 @@ mod tests { #[test] fn test_string() { - let source = String::from(r#""double" 'single' 'can\'t' "\\\"" '\t\r\n' '\g'"#); + let source = String::from(r#""double" 'single' 'can\'t' "\\\"" '\t\r\n' '\g' r'raw\''"#); let tokens = lex_source(&source); assert_eq!( tokens, @@ -1467,6 +1474,10 @@ mod tests { value: String::from("\\g"), is_fstring: false, }, + Tok::String { + value: String::from("raw\'"), + is_fstring: false, + }, ] ); } diff --git a/parser/src/python.lalrpop b/parser/src/python.lalrpop index 9e5b309b1e..7f010278d2 100644 --- a/parser/src/python.lalrpop +++ b/parser/src/python.lalrpop @@ -337,10 +337,7 @@ CompoundStatement: ast::LocatedStatement = { IfStatement: ast::LocatedStatement = { "if" ":" => { // Determine last else: - let mut last = match s3 { - Some(s) => Some(s.2), - None => None, - }; + let mut last = s3.map(|s| s.2); // handle elif: for i in s2.into_iter().rev() { @@ -360,10 +357,7 @@ IfStatement: ast::LocatedStatement = { WhileStatement: ast::LocatedStatement = { "while" ":" => { - let or_else = match s2 { - Some(s) => Some(s.2), - None => None, - }; + let or_else = s2.map(|s| s.2); ast::LocatedStatement { location: loc, node: ast::Statement::While { test: e, body: s, orelse: or_else }, @@ -373,10 +367,7 @@ WhileStatement: ast::LocatedStatement = { ForStatement: ast::LocatedStatement = { "for" "in" ":" => { - let or_else = match s2 { - Some(s) => Some(s.2), - None => None, - }; + let or_else = s2.map(|s| s.2); ast::LocatedStatement { location: loc, node: ast::Statement::For { @@ -389,14 +380,8 @@ ForStatement: ast::LocatedStatement = { TryStatement: ast::LocatedStatement = { "try" ":" => { - let or_else = match else_suite { - Some(s) => Some(s.2), - None => None, - }; - let finalbody = match finally { - Some(s) => Some(s.2), - None => None, - }; + let or_else = else_suite.map(|s| s.2); + let finalbody = finally.map(|s| s.2); ast::LocatedStatement { location: loc, node: ast::Statement::Try { @@ -437,10 +422,7 @@ WithStatement: ast::LocatedStatement = { WithItem: ast::WithItem = { => { - let optional_vars = match n { - Some(val) => Some(val.1), - None => None, - }; + let optional_vars = n.map(|val| val.1); ast::WithItem { context_expr: t, optional_vars } }, }; @@ -461,27 +443,19 @@ FuncDef: ast::LocatedStatement = { }; Parameters: ast::Parameters = { - "(" )?> ")" => { - match a { - Some(a) => a, - None => Default::default(), - } + "(" )?> ")" => { + a.unwrap_or_else(Default::default) }, }; -// parameters are (String, None), kwargs are (String, Some(Test)) where Test is -// the default // Note that this is a macro which is used once for function defs, and // once for lambda defs. -TypedArgsList: ast::Parameters = { - > )?> => { +ParameterList: ast::Parameters = { + > )?> ","? => { let (names, default_elements) = param1; // Now gather rest of parameters: - let (vararg, kwonlyargs, kw_defaults, kwarg) = match args2 { - Some((_, x)) => x, - None => (None, vec![], vec![], None), - }; + let (vararg, kwonlyargs, kw_defaults, kwarg) = args2.map_or((None, vec![], vec![], None), |x| x.1); ast::Parameters { args: names, @@ -492,7 +466,7 @@ TypedArgsList: ast::Parameters = { kw_defaults: kw_defaults, } }, - > )> => { + > )> ","? => { let (names, default_elements) = param1; // Now gather rest of parameters: @@ -510,7 +484,7 @@ TypedArgsList: ast::Parameters = { kw_defaults: kw_defaults, } }, - > => { + > ","? => { let (vararg, kwonlyargs, kw_defaults, kwarg) = params; ast::Parameters { args: vec![], @@ -521,7 +495,7 @@ TypedArgsList: ast::Parameters = { kw_defaults: kw_defaults, } }, - > => { + > ","? => { ast::Parameters { args: vec![], kwonlyargs: vec![], @@ -535,8 +509,8 @@ TypedArgsList: ast::Parameters = { // Use inline here to make sure the "," is not creating an ambiguity. #[inline] -TypedParameters: (Vec, Vec) = { - > )*> => { +ParameterDefs: (Vec, Vec) = { + > )*> => { // Combine first parameters: let mut args = vec![param1]; args.extend(param2.into_iter().map(|x| x.1)); @@ -564,7 +538,7 @@ TypedParameters: (Vec, Vec) = { } }; -TypedParameterDef: (ast::Parameter, Option) = { +ParameterDef: (ast::Parameter, Option) = { => (i, None), "=" => (i, Some(e)), }; @@ -580,8 +554,11 @@ TypedParameter: ast::Parameter = { }, }; +// Use inline here to make sure the "," is not creating an ambiguity. +// TODO: figure out another grammar that makes this inline no longer required. +#[inline] ParameterListStarArgs: (Option>, Vec, Vec>, Option>) = { - "*" )*> )?> => { + "*" )*> )?> => { // Extract keyword arguments: let mut kwonlyargs = vec![]; let mut kw_defaults = vec![]; @@ -590,10 +567,7 @@ ParameterListStarArgs: (Option>, Vec Some(name), - None => None, - }; + let kwarg = kwarg.map(|n| n.1); (Some(va), kwonlyargs, kw_defaults, kwarg) } @@ -684,7 +658,7 @@ Test: ast::Expression = { }; LambdaDef: ast::Expression = { - "lambda" ?> ":" => + "lambda" ?> ":" => ast::Expression::Lambda { args: p.unwrap_or(Default::default()), body:Box::new(b) diff --git a/tests/snippets/function.py b/tests/snippets/function.py index a69178bb78..b1ea968609 100644 --- a/tests/snippets/function.py +++ b/tests/snippets/function.py @@ -2,3 +2,8 @@ def foo(): return 42 assert foo() == 42 + +def my_func(a,): + return a+2 + +assert my_func(2) == 4