@@ -1267,8 +1267,19 @@ fn parse_generic_bound(token: &Token) -> Option<GenericBound> {
12671267}
12681268
12691269fn parse_block ( tokens : & [ Token ] , open : usize , close : usize ) -> Block {
1270+ Block {
1271+ statements : collect_statements ( tokens, open + 1 , close) ,
1272+ span : tokens[ open] . span . clone ( ) ,
1273+ }
1274+ }
1275+
1276+ /// Collect statements in `[start, close)`. Handles the scoped-view desugar:
1277+ /// `view name = expr` followed by the rest of the block becomes
1278+ /// `with expr as name { <rest> }`, so a borrowed view's scope ends at the
1279+ /// enclosing block (spec §20.2-1) and it reuses every `with`-lease rule
1280+ /// (no escape / no managed capture) without a separate code path.
1281+ fn collect_statements ( tokens : & [ Token ] , mut index : usize , close : usize ) -> Vec < Stmt > {
12701282 let mut statements = Vec :: new ( ) ;
1271- let mut index = open + 1 ;
12721283 while index < close {
12731284 if tokens[ index] . symbol ( "}" ) {
12741285 break ;
@@ -1281,15 +1292,58 @@ fn parse_block(tokens: &[Token], open: usize, close: usize) -> Block {
12811292 continue ;
12821293 }
12831294
1295+ if is_view_binding ( tokens, index, close) {
1296+ let span = tokens[ index] . span . clone ( ) ;
1297+ let ( binding, resource, after) = parse_view_header ( tokens, index, close) ;
1298+ // The remaining statements of the block are the view's scope.
1299+ let body = Block {
1300+ statements : collect_statements ( tokens, after, close) ,
1301+ span : span. clone ( ) ,
1302+ } ;
1303+ statements. push ( Stmt :: With ( WithStmt {
1304+ resource : resource. unwrap_or_else ( || Expr :: Unknown ( span. clone ( ) ) ) ,
1305+ binding,
1306+ body,
1307+ span,
1308+ } ) ) ;
1309+ break ;
1310+ }
1311+
12841312 let ( statement, next) = parse_stmt ( tokens, index, close) ;
12851313 statements. push ( statement) ;
12861314 index = next. max ( index + 1 ) ;
12871315 }
1316+ statements
1317+ }
12881318
1289- Block {
1290- statements,
1291- span : tokens[ open] . span . clone ( ) ,
1292- }
1319+ /// `view <ident> = ...` — a scoped-view binding (distinct from `view` used as an
1320+ /// ordinary identifier, which is never followed by `<ident> =`).
1321+ fn is_view_binding ( tokens : & [ Token ] , start : usize , limit : usize ) -> bool {
1322+ tokens[ start] . is_ident_text ( "view" )
1323+ && tokens
1324+ . get ( start + 1 )
1325+ . and_then ( ident_name)
1326+ . is_some_and ( |name| name != "=" )
1327+ && tokens. get ( start + 2 ) . is_some_and ( |token| token. symbol ( "=" ) )
1328+ && start + 2 < limit
1329+ }
1330+
1331+ /// Parse the `view <name> = <expr>` header, returning the binding name, the
1332+ /// resource expression, and the index just past the statement.
1333+ fn parse_view_header (
1334+ tokens : & [ Token ] ,
1335+ start : usize ,
1336+ limit : usize ,
1337+ ) -> ( String , Option < Expr > , usize ) {
1338+ let name = tokens
1339+ . get ( start + 1 )
1340+ . and_then ( ident_name)
1341+ . unwrap_or ( "" )
1342+ . to_string ( ) ;
1343+ let end = statement_end ( tokens, start, limit) ;
1344+ let equals = ( start + 2 ..end) . find ( |index| tokens[ * index] . symbol ( "=" ) ) ;
1345+ let resource = equals. and_then ( |equals| parse_expr ( tokens, equals + 1 , end) ) ;
1346+ ( name, resource, end)
12931347}
12941348
12951349fn parse_stmt ( tokens : & [ Token ] , start : usize , limit : usize ) -> ( Stmt , usize ) {
@@ -1488,7 +1542,10 @@ fn parse_let_stmt(tokens: &[Token], start: usize, limit: usize) -> (Stmt, usize)
14881542 // `let (a, b) = expr` destructures a tuple. The element names are recorded on
14891543 // the binding and expanded into a temporary plus per-element `let`s by the
14901544 // tuple desugar.
1491- if tokens. get ( name_index) . is_some_and ( |token| token. symbol ( "(" ) ) {
1545+ if tokens
1546+ . get ( name_index)
1547+ . is_some_and ( |token| token. symbol ( "(" ) )
1548+ {
14921549 return parse_let_tuple_stmt ( tokens, start, kind, name_index, limit) ;
14931550 }
14941551 let parsed_name = tokens. get ( name_index) . and_then ( ident_name) ;
@@ -2332,7 +2389,11 @@ fn split_match_pattern_guard(tokens: &[Token], start: usize, end: usize) -> Opti
23322389/// Parse a pattern head name: a bare identifier (`ADD`) or a module-qualified
23332390/// dotted name (`ops.ADD`, `a.b.Variant`). Returns the joined name and the token
23342391/// index just past it.
2335- fn parse_dotted_pattern_name ( tokens : & [ Token ] , start : usize , end : usize ) -> Option < ( String , usize ) > {
2392+ fn parse_dotted_pattern_name (
2393+ tokens : & [ Token ] ,
2394+ start : usize ,
2395+ end : usize ,
2396+ ) -> Option < ( String , usize ) > {
23362397 let mut name = ident_name ( tokens. get ( start) ?) ?. to_string ( ) ;
23372398 let mut index = start + 1 ;
23382399 while index + 1 < end
@@ -2552,14 +2613,11 @@ fn parse_list_pattern(tokens: &[Token], start: usize, end: usize) -> Option<Matc
25522613/// where `binding` is `None` for an ignored `..` (or `.._`) and `Some(name)`
25532614/// for `..name`. Returns `None` (the outer option) when the range is an ordinary
25542615/// element pattern. `..` may tokenise as one `..` token or two `.` tokens.
2555- fn parse_list_rest_segment (
2556- tokens : & [ Token ] ,
2557- start : usize ,
2558- end : usize ,
2559- ) -> Option < Option < String > > {
2616+ fn parse_list_rest_segment ( tokens : & [ Token ] , start : usize , end : usize ) -> Option < Option < String > > {
25602617 let dots_end = if tokens. get ( start) ?. symbol ( ".." ) {
25612618 start + 1
2562- } else if tokens. get ( start) ?. symbol ( "." ) && tokens. get ( start + 1 ) . is_some_and ( |t| t. symbol ( "." ) ) {
2619+ } else if tokens. get ( start) ?. symbol ( "." ) && tokens. get ( start + 1 ) . is_some_and ( |t| t. symbol ( "." ) )
2620+ {
25632621 start + 2
25642622 } else {
25652623 return None ;
0 commit comments