Changes in src/AST/Convert.cpp [19e567dd:514a791]
- File:
-
- 1 edited
-
src/AST/Convert.cpp (modified) (26 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Convert.cpp
r19e567dd r514a791 10 10 // Created On : Thu May 09 15::37::05 2019 11 11 // Last Modified By : Andrew Beach 12 // Last Modified On : Fri May 17 16:01:00 201913 // Update Count : 412 // Last Modified On : Tue May 21 15:30:00 2019 13 // Update Count : 5 14 14 // 15 15 16 16 #include "Convert.hpp" 17 18 #include <unordered_map> 17 19 18 20 #include "AST/Attribute.hpp" … … 42 44 class ConverterNewToOld : public ast::Visitor { 43 45 BaseSyntaxNode * node = nullptr; 46 std::unordered_map< ast::Node *, BaseSyntaxNode * > cache; 44 47 45 48 template<typename T> … … 47 50 ConverterNewToOld & visitor; 48 51 49 template<typename U> 50 T * accept1( const ast::ptr<U> & ptr ) { 52 template<typename U, enum ast::Node::ref_type R> 53 T * accept1( const ast::ptr_base<U, R> & ptr ) { 54 if ( ! ptr ) return nullptr; 51 55 ptr->accept( visitor ); 52 56 T * ret = strict_dynamic_cast< T * >( visitor.node ); … … 87 91 } 88 92 93 /// get new qualifiers from old type 94 Type::Qualifiers cv( const ast::Type * ty ) { return { ty->qualifiers.val }; } 95 96 template<typename NewT, typename OldT> 97 NewT * cached( const OldT & old ) { 98 auto it = cache.find( old.get() ); 99 if ( it == cache.end() ) { 100 // doesn't update cache, that should be handled by the accept function 101 return get< NewT >().accept1( old ); 102 } else { 103 return strict_dynamic_cast< NewT * >( it->second ); 104 } 105 } 106 89 107 public: 90 108 Declaration * decl( const ast::Decl * declNode ) { … … 93 111 94 112 private: 113 void declPostamble( Declaration * decl, const ast::Decl * node ) { 114 decl->location = node->location; 115 // name comes from constructor 116 // linkage comes from constructor 117 decl->extension = node->extension; 118 decl->uniqueId = node->uniqueId; 119 // storageClasses comes from constructor 120 this->node = decl; 121 } 122 123 const ast::DeclWithType * declWithTypePostamble ( 124 DeclarationWithType * decl, const ast::DeclWithType * node ) { 125 declPostamble( decl, node ); 126 decl->mangleName = node->mangleName; 127 decl->scopeLevel = node->scopeLevel; 128 decl->asmName = get<Expression>().accept1( node->asmName ); 129 // attributes comes from constructor 130 decl->isDeleted = node->isDeleted; 131 // fs comes from constructor 132 return nullptr; 133 } 134 95 135 const ast::DeclWithType * visit( const ast::ObjectDecl * node ) override final { 96 (void)node; 97 return nullptr; 136 auto decl = new ObjectDecl( 137 node->name, 138 Type::StorageClasses( node->storage.val ), 139 LinkageSpec::Spec( node->linkage.val ), 140 get<Expression>().accept1( node->bitfieldWidth ), 141 get<Type>().accept1( node->type ), 142 get<Initializer>().accept1( node->init ), 143 get<Attribute>().acceptL( node->attributes ), 144 Type::FuncSpecifiers( node->funcSpec.val ) 145 ); 146 return declWithTypePostamble( decl, node ); 98 147 } 99 148 100 149 const ast::DeclWithType * visit( const ast::FunctionDecl * node ) override final { 101 (void)node; 150 auto decl = new FunctionDecl( 151 node->name, 152 Type::StorageClasses( node->storage.val ), 153 LinkageSpec::Spec( node->linkage.val ), 154 get<FunctionType>().accept1( node->type ), 155 get<CompoundStmt>().accept1( node->stmts ), 156 get<Attribute>().acceptL( node->attributes ), 157 Type::FuncSpecifiers( node->funcSpec.val ) 158 ); 159 decl->withExprs = get<Expression>().acceptL( node->withExprs ); 160 return declWithTypePostamble( decl, node ); 161 } 162 163 // NamedTypeDecl 164 const ast::Decl * namedTypePostamble( NamedTypeDecl * decl, const ast::NamedTypeDecl * node ) { 165 declPostamble( decl, node ); 166 // base comes from constructor 167 decl->parameters = get<TypeDecl>().acceptL( node->params ); 168 decl->assertions = get<DeclarationWithType>().acceptL( node->assertions ); 169 return nullptr; 170 } 171 172 const ast::Decl * visit( const ast::TypeDecl * node ) override final { 173 TypeDecl::Kind kind; 174 switch (node->kind) { 175 case ast::TypeVar::Dtype: 176 kind = TypeDecl::Dtype; 177 break; 178 case ast::TypeVar::Ftype: 179 kind = TypeDecl::Ftype; 180 break; 181 case ast::TypeVar::Ttype: 182 kind = TypeDecl::Ttype; 183 break; 184 default: 185 assertf(false, "Invalid ast::TypeVar::Kind: %d\n", node->kind); 186 }; 187 auto decl = new TypeDecl( 188 node->name, 189 Type::StorageClasses( node->storage.val ), 190 get<Type>().accept1( node->base ), 191 kind, 192 node->sized, 193 get<Type>().accept1( node->init ) 194 ); 195 return namedTypePostamble( decl, node ); 196 } 197 198 const ast::Decl * visit( const ast::TypedefDecl * node ) override final { 199 auto decl = new TypedefDecl( 200 node->name, 201 node->location, 202 Type::StorageClasses( node->storage.val ), 203 get<Type>().accept1( node->base ), 204 LinkageSpec::Spec( node->linkage.val ) 205 ); 206 return namedTypePostamble( decl, node ); 207 } 208 209 const ast::Decl * aggregatePostamble( AggregateDecl * decl, const ast::AggregateDecl * node ) { 210 decl->members = get<Declaration>().acceptL( node->members ); 211 decl->parameters = get<TypeDecl>().acceptL( node->params ); 212 decl->body = node->body; 213 // attributes come from constructor 214 // TODO: Need caching for: decl->parent = node->parent; 102 215 return nullptr; 103 216 } 104 217 105 218 const ast::Decl * visit( const ast::StructDecl * node ) override final { 106 (void)node; 107 return nullptr; 219 auto decl = new StructDecl( 220 node->name, 221 node->kind, 222 get<Attribute>().acceptL( node->attributes ), 223 LinkageSpec::Spec( node->linkage.val ) 224 ); 225 return aggregatePostamble( decl, node ); 108 226 } 109 227 110 228 const ast::Decl * visit( const ast::UnionDecl * node ) override final { 111 (void)node; 112 return nullptr; 229 auto decl = new UnionDecl( 230 node->name, 231 get<Attribute>().acceptL( node->attributes ), 232 LinkageSpec::Spec( node->linkage.val ) 233 ); 234 return aggregatePostamble( decl, node ); 113 235 } 114 236 115 237 const ast::Decl * visit( const ast::EnumDecl * node ) override final { 116 (void)node; 117 return nullptr; 238 auto decl = new EnumDecl( 239 node->name, 240 get<Attribute>().acceptL( node->attributes ), 241 LinkageSpec::Spec( node->linkage.val ) 242 ); 243 return aggregatePostamble( decl, node ); 118 244 } 119 245 120 246 const ast::Decl * visit( const ast::TraitDecl * node ) override final { 121 (void)node; 122 return nullptr; 123 } 124 125 const ast::Decl * visit( const ast::TypeDecl * node ) override final { 126 (void)node; 127 return nullptr; 128 } 129 130 const ast::Decl * visit( const ast::TypedefDecl * node ) override final { 131 (void)node; 132 return nullptr; 247 auto decl = new TraitDecl( 248 node->name, 249 {}, 250 LinkageSpec::Spec( node->linkage.val ) 251 ); 252 return aggregatePostamble( decl, node ); 133 253 } 134 254 135 255 const ast::AsmDecl * visit( const ast::AsmDecl * node ) override final { 136 (void)node; 256 auto decl = new AsmDecl( get<AsmStmt>().accept1( node->stmt ) ); 257 declPostamble( decl, node ); 137 258 return nullptr; 138 259 } 139 260 140 261 const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * node ) override final { 141 (void)node; 142 return nullptr; 143 } 144 145 const ast::CompoundStmt * visit( const ast::CompoundStmt * node ) override final { 146 auto stmt = new CompoundStmt( get<Statement>().acceptL( node->kids ) ); 262 auto decl = new StaticAssertDecl( 263 get<Expression>().accept1( node->cond ), 264 get<ConstantExpr>().accept1( node->msg ) 265 ); 266 declPostamble( decl, node ); 267 return nullptr; 268 } 269 270 const ast::Stmt * stmtPostamble( Statement * stmt, const ast::Stmt * node ) { 147 271 stmt->location = node->location; 148 272 stmt->labels = makeLabelL( stmt, node->labels ); … … 151 275 } 152 276 277 const ast::CompoundStmt * visit( const ast::CompoundStmt * node ) override final { 278 auto stmt = new CompoundStmt( get<Statement>().acceptL( node->kids ) ); 279 stmtPostamble( stmt, node ); 280 return nullptr; 281 } 282 153 283 const ast::Stmt * visit( const ast::ExprStmt * node ) override final { 154 284 auto stmt = new ExprStmt( get<Expression>().accept1( node->expr ) ); 155 stmt->location = node->location; 156 stmt->labels = makeLabelL( stmt, node->labels ); 157 this->node = stmt; 158 return nullptr; 285 return stmtPostamble( stmt, node ); 159 286 } 160 287 … … 168 295 makeLabelL( nullptr, node->gotoLabels ) // What are these labelling? 169 296 ); 170 stmt->location = node->location; 171 stmt->labels = makeLabelL( stmt, node->labels ); 172 this->node = stmt; 173 return nullptr; 297 return stmtPostamble( stmt, node ); 174 298 } 175 299 176 300 const ast::Stmt * visit( const ast::DirectiveStmt * node ) override final { 177 301 auto stmt = new DirectiveStmt( node->directive ); 178 stmt->location = node->location; 179 stmt->labels = makeLabelL( stmt, node->labels ); 180 this->node = stmt; 181 return nullptr; 302 return stmtPostamble( stmt, node ); 182 303 } 183 304 … … 189 310 get<Statement>().acceptL( node->inits ) 190 311 ); 191 stmt->location = node->location; 192 stmt->labels = makeLabelL( stmt, node->labels ); 193 this->node = stmt; 194 return nullptr; 312 return stmtPostamble( stmt, node ); 195 313 } 196 314 … … 200 318 get<Statement>().acceptL( node->stmts ) 201 319 ); 202 stmt->location = node->location; 203 stmt->labels = makeLabelL( stmt, node->labels ); 204 this->node = stmt; 205 return nullptr; 320 return stmtPostamble( stmt, node ); 206 321 } 207 322 … … 212 327 node->isDefault() 213 328 ); 214 stmt->location = node->location; 215 stmt->labels = makeLabelL( stmt, node->labels ); 216 this->node = stmt; 217 return nullptr; 329 return stmtPostamble( stmt, node ); 218 330 } 219 331 … … 226 338 node->isDoWhile 227 339 ); 228 stmt->location = node->location; 229 stmt->labels = makeLabelL( stmt, node->labels ); 230 this->node = stmt; 231 return nullptr; 340 return stmtPostamble( stmt, node ); 232 341 } 233 342 … … 239 348 get<Statement>().accept1( node->body ) 240 349 ); 241 stmt->location = node->location; 242 stmt->labels = makeLabelL( stmt, node->labels ); 243 this->node = stmt; 244 return nullptr; 350 return stmtPostamble( stmt, node ); 245 351 } 246 352 … … 271 377 stmt->target = makeLabel( stmt, node->target ); 272 378 } 273 stmt->location = node->location; 274 stmt->labels = makeLabelL( stmt, node->labels ); 275 this->node = stmt; 276 return nullptr; 379 return stmtPostamble( stmt, node ); 277 380 } 278 381 279 382 const ast::Stmt * visit( const ast::ReturnStmt * node ) override final { 280 383 auto stmt = new ReturnStmt( get<Expression>().accept1( node->expr ) ); 281 stmt->location = node->location; 282 stmt->labels = makeLabelL( stmt, node->labels ); 283 this->node = stmt; 284 return nullptr; 384 return stmtPostamble( stmt, node ); 285 385 } 286 386 … … 302 402 get<Expression>().accept1( node->target ) 303 403 ); 304 stmt->location = node->location; 305 stmt->labels = makeLabelL( stmt, node->labels ); 306 this->node = stmt; 307 return nullptr; 404 return stmtPostamble( stmt, node ); 308 405 } 309 406 … … 315 412 get<FinallyStmt>().accept1( node->finally ) 316 413 ); 317 stmt->location = node->location; 318 stmt->labels = makeLabelL( stmt, node->labels ); 319 this->node = stmt; 320 return nullptr; 414 return stmtPostamble( stmt, node ); 321 415 } 322 416 … … 339 433 get<Statement>().accept1( node->body ) 340 434 ); 341 stmt->location = node->location; 342 stmt->labels = makeLabelL( stmt, node->labels ); 343 this->node = stmt; 344 return nullptr; 435 return stmtPostamble( stmt, node ); 345 436 } 346 437 347 438 const ast::Stmt * visit( const ast::FinallyStmt * node ) override final { 348 439 auto stmt = new FinallyStmt( get<CompoundStmt>().accept1( node->body ) ); 349 stmt->location = node->location; 350 stmt->labels = makeLabelL( stmt, node->labels ); 351 this->node = stmt; 352 return nullptr; 440 return stmtPostamble( stmt, node ); 353 441 } 354 442 … … 358 446 for ( auto clause : node->clauses ) { 359 447 stmt->clauses.push_back({{ 360 get<Expression>().accept1( clause.target.func tion),361 get<Expression>().acceptL( clause.target.arg uments ),448 get<Expression>().accept1( clause.target.func ), 449 get<Expression>().acceptL( clause.target.args ), 362 450 }, 363 451 get<Statement>().accept1( clause.stmt ), … … 374 462 get<Expression>().accept1( node->orElse.cond ), 375 463 }; 376 stmt->location = node->location; 377 stmt->labels = makeLabelL( stmt, node->labels ); 378 this->node = stmt; 379 return nullptr; 464 return stmtPostamble( stmt, node ); 380 465 } 381 466 … … 385 470 get<Statement>().accept1( node->stmt ) 386 471 ); 387 stmt->location = node->location; 388 stmt->labels = makeLabelL( stmt, node->labels ); 389 this->node = stmt; 390 return nullptr; 472 return stmtPostamble( stmt, node ); 391 473 } 392 474 393 475 const ast::NullStmt * visit( const ast::NullStmt * node ) override final { 394 476 auto stmt = new NullStmt(); 395 stmt->location = node->location; 396 stmt->labels = makeLabelL( stmt, node->labels ); 397 this->node = stmt; 477 stmtPostamble( stmt, node ); 398 478 return nullptr; 399 479 } … … 401 481 const ast::Stmt * visit( const ast::DeclStmt * node ) override final { 402 482 auto stmt = new DeclStmt( get<Declaration>().accept1( node->decl ) ); 403 stmt->location = node->location; 404 stmt->labels = makeLabelL( stmt, node->labels ); 405 this->node = stmt; 406 return nullptr; 483 return stmtPostamble( stmt, node ); 407 484 } 408 485 … … 670 747 671 748 const ast::Type * visit( const ast::VoidType * node ) override final { 672 (void)node;749 this->node = new VoidType{ cv( node ) }; 673 750 return nullptr; 674 751 } 675 752 676 753 const ast::Type * visit( const ast::BasicType * node ) override final { 677 (void)node;754 this->node = new BasicType{ cv( node ), (BasicType::Kind)(unsigned)node->kind }; 678 755 return nullptr; 679 756 } 680 757 681 758 const ast::Type * visit( const ast::PointerType * node ) override final { 682 (void)node; 759 this->node = new PointerType{ 760 cv( node ), 761 get<Type>().accept1( node->base ), 762 get<Expression>().accept1( node->dimension ), 763 node->isVarLen, 764 node->isStatic 765 }; 683 766 return nullptr; 684 767 } 685 768 686 769 const ast::Type * visit( const ast::ArrayType * node ) override final { 687 (void)node; 770 this->node = new ArrayType{ 771 cv( node ), 772 get<Type>().accept1( node->base ), 773 get<Expression>().accept1( node->dimension ), 774 node->isVarLen, 775 node->isStatic 776 }; 688 777 return nullptr; 689 778 } 690 779 691 780 const ast::Type * visit( const ast::ReferenceType * node ) override final { 692 (void)node; 781 this->node = new ReferenceType{ 782 cv( node ), 783 get<Type>().accept1( node->base ) 784 }; 693 785 return nullptr; 694 786 } 695 787 696 788 const ast::Type * visit( const ast::QualifiedType * node ) override final { 697 (void)node; 789 this->node = new QualifiedType{ 790 cv( node ), 791 get<Type>().accept1( node->parent ), 792 get<Type>().accept1( node->child ) 793 }; 698 794 return nullptr; 699 795 } 700 796 701 797 const ast::Type * visit( const ast::FunctionType * node ) override final { 702 (void)node; 798 auto ty = new FunctionType { cv( node ), node->isVarArgs }; 799 ty->returnVals = get<DeclarationWithType>().acceptL( node->returns ); 800 ty->parameters = get<DeclarationWithType>().acceptL( node->params ); 801 ty->forall = get<TypeDecl>().acceptL( node->forall ); 802 this->node = ty; 703 803 return nullptr; 704 804 } … … 808 908 } 809 909 private: 910 /// conversion output 810 911 ast::Node * node; 912 /// cache of nodes that might be referenced by readonly<> for de-duplication 913 std::unordered_map< BaseSyntaxNode *, ast::Node * > cache; 811 914 812 915 // Local Utilities: … … 814 917 template<typename NewT, typename OldT> 815 918 NewT * getAccept1( OldT old ) { 919 if ( ! old ) return nullptr; 816 920 old->accept(*this); 817 921 return strict_dynamic_cast< NewT * >( node ); … … 854 958 # define GET_LABELS_V(labels) \ 855 959 to<std::vector>::from( make_labels( std::move( labels ) ) ) 960 961 static ast::CV::Qualifiers cv( Type * ty ) { return { ty->get_qualifiers().val }; } 962 963 template<typename NewT, typename OldT> 964 NewT * cached( OldT * old ) { 965 auto it = cache.find( old ); 966 // doesn't update cache, that should be handled by the accept function 967 ast::Node * nw = it == cache.end() ? getAccept1< NewT >( old ) : it->second; 968 return strict_dynamic_cast< NewT * >( nw ); 969 } 856 970 857 971 // Now all the visit functions: … … 1260 1374 } 1261 1375 1262 void convertInferUnion(ast::Expr::InferUnion &newInferred, 1376 void convertInferUnion(ast::Expr::InferUnion &newInferred, 1263 1377 const std::map<UniqueId,ParamEntry> &oldInferParams, 1264 1378 const std::vector<UniqueId> &oldResnSlots) { … … 1467 1581 } 1468 1582 1469 virtual void visit( VoidType * ) override final { 1470 1471 } 1472 1473 virtual void visit( BasicType * ) override final { 1474 1475 } 1476 1477 virtual void visit( PointerType * ) override final { 1478 1479 } 1480 1481 virtual void visit( ArrayType * ) override final { 1482 1483 } 1484 1485 virtual void visit( ReferenceType * ) override final { 1486 1487 } 1488 1489 virtual void visit( QualifiedType * ) override final { 1490 1491 } 1492 1493 virtual void visit( FunctionType * ) override final { 1494 1495 } 1496 1497 virtual void visit( StructInstType * ) override final { 1498 1499 } 1500 1501 virtual void visit( UnionInstType * ) override final { 1502 1503 } 1504 1505 virtual void visit( EnumInstType * ) override final { 1506 1507 } 1508 1509 virtual void visit( TraitInstType * ) override final { 1510 1511 } 1512 1513 virtual void visit( TypeInstType * ) override final { 1514 1583 virtual void visit( VoidType * old ) override final { 1584 this->node = new ast::VoidType{ cv( old ) }; 1585 } 1586 1587 virtual void visit( BasicType * old ) override final { 1588 this->node = new ast::BasicType{ (ast::BasicType::Kind)(unsigned)old->kind, cv( old ) }; 1589 } 1590 1591 virtual void visit( PointerType * old ) override final { 1592 this->node = new ast::PointerType{ 1593 GET_ACCEPT_1( base, Type ), 1594 GET_ACCEPT_1( dimension, Expr ), 1595 (ast::LengthFlag)old->isVarLen, 1596 (ast::DimensionFlag)old->isStatic, 1597 cv( old ) 1598 }; 1599 } 1600 1601 virtual void visit( ArrayType * old ) override final { 1602 this->node = new ast::ArrayType{ 1603 GET_ACCEPT_1( base, Type ), 1604 GET_ACCEPT_1( dimension, Expr ), 1605 (ast::LengthFlag)old->isVarLen, 1606 (ast::DimensionFlag)old->isStatic, 1607 cv( old ) 1608 }; 1609 } 1610 1611 virtual void visit( ReferenceType * old ) override final { 1612 this->node = new ast::ReferenceType{ 1613 GET_ACCEPT_1( base, Type ), 1614 cv( old ) 1615 }; 1616 } 1617 1618 virtual void visit( QualifiedType * old ) override final { 1619 this->node = new ast::QualifiedType{ 1620 GET_ACCEPT_1( parent, Type ), 1621 GET_ACCEPT_1( child, Type ), 1622 cv( old ) 1623 }; 1624 } 1625 1626 virtual void visit( FunctionType * old ) override final { 1627 auto ty = new ast::FunctionType { 1628 (ast::ArgumentFlag)old->isVarArgs, 1629 cv( old ) 1630 }; 1631 ty->returns = GET_ACCEPT_V( returnVals, DeclWithType ); 1632 ty->params = GET_ACCEPT_V( parameters, DeclWithType ); 1633 ty->forall = GET_ACCEPT_V( forall, TypeDecl ); 1634 this->node = ty; 1635 } 1636 1637 void postvisit( ReferenceToType * old, ast::ReferenceToType * ty ) { 1638 ty->forall = GET_ACCEPT_V( forall, TypeDecl ); 1639 ty->params = GET_ACCEPT_V( parameters, Expr ); 1640 ty->hoistType = old->hoistType; 1641 } 1642 1643 virtual void visit( StructInstType * old ) override final { 1644 auto ty = new ast::StructInstType{ 1645 cached< ast::StructDecl >( old->baseStruct ), 1646 cv( old ), 1647 GET_ACCEPT_V( attributes, Attribute ) 1648 }; 1649 postvisit( old, ty ); 1650 this->node = ty; 1651 } 1652 1653 virtual void visit( UnionInstType * old ) override final { 1654 auto ty = new ast::UnionInstType{ 1655 cached< ast::UnionDecl >( old->baseUnion ), 1656 cv( old ), 1657 GET_ACCEPT_V( attributes, Attribute ) 1658 }; 1659 postvisit( old, ty ); 1660 this->node = ty; 1661 } 1662 1663 virtual void visit( EnumInstType * old ) override final { 1664 auto ty = new ast::EnumInstType{ 1665 cached< ast::EnumDecl >( old->baseEnum ), 1666 cv( old ), 1667 GET_ACCEPT_V( attributes, Attribute ) 1668 }; 1669 postvisit( old, ty ); 1670 this->node = ty; 1671 } 1672 1673 virtual void visit( TraitInstType * old ) override final { 1674 auto ty = new ast::TraitInstType{ 1675 cached< ast::TraitDecl >( old->baseTrait ), 1676 cv( old ), 1677 GET_ACCEPT_V( attributes, Attribute ) 1678 }; 1679 postvisit( old, ty ); 1680 this->node = ty; 1681 } 1682 1683 virtual void visit( TypeInstType * old ) override final { 1684 ast::TypeInstType * ty; 1685 if ( old->baseType ) { 1686 ty = new ast::TypeInstType{ 1687 old->name, 1688 cached< ast::TypeDecl >( old->baseType ), 1689 cv( old ), 1690 GET_ACCEPT_V( attributes, Attribute ) 1691 }; 1692 } else { 1693 ty = new ast::TypeInstType{ 1694 old->name, 1695 old->isFtype ? ast::TypeVar::Ftype : ast::TypeVar::Dtype, 1696 cv( old ), 1697 GET_ACCEPT_V( attributes, Attribute ) 1698 }; 1699 } 1700 postvisit( old, ty ); 1701 this->node = ty; 1515 1702 } 1516 1703
Note:
See TracChangeset
for help on using the changeset viewer.