1
+ use std::convert::TryFrom;
1
2
use std::str::FromStr;
2
3
use crate::time;
3
4
use crate::parser::{ast, Expr, Stmt, ParseError, concat, prepend, call, self};
5
+ use ast::AssignTarget;
4
6
5
7
grammar;
6
8
@@ -277,13 +279,13 @@ FnExpr = { FnExpr1, FnExpr2 };
277
279
FnExpr1: Expr = <dyn_scoping:"dyn"?> <params:FnExpr1Params> <body:Either2<Expr, FnBlockNoReturn>> =>
278
280
ast::FnExpr { params, body: body.into(), dynamic_scoping: dyn_scoping.is_some() }.into();
279
281
FnExpr1Params = {
280
- "|" <List0<IdentTerm , ",">> "|",
282
+ "|" <List0<AssignTarget , ",">> "|",
281
283
// Zero arguments should be captures by the List0, but it isn't because `||` is pre-tokenized as OR
282
284
"||" => vec![],
283
285
};
284
286
285
287
// FnDef-like syntax, more suitable for chaining with FnDef: fn adder($a) = fn ($b) = $a+$b; adder(2)(3)
286
- FnExpr2: Expr = <dyn_scoping:"dyn"?> "fn" <params:Paren<List0<IdentTerm , ",">>> <body:Either3<("=" <Expr>), BlockExpr, FnBlockNoReturn>> =>
288
+ FnExpr2: Expr = <dyn_scoping:"dyn"?> "fn" <params:Paren<List0<AssignTarget , ",">>> <body:Either3<("=" <Expr>), BlockExpr, FnBlockNoReturn>> =>
287
289
ast::FnExpr { params, body: body.into(), dynamic_scoping: dyn_scoping.is_some() }.into();
288
290
289
291
// XXX Should probably settle on one syntax to rule them all. Maybe `($a, $b) => $a+$b`?
@@ -393,10 +395,10 @@ BtcAmount: Expr = <num:SExpr> <denom:BTC_DENOMINATION> =>
393
395
Assign: Stmt = "let"? <assigns:List1<Assignment, ",">> ";" =>
394
396
ast::Assign(assigns).into();
395
397
396
- Assignment: ast::Assignment = <lhs:IdentTerm > "=" <rhs:Expr> =>
398
+ Assignment: ast::Assignment = <lhs:AssignTarget > "=" <rhs:Expr> =>
397
399
ast::Assignment { lhs, rhs };
398
400
399
- FnDef: Stmt = <dyn_scoping:"dyn"?> "fn" <ident:IdentTerm> <params:Paren<List0<IdentTerm , ",">>> <body:FnDefBody> =>
401
+ FnDef: Stmt = <dyn_scoping:"dyn"?> "fn" <ident:IdentTerm> <params:Paren<List0<AssignTarget , ",">>> <body:FnDefBody> =>
400
402
ast::FnDef { ident, params, body, dynamic_scoping: dyn_scoping.is_some() }.into();
401
403
402
404
FnDefBody = { "=" <Expr> ";", <BlockExpr> ";"?, <FnBlockNoReturn> ";"? };
@@ -409,15 +411,23 @@ IfStmtElse: Vec<Stmt> = {
409
411
"else" <IfStmt> => vec![<>],
410
412
};
411
413
412
- // An expression used in a statement position. The evaluated return value is
413
- // discarded, but this can be useful for expressions that produce side effects
414
- // like logging and exceptions.
414
+ // An expression used in a statement position. The evaluated return value is discarded,
415
+ // but this can be useful for expressions that produce logging/exceptions side effects.
415
416
ExprStmt: Stmt = <Expr> ";" => ast::ExprStmt(<>).into();
416
417
418
+ // Used as the target for Assignment and function parameters
419
+ AssignTarget: AssignTarget = {
420
+ IdentTerm => AssignTarget::Ident(<>),
421
+ // Reuses the existing Expr Array type as an AssignTarget to play nicely with LR(1) grammar.
422
+ // ASsignTarget::try_from() will reject Arrays that are not valid as a target.
423
+ // https://github.com/lalrpop/lalrpop/issues/552#issuecomment-778923903
424
+ Array =>? Ok(AssignTarget::try_from(<>)?),
425
+ };
426
+
417
427
// Helpers
418
428
419
429
Either2<A, B>: Expr = { A, B };
420
- Either3<A, B, C>: Expr = { A, B };
430
+ Either3<A, B, C>: Expr = { A, B, C };
421
431
422
432
// A `S`-separated list of zero or more `T` values
423
433
List0<T, S>: Vec<T> = <l:(<T> S)*> <t:T?> => concat(l, t);
0 commit comments