Changeset 1728
- Timestamp:
- 11/03/08 23:34:16 (2 months ago)
- Location:
- cobra/trunk
- Files:
-
- 2 added
- 3 modified
-
Developer/IntermediateReleaseNotes.text (modified) (1 diff)
-
Source/CobraParser.cobra (modified) (1 diff)
-
Source/Statements.cobra (modified) (5 diffs)
-
Tests/320-misc-two/810-multi-assignment/300-multiAssign-comma-sep.cobra (added)
-
Tests/320-misc-two/810-multi-assignment/310-multiAssign-comma-sep-fail.cobra (added)
Legend:
- Unmodified
- Added
- Removed
-
cobra/trunk/Developer/IntermediateReleaseNotes.text
r1720 r1728 31 31 %% error 'Cannot build this file till mondo-patch installed' 32 32 33 * Added support for "multi-arg assignment" which allows you to assign to a number of variables from contents of a list in one statement 33 * Added support for "multi-arg assignment" which allows you to assign to a number of variables from a compatible list of expressions in one statement 34 .code 35 a,b,c = 'val1', 999, c'\t' 36 d,e,f = 99+1, 100*1, 101-1 37 a,b = b,a # one line swap 38 or from contents of a list or array (any integer indexable item) in one statement 34 39 .code 35 40 a,b,c = ['val1', 'val2', 'val3'] 41 d,e,f = @[99, 100, 101] 36 42 Also support such assignment in for statements for (generic) dictionaries and lists 37 43 .code -
cobra/trunk/Source/CobraParser.cobra
r1723 r1728 2752 2752 .throwError('Comma-separated assignment targets must end with "=", or this is a general syntax error.') 2753 2753 assignTkn = .last to ! 2754 rhs = .expression 2755 return MultiTargetAssignStatement(assignTkn, args, rhs) 2754 rhs as Expr? = .expression 2755 if .optional('COMMA') 2756 rhsList = .commaSepExprs('EOL') 2757 assert .last.which=='EOL' 2758 .undo # need EOL 2759 rhsList.insert(0, rhs) 2760 rhs = nil 2761 return MultiTargetAssignStatement(assignTkn, args, rhs, rhsList) 2756 2762 2757 2763 def callExpr as Expr -
cobra/trunk/Source/Statements.cobra
r1716 r1728 1384 1384 pass 1385 1385 curCodeMember.hasYieldStmt = true 1386 1387 1386 1388 1387 class MultiTargetAssignStatement 1389 1388 is partial 1390 1389 inherits Stmt 1391 1390 """ 1392 Handle atatement of form 1393 a, b[,...] = <List> 1394 Gets turned into a sequence of assignExpr. 1395 a = <List>[0] 1396 b = <List>[1] 1397 1391 Handle statements of form 1392 a,[b,...] = <List-Generating-Expr> 1393 or 1394 a,[b,...] = <expr>,[<expr>,...] 1395 Gets turned into various sequences of assignExpr. 1396 tmp = <List-Generating-Expr> 1397 a = tmp[0] 1398 b = tmp[1] 1399 ... 1400 a = <expr> 1401 b = <expr> 1402 ... 1398 1403 TODO: support a, b[,...] = <Enumerable> 1399 1404 TODO: support a, b[,...] = <KeyValuePair|DictionaryEntry> 1400 TODO: support a, b[,...] = c,d[,...] form1401 1405 """ 1406 1402 1407 var _targets as List<of Expr> # Lvalues 1403 var _source as Expr # evaluate to IList/Array/String or otherwise indexable by int 1404 var _block as BlockStmt? # the rewritten/expanded code 1405 1406 def init(opToken as IToken, args as List<of Expr>, rhs as Expr) 1408 var _source as Expr? # evaluate to IList/Array/String or otherwise indexable by int 1409 var _rvals as List<of Expr>? # list of source expressions 1410 var _block as BlockStmt? # the rewritten/expanded code 1411 1412 def init(opToken as IToken, args as List<of Expr>, rhs as Expr?, rhsList as List<of Expr>?) 1407 1413 base.init(opToken) 1408 1414 assert opToken.which == 'ASSIGN' 1415 assert (rhs or rhsList) and not (rhs and rhsList) # either but not both 1409 1416 _targets = args 1410 1417 _source = rhs 1418 _rvals = rhsList 1411 1419 1412 1420 def addSubFields … … 1414 1422 .addField('targets', _targets) 1415 1423 .addField('source', _source) 1424 .addField('rvals', _rvals) 1416 1425 .addField('block', _block) 1417 1426 … … 1420 1429 get source from var 1421 1430 1431 get rvals from var 1432 1422 1433 get block from var 1423 1434 1424 def _writeBlock 1425 """ 1426 Construct expanded assignment block for a multi target assignment. 1435 def _bindImp 1436 assert _source or _rvals 1437 base._bindImp 1438 for target in _targets 1439 if not _isLValue(target) 1440 .throwError('"[target.toCobraSource]" is not an assignable lvalue (identifier, var, property or indexer).') 1441 if _rvals 1442 if _targets.count <> _rvals.count 1443 .throwError('The number of targets ([_targets.count]) must be the same as the number of expressions ([_rvals.count]) assigned to them') 1444 #If rvals are all safe to assign (no rerefs) we can do the simplest thing and turn 1445 # them into a sequence of individual assignments. i.e a,b = 1,2 or a,b = c,d cases 1446 # If not, we need to turn the rvals list into a literal list, pinning the current values, 1447 # and do the expansion on the list as a single item i.e a,b = b,a -> a,b = [b,a] 1448 if _isSafeToSimpleAssign() 1449 _writeBlockForList 1450 else 1451 _source = ListLit(.lastToken.copy('LBRACKET', r'['), _rvals) 1452 if _source 1453 #TODO: chk _source supports an int indexer somehow... 1454 #if not .can_be_indexed_by_int_indexer(_source) 1455 # .throwError(r"rhs expression [_source.toCobraSource] must support being indexed by an integer offset (e.g rhs[0]") 1456 _writeBlockForItem 1457 1458 _block.bindImp 1459 1460 def _isLValue(id as Expr) as bool 1461 # TODO: push to Expr.isLValue. probably require .didBindImp 1462 # TODO: for DotExpr and IndexExpr check if there is a setter 1463 # TODO: for MemberExpr check that its a setter property or visible var (not a method) 1464 return id inherits IdentifierExpr or id inherits DotExpr or id inherits IndexExpr 1465 1466 def _isSafeToSimpleAssign as bool 1467 # conservatively we just presume its safe if the rvals list is all Literals 1468 if all for e in _rvals get e inherits Literal 1469 return true 1470 # or if identifiers in rvals are not also in target 1471 if _disjointIdentifierLists() 1472 return true 1473 # There are possibly others but above expected to be most common usage 1474 # TODO: expand this for more wide ranging simple assignment e.g MemberExprs non matching 1475 return false 1476 1477 def _disjointIdentifierLists as bool 1478 # Specifically all of targets list are IdentifierExprs and rvals are Literals, DotExprs, 1479 # MemberExprs or Indentifiers and any Identifiers are not also in target list 1480 tnames = Set<of String>() 1481 for t in _targets 1482 if t inherits IdentifierExpr or t inherits AsExpr 1483 tnames.add((t to NameExpr).name) 1484 else 1485 return false 1486 if all for e in _rvals get e inherits Literal or e inherits DotExpr or e inherits MemberExpr or _ 1487 (e inherits IdentifierExpr and (e to IdentifierExpr).name not in tnames) 1488 return true 1489 return false 1490 1491 def _writeBlockForList 1492 """ 1493 Construct expanded assignment block for a multi target assignment from a list of expressions. 1494 Assignment block contains 1495 id0 = rvals[0] # id0 is contents of targets[0] 1496 id1 = rvals[1] # id1 is contents of targets[1] 1497 (... repeated for number of items in targets specifying ids (lvalues)) 1498 """ 1499 assert _targets.count == _rvals.count 1500 stmts = List<of Stmt>() 1501 assignTkn = .lastToken # the one we stored in init 1502 count = 0 1503 for id in _targets 1504 expr = _rvals[count] 1505 stmts.add(AssignExpr(assignTkn, assignTkn.which, id, expr)) 1506 count += 1 1507 _block = BlockStmt(.lastToken.copy('INDENT', ''), stmts) 1508 1509 def _writeBlockForItem 1510 """ 1511 Construct expanded assignment block for a multi target assignment from a single source expression. 1427 1512 if fewer targets than exprs in _source - extra exprs (silently) ignored 1428 1513 TODO: give error when rvalues are too many … … 1430 1515 above differ fm python - both give errors 1431 1516 Unchecked assumptions; 1432 source is int indexable (x[n]) - c# compiler pick up 1517 source is int indexable (x[n]) - c# compiler pick up currently 1433 1518 Assignment block contains 1434 1519 lh_mt_serno = <source> … … 1460 1545 count += 1 1461 1546 _block = BlockStmt(ttoken.copy('INDENT', ''), stmts) 1462 1463 def _isLValue(id as Expr) as bool1464 # TODO: push to Expr.isLValue. probably require .didBindImp1465 # TODO: for DotExpr and IndexExpr check if there is a setter1466 # TODO: for MemberExpr check that its a setter property or visible var (not a method)1467 return id inherits IdentifierExpr or id inherits DotExpr or id inherits IndexExpr1468 1469 def _bindImp1470 base._bindImp1471 for target in _targets1472 if not _isLValue(target)1473 .throwError('"[target.toCobraSource]" is not an assignable lvalue (identifier, var, property or indexer).')1474 # TODO: check _source supports an int indexer ??1475 _writeBlock1476 _block.bindImp
