Changeset 54e41b3 for src/AST/Expr.hpp
- Timestamp:
- May 16, 2019, 1:46:28 PM (5 years ago)
- Branches:
- ADT, arm-eh, ast-experimental, cleanup-dtors, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, pthread-emulation, qualifiedEnum
- Children:
- 24afc53
- Parents:
- 89c2f7c9
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
src/AST/Expr.hpp
r89c2f7c9 r54e41b3 18 18 #include <cassert> 19 19 #include <map> 20 #include <string> 20 21 #include <utility> // for move 21 22 #include <vector> 22 23 23 24 #include "Fwd.hpp" // for UniqueId 25 #include "Label.hpp" 24 26 #include "ParseNode.hpp" 25 27 #include "Visitor.hpp" … … 117 119 bool extension = false; 118 120 119 Expr(const CodeLocation & loc ) : ParseNode( loc ), result(), env(), inferred() {} 121 Expr( const CodeLocation & loc, const Type * res = nullptr ) 122 : ParseNode( loc ), result( res ), env(), inferred() {} 120 123 121 124 Expr * set_extension( bool ex ) { extension = ex; return this; } … … 124 127 private: 125 128 Expr * clone() const override = 0; 129 }; 130 131 /// The application of a function to a set of parameters. 132 /// Post-resolver form of `UntypedExpr` 133 class ApplicationExpr final : public Expr { 134 public: 135 ptr<Expr> func; 136 std::vector<ptr<Expr>> args; 137 138 ApplicationExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} ); 139 140 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 141 private: 142 ApplicationExpr * clone() const override { return new ApplicationExpr{ *this }; } 143 }; 144 145 /// The application of a function to a set of parameters, pre-overload resolution. 146 class UntypedExpr final : public Expr { 147 public: 148 ptr<Expr> func; 149 std::vector<ptr<Expr>> args; 150 151 UntypedExpr( const CodeLocation & loc, const Expr * f, std::vector<ptr<Expr>> && as = {} ) 152 : Expr( loc ), func( f ), args( std::move(as) ) {} 153 154 /// Creates a new dereference expression 155 static UntypedExpr * createDeref( const CodeLocation & loc, Expr * arg ); 156 /// Creates a new assignment expression 157 static UntypedExpr * createAssign( const CodeLocation & loc, Expr * lhs, Expr * rhs ); 158 159 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 160 private: 161 UntypedExpr * clone() const override { return new UntypedExpr{ *this }; } 162 }; 163 164 /// A name whose name is as-yet undetermined. 165 /// May also be used to avoid name mangling in codegen phase. 166 class NameExpr final : public Expr { 167 public: 168 std::string name; 169 170 NameExpr( const CodeLocation & loc, const std::string & n ) : Expr( loc ), name( n ) {} 171 172 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 173 private: 174 NameExpr * clone() const override { return new NameExpr{ *this }; } 175 }; 176 177 /// Address-of expression `&e` 178 class AddressExpr final : public Expr { 179 public: 180 ptr<Expr> arg; 181 182 AddressExpr( const CodeLocation & loc, const Expr * a ); 183 184 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 185 private: 186 AddressExpr * clone() const override { return new AddressExpr{ *this }; } 187 }; 188 189 /// GCC &&label 190 /// https://gcc.gnu.org/onlinedocs/gcc-3.4.2/gcc/Labels-as-Values.html 191 class LabelAddressExpr final : public Expr { 192 public: 193 Label arg; 194 195 LabelAddressExpr( const CodeLocation & loc, Label && a ); 196 197 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 198 private: 199 LabelAddressExpr * clone() const override { return new LabelAddressExpr{ *this }; } 200 }; 201 202 /// Whether a cast existed in the program source or not 203 enum GeneratedFlag { ExplicitCast, GeneratedCast }; 204 205 /// A type cast, e.g. `(int)e` 206 class CastExpr final : public Expr { 207 public: 208 ptr<Expr> arg; 209 GeneratedFlag isGenerated; 210 211 CastExpr( const CodeLocation & loc, const Expr * a, const Type * to, 212 GeneratedFlag g = GeneratedCast ) : Expr( loc, to ), arg( a ), isGenerated( g ) {} 213 /// Cast-to-void 214 CastExpr( const CodeLocation & loc, const Expr * a, GeneratedFlag g = GeneratedCast ); 215 216 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 217 private: 218 CastExpr * clone() const override { return new CastExpr{ *this }; } 219 }; 220 221 /// A cast to "keyword types", e.g. `(thread &)t` 222 class KeywordCastExpr final : public Expr { 223 public: 224 ptr<Expr> arg; 225 enum Target { Coroutine, Thread, Monitor, NUMBER_OF_TARGETS } target; 226 227 KeywordCastExpr( const CodeLocation & loc, const Expr * a, Target t ) 228 : Expr( loc ), arg( a ), target( t ) {} 229 230 /// Get a name for the target type 231 const std::string& targetString() const; 232 233 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 234 private: 235 KeywordCastExpr * clone() const override { return new KeywordCastExpr{ *this }; } 236 }; 237 238 /// A virtual dynamic cast, e.g. `(virtual exception)e` 239 class VirtualCastExpr final : public Expr { 240 public: 241 ptr<Expr> arg; 242 243 VirtualCastExpr( const CodeLocation & loc, const Expr * a, const Type * to ) 244 : Expr( loc, to ), arg( a ) {} 245 246 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 247 private: 248 VirtualCastExpr * clone() const override { return new VirtualCastExpr{ *this }; } 249 }; 250 251 /// A member selection operation before expression resolution, e.g. `q.p` 252 class UntypedMemberExpr final : public Expr { 253 public: 254 ptr<Expr> member; 255 ptr<Expr> aggregate; 256 257 UntypedMemberExpr( const CodeLocation & loc, const Expr * mem, const Expr * agg ) 258 : Expr( loc ), member( mem ), aggregate( agg ) { assert( aggregate ); } 259 260 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 261 private: 262 UntypedMemberExpr * clone() const override { return new UntypedMemberExpr{ *this }; } 263 }; 264 265 /// A member selection operation after expression resolution, e.g. `q.p` 266 class MemberExpr final : public Expr { 267 public: 268 readonly<DeclWithType> member; 269 ptr<Expr> aggregate; 270 271 MemberExpr( const CodeLocation & loc, const DeclWithType * mem, const Expr * agg ); 272 273 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 274 private: 275 MemberExpr * clone() const override { return new MemberExpr{ *this }; } 276 }; 277 278 /// A reference to a named variable. 279 class VariableExpr final : public Expr { 280 public: 281 readonly<DeclWithType> var; 282 283 VariableExpr( const CodeLocation & loc, const DeclWithType * v ); 284 285 /// generates a function pointer for a given function 286 static VariableExpr * functionPointer( const CodeLocation & loc, const FunctionDecl * decl ); 287 288 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 289 private: 290 VariableExpr * clone() const override { return new VariableExpr{ *this }; } 291 }; 292 293 /// A compile-time constant 294 class ConstantExpr final : public Expr { 295 union Val { 296 unsigned long long ival; 297 double dval; 298 299 Val( unsigned long long i ) : ival( i ) {} 300 Val( double d ) : dval( d ) {} 301 } val; 302 public: 303 std::string rep; 304 305 ConstantExpr( 306 const CodeLocation & loc, const Type * ty, const std::string & r, unsigned long long v ) 307 : Expr( loc, ty ), val( v ), rep( r ) {} 308 ConstantExpr( const CodeLocation & loc, const Type * ty, const std::string & r, double v ) 309 : Expr( loc, ty ), val( v ), rep( r ) {} 310 311 /// Gets the value of this constant as an integer 312 long long int intValue() const; 313 /// Gets the value of this constant as floating point 314 double floatValue() const; 315 316 /// generates a boolean constant of the given bool 317 static ConstantExpr * from_bool( const CodeLocation & loc, bool b ); 318 /// generates a char constant of the given char 319 static ConstantExpr * from_char( const CodeLocation & loc, char c ); 320 /// generates an integer constant of the given int 321 static ConstantExpr * from_int( const CodeLocation & loc, int i ); 322 /// generates an integer constant of the given unsigned long int 323 static ConstantExpr * from_ulong( const CodeLocation & loc, unsigned long i ); 324 /// generates a floating point constant of the given double 325 static ConstantExpr * from_double( const CodeLocation & loc, double d ); 326 /// generates an array of chars constant of the given string 327 static ConstantExpr * from_string( const CodeLocation & loc, const std::string & s ); 328 /// generates a null pointer value for the given type. void * if omitted. 329 static ConstantExpr * null( const CodeLocation & loc, const Type * ptrType = nullptr ); 330 331 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 332 private: 333 ConstantExpr * clone() const override { return new ConstantExpr{ *this }; } 334 }; 335 336 /// sizeof expression, e.g. `sizeof(int)`, `sizeof 3+4` 337 class SizeofExpr final : public Expr { 338 public: 339 ptr<Expr> expr; 340 ptr<Type> type; 341 342 SizeofExpr( const CodeLocation & loc, const Expr * e ); 343 SizeofExpr( const CodeLocation & loc, const Type * t ); 344 // deliberately no disambiguating overload for nullptr_t 345 346 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 347 private: 348 SizeofExpr * clone() const override { return new SizeofExpr{ *this }; } 349 }; 350 351 /// alignof expression, e.g. `alignof(int)`, `alignof 3+4` 352 class AlignofExpr final : public Expr { 353 public: 354 ptr<Expr> expr; 355 ptr<Type> type; 356 357 AlignofExpr( const CodeLocation & loc, const Expr * e ); 358 AlignofExpr( const CodeLocation & loc, const Type * t ); 359 // deliberately no disambiguating overload for nullptr_t 360 361 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 362 private: 363 AlignofExpr * clone() const override { return new AlignofExpr{ *this }; } 364 }; 365 366 /// offsetof expression before resolver determines field, e.g. `offsetof(MyStruct, myfield)` 367 class UntypedOffsetofExpr final : public Expr { 368 public: 369 ptr<Type> type; 370 std::string member; 371 372 UntypedOffsetofExpr( const CodeLocation & loc, const Type * ty, const std::string & mem ) 373 : Expr( loc ), type( ty ), member( mem ) {} 374 375 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 376 private: 377 UntypedOffsetofExpr * clone() const override { return new UntypedOffsetofExpr{ *this }; } 378 }; 379 380 /// offsetof expression after resolver determines field, e.g. `offsetof(MyStruct, myfield)` 381 class OffsetofExpr final : public Expr { 382 public: 383 ptr<Type> type; 384 readonly<DeclWithType> member; 385 386 OffsetofExpr( const CodeLocation & loc, const Type * ty, const DeclWithType * mem ); 387 388 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 389 private: 390 OffsetofExpr * clone() const override { return new OffsetofExpr{ *this }; } 391 }; 392 393 /// a pack of field-offsets for a generic type 394 class OffsetPackExpr final : public Expr { 395 public: 396 ptr<StructInstType> type; 397 398 OffsetPackExpr( const CodeLocation & loc, const StructInstType * ty ); 399 400 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 401 private: 402 OffsetPackExpr * clone() const override { return new OffsetPackExpr{ *this }; } 403 }; 404 405 /// Variants of short-circuiting logical expression 406 enum LogicalFlag { OrExpr, AndExpr }; 407 408 /// Short-circuiting boolean expression (`&&` or `||`) 409 class LogicalExpr final : public Expr { 410 public: 411 ptr<Expr> arg1; 412 ptr<Expr> arg2; 413 LogicalFlag isAnd; 414 415 LogicalExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2, LogicalFlag ia ); 416 417 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 418 private: 419 LogicalExpr * clone() const override { return new LogicalExpr{ *this }; } 420 }; 421 422 /// Three-argument conditional e.g. `p ? a : b` 423 class ConditionalExpr final : public Expr { 424 public: 425 ptr<Expr> arg1; 426 ptr<Expr> arg2; 427 ptr<Expr> arg3; 428 429 ConditionalExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2, const Expr * a3 ) 430 : Expr( loc ), arg1( a1 ), arg2( a2 ), arg3( a3 ) {} 431 432 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 433 private: 434 ConditionalExpr * clone() const override { return new ConditionalExpr{ *this }; } 435 }; 436 437 /// Comma expression e.g. `( a , b )` 438 class CommaExpr final : public Expr { 439 public: 440 ptr<Expr> arg1; 441 ptr<Expr> arg2; 442 443 CommaExpr( const CodeLocation & loc, const Expr * a1, const Expr * a2 ) 444 : Expr( loc ), arg1( a1 ), arg2( a2 ) {} 445 446 const Expr * accept( Visitor & v ) const override { return v.visit( this ); } 447 private: 448 CommaExpr * clone() const override { return new CommaExpr{ *this }; } 126 449 }; 127 450 … … 138 461 }; 139 462 463 /// A GCC "asm constraint operand" used in an asm statement, e.g. `[output] "=f" (result)`. 464 /// https://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Machine-Constraints.html#Machine-Constraints 465 class AsmExpr final : public Expr { 466 public: 467 ptr<Expr> inout; 468 ptr<Expr> constraint; 469 }; 140 470 141 471 //================================================================================================= … … 146 476 inline void increment( const class Expr * node, Node::ref_type ref ) { node->increment(ref); } 147 477 inline void decrement( const class Expr * node, Node::ref_type ref ) { node->decrement(ref); } 148 // inline void increment( const class ApplicationExpr * node, Node::ref_type ref ) { node->increment(ref); } 149 // inline void decrement( const class ApplicationExpr * node, Node::ref_type ref ) { node->decrement(ref); } 150 // inline void increment( const class UntypedExpr * node, Node::ref_type ref ) { node->increment(ref); } 151 // inline void decrement( const class UntypedExpr * node, Node::ref_type ref ) { node->decrement(ref); } 152 // inline void increment( const class NameExpr * node, Node::ref_type ref ) { node->increment(ref); } 153 // inline void decrement( const class NameExpr * node, Node::ref_type ref ) { node->decrement(ref); } 154 // inline void increment( const class AddressExpr * node, Node::ref_type ref ) { node->increment(ref); } 155 // inline void decrement( const class AddressExpr * node, Node::ref_type ref ) { node->decrement(ref); } 156 // inline void increment( const class LabelAddressExpr * node, Node::ref_type ref ) { node->increment(ref); } 157 // inline void decrement( const class LabelAddressExpr * node, Node::ref_type ref ) { node->decrement(ref); } 158 // inline void increment( const class CastExpr * node, Node::ref_type ref ) { node->increment(ref); } 159 // inline void decrement( const class CastExpr * node, Node::ref_type ref ) { node->decrement(ref); } 160 // inline void increment( const class KeywordCastExpr * node, Node::ref_type ref ) { node->increment(ref); } 161 // inline void decrement( const class KeywordCastExpr * node, Node::ref_type ref ) { node->decrement(ref); } 162 // inline void increment( const class VirtualCastExpr * node, Node::ref_type ref ) { node->increment(ref); } 163 // inline void decrement( const class VirtualCastExpr * node, Node::ref_type ref ) { node->decrement(ref); } 164 // inline void increment( const class MemberExpr * node, Node::ref_type ref ) { node->increment(ref); } 165 // inline void decrement( const class MemberExpr * node, Node::ref_type ref ) { node->decrement(ref); } 166 // inline void increment( const class UntypedMemberExpr * node, Node::ref_type ref ) { node->increment(ref); } 167 // inline void decrement( const class UntypedMemberExpr * node, Node::ref_type ref ) { node->decrement(ref); } 168 // inline void increment( const class VariableExpr * node, Node::ref_type ref ) { node->increment(ref); } 169 // inline void decrement( const class VariableExpr * node, Node::ref_type ref ) { node->decrement(ref); } 170 // inline void increment( const class ConstantExpr * node, Node::ref_type ref ) { node->increment(ref); } 171 // inline void decrement( const class ConstantExpr * node, Node::ref_type ref ) { node->decrement(ref); } 172 // inline void increment( const class SizeofExpr * node, Node::ref_type ref ) { node->increment(ref); } 173 // inline void decrement( const class SizeofExpr * node, Node::ref_type ref ) { node->decrement(ref); } 174 // inline void increment( const class AlignofExpr * node, Node::ref_type ref ) { node->increment(ref); } 175 // inline void decrement( const class AlignofExpr * node, Node::ref_type ref ) { node->decrement(ref); } 176 // inline void increment( const class UntypedOffsetofExpr * node, Node::ref_type ref ) { node->increment(ref); } 177 // inline void decrement( const class UntypedOffsetofExpr * node, Node::ref_type ref ) { node->decrement(ref); } 178 // inline void increment( const class OffsetofExpr * node, Node::ref_type ref ) { node->increment(ref); } 179 // inline void decrement( const class OffsetofExpr * node, Node::ref_type ref ) { node->decrement(ref); } 180 // inline void increment( const class OffsetPackExpr * node, Node::ref_type ref ) { node->increment(ref); } 181 // inline void decrement( const class OffsetPackExpr * node, Node::ref_type ref ) { node->decrement(ref); } 182 // inline void increment( const class AttrExpr * node, Node::ref_type ref ) { node->increment(ref); } 183 // inline void decrement( const class AttrExpr * node, Node::ref_type ref ) { node->decrement(ref); } 184 // inline void increment( const class LogicalExpr * node, Node::ref_type ref ) { node->increment(ref); } 185 // inline void decrement( const class LogicalExpr * node, Node::ref_type ref ) { node->decrement(ref); } 186 // inline void increment( const class ConditionalExpr * node, Node::ref_type ref ) { node->increment(ref); } 187 // inline void decrement( const class ConditionalExpr * node, Node::ref_type ref ) { node->decrement(ref); } 188 // inline void increment( const class CommaExpr * node, Node::ref_type ref ) { node->increment(ref); } 189 // inline void decrement( const class CommaExpr * node, Node::ref_type ref ) { node->decrement(ref); } 190 // inline void increment( const class TypeExpr * node, Node::ref_type ref ) { node->increment(ref); } 191 // inline void decrement( const class TypeExpr * node, Node::ref_type ref ) { node->decrement(ref); } 192 // inline void increment( const class AsmExpr * node, Node::ref_type ref ) { node->increment(ref); } 193 // inline void decrement( const class AsmExpr * node, Node::ref_type ref ) { node->decrement(ref); } 478 inline void increment( const class ApplicationExpr * node, Node::ref_type ref ) { node->increment(ref); } 479 inline void decrement( const class ApplicationExpr * node, Node::ref_type ref ) { node->decrement(ref); } 480 inline void increment( const class UntypedExpr * node, Node::ref_type ref ) { node->increment(ref); } 481 inline void decrement( const class UntypedExpr * node, Node::ref_type ref ) { node->decrement(ref); } 482 inline void increment( const class NameExpr * node, Node::ref_type ref ) { node->increment(ref); } 483 inline void decrement( const class NameExpr * node, Node::ref_type ref ) { node->decrement(ref); } 484 inline void increment( const class AddressExpr * node, Node::ref_type ref ) { node->increment(ref); } 485 inline void decrement( const class AddressExpr * node, Node::ref_type ref ) { node->decrement(ref); } 486 inline void increment( const class LabelAddressExpr * node, Node::ref_type ref ) { node->increment(ref); } 487 inline void decrement( const class LabelAddressExpr * node, Node::ref_type ref ) { node->decrement(ref); } 488 inline void increment( const class CastExpr * node, Node::ref_type ref ) { node->increment(ref); } 489 inline void decrement( const class CastExpr * node, Node::ref_type ref ) { node->decrement(ref); } 490 inline void increment( const class KeywordCastExpr * node, Node::ref_type ref ) { node->increment(ref); } 491 inline void decrement( const class KeywordCastExpr * node, Node::ref_type ref ) { node->decrement(ref); } 492 inline void increment( const class VirtualCastExpr * node, Node::ref_type ref ) { node->increment(ref); } 493 inline void decrement( const class VirtualCastExpr * node, Node::ref_type ref ) { node->decrement(ref); } 494 inline void increment( const class MemberExpr * node, Node::ref_type ref ) { node->increment(ref); } 495 inline void decrement( const class MemberExpr * node, Node::ref_type ref ) { node->decrement(ref); } 496 inline void increment( const class UntypedMemberExpr * node, Node::ref_type ref ) { node->increment(ref); } 497 inline void decrement( const class UntypedMemberExpr * node, Node::ref_type ref ) { node->decrement(ref); } 498 inline void increment( const class VariableExpr * node, Node::ref_type ref ) { node->increment(ref); } 499 inline void decrement( const class VariableExpr * node, Node::ref_type ref ) { node->decrement(ref); } 500 inline void increment( const class ConstantExpr * node, Node::ref_type ref ) { node->increment(ref); } 501 inline void decrement( const class ConstantExpr * node, Node::ref_type ref ) { node->decrement(ref); } 502 inline void increment( const class SizeofExpr * node, Node::ref_type ref ) { node->increment(ref); } 503 inline void decrement( const class SizeofExpr * node, Node::ref_type ref ) { node->decrement(ref); } 504 inline void increment( const class AlignofExpr * node, Node::ref_type ref ) { node->increment(ref); } 505 inline void decrement( const class AlignofExpr * node, Node::ref_type ref ) { node->decrement(ref); } 506 inline void increment( const class UntypedOffsetofExpr * node, Node::ref_type ref ) { node->increment(ref); } 507 inline void decrement( const class UntypedOffsetofExpr * node, Node::ref_type ref ) { node->decrement(ref); } 508 inline void increment( const class OffsetofExpr * node, Node::ref_type ref ) { node->increment(ref); } 509 inline void decrement( const class OffsetofExpr * node, Node::ref_type ref ) { node->decrement(ref); } 510 inline void increment( const class OffsetPackExpr * node, Node::ref_type ref ) { node->increment(ref); } 511 inline void decrement( const class OffsetPackExpr * node, Node::ref_type ref ) { node->decrement(ref); } 512 inline void increment( const class LogicalExpr * node, Node::ref_type ref ) { node->increment(ref); } 513 inline void decrement( const class LogicalExpr * node, Node::ref_type ref ) { node->decrement(ref); } 514 inline void increment( const class ConditionalExpr * node, Node::ref_type ref ) { node->increment(ref); } 515 inline void decrement( const class ConditionalExpr * node, Node::ref_type ref ) { node->decrement(ref); } 516 inline void increment( const class CommaExpr * node, Node::ref_type ref ) { node->increment(ref); } 517 inline void decrement( const class CommaExpr * node, Node::ref_type ref ) { node->decrement(ref); } 518 inline void increment( const class TypeExpr * node, Node::ref_type ref ) { node->increment(ref); } 519 inline void decrement( const class TypeExpr * node, Node::ref_type ref ) { node->decrement(ref); } 520 inline void increment( const class AsmExpr * node, Node::ref_type ref ) { node->increment(ref); } 521 inline void decrement( const class AsmExpr * node, Node::ref_type ref ) { node->decrement(ref); } 194 522 // inline void increment( const class ImplicitCopyCtorExpr * node, Node::ref_type ref ) { node->increment(ref); } 195 523 // inline void decrement( const class ImplicitCopyCtorExpr * node, Node::ref_type ref ) { node->decrement(ref); }
Note: See TracChangeset
for help on using the changeset viewer.