source: src/Parser/ParseNode.h@ 6f7424a

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors ctor deferred_resn demangler enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox memory new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new with_gc
Last change on this file since 6f7424a was 321f55d, checked in by Peter A. Buhr <pabuhr@…>, 9 years ago

more refactoring of parser code

  • Property mode set to 100644
File size: 18.2 KB
RevLine 
[b87a5ed]1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
[974906e2]7// ParseNode.h --
[b87a5ed]8//
9// Author : Rodolfo G. Esteves
10// Created On : Sat May 16 13:28:16 2015
[e04ef3a]11// Last Modified By : Peter A. Buhr
[321f55d]12// Last Modified On : Wed Aug 10 21:51:49 2016
13// Update Count : 437
[b87a5ed]14//
15
[51b73452]16#ifndef PARSENODE_H
17#define PARSENODE_H
18
19#include <string>
20#include <list>
21#include <iterator>
[e04ef3a]22#include <memory>
[51b73452]23
[d3b7937]24#include "Common/utility.h"
[68cd1ce]25#include "Parser/LinkageSpec.h"
[59db689]26#include "SynTree/Type.h"
[e04ef3a]27#include "SynTree/Expression.h"
[2f22cc4]28#include "SynTree/Statement.h"
[68cd1ce]29//#include "SynTree/Declaration.h"
[d3b7937]30#include "Common/UniqueName.h"
[0f8e4ac]31#include "SynTree/Label.h"
[51b73452]32
33class StatementNode;
34class CompoundStmtNode;
35class DeclarationNode;
[d1625f8]36class ExpressionNode;
[51b73452]37class InitializerNode;
38
39// Builder
40class ParseNode {
[bdd516a]41 public:
[59db689]42 ParseNode();
43 ParseNode( const std::string * );
[8e9cbb2]44 ParseNode( const std::string & ); // for copy constructing subclasses
[59db689]45 virtual ~ParseNode();
[51b73452]46
[8e9cbb2]47 ParseNode *get_link() const { return next; }
[59db689]48 ParseNode *get_last();
[b87a5ed]49 ParseNode *set_link( ParseNode * );
50 void set_next( ParseNode *newlink ) { next = newlink; }
[51b73452]51
[b87a5ed]52 virtual ParseNode *clone() const { return 0; };
[51b73452]53
[e869d663]54 const std::string &get_name() const { return name; }
55 void set_name( const std::string &newValue ) { name = newValue; }
56
[7bf7fb9]57 virtual void print( std::ostream &os, int indent = 0 ) const;
58 virtual void printList( std::ostream &os, int indent = 0 ) const;
[51b73452]59
[2f22cc4]60 ParseNode &operator,( ParseNode & );
[bdd516a]61 protected:
[e869d663]62 std::string name;
[b87a5ed]63 static int indent_by;
[8e9cbb2]64 ParseNode *next;
[51b73452]65};
66
[bdd516a]67ParseNode *mkList( ParseNode & );
[51b73452]68
[7bf7fb9]69//##############################################################################
70
[d1625f8]71class InitializerNode : public ParseNode {
72 public:
73 InitializerNode( ExpressionNode *, bool aggrp = false, ExpressionNode *des = 0 );
74 InitializerNode( InitializerNode *, bool aggrp = false, ExpressionNode *des = 0 );
75 ~InitializerNode();
76
77 ExpressionNode *get_expression() const { return expr; }
78
79 InitializerNode *set_designators( ExpressionNode *des ) { designator = des; return this; }
80 ExpressionNode *get_designators() const { return designator; }
81
82 InitializerNode *set_maybeConstructed( bool value ) { maybeConstructed = value; return this; }
83 bool get_maybeConstructed() const { return maybeConstructed; }
84
85 InitializerNode *next_init() const { return kids; }
86
87 void print( std::ostream &os, int indent = 0 ) const;
88 void printOneLine( std::ostream & ) const;
89
90 virtual Initializer *build() const;
91 private:
92 ExpressionNode *expr;
93 bool aggregate;
94 ExpressionNode *designator; // may be list
95 InitializerNode *kids;
96 bool maybeConstructed;
97};
98
99//##############################################################################
100
[51b73452]101class ExpressionNode : public ParseNode {
[bdd516a]102 public:
[d1625f8]103 ExpressionNode( Expression * expr = nullptr ) : expr( expr ) {}
104 ExpressionNode( Expression * expr, const std::string *name ) : ParseNode( name ), expr( expr ) {}
[b87a5ed]105 ExpressionNode( const ExpressionNode &other );
[d1625f8]106 virtual ~ExpressionNode() {}
[51b73452]107
[d1625f8]108 virtual ExpressionNode *clone() const { return 0; }
[51b73452]109
[e04ef3a]110 bool get_extension() const { return extension; }
111 ExpressionNode *set_extension( bool exten ) { extension = exten; return this; }
[51b73452]112
[d1625f8]113 virtual void print( std::ostream &os, int indent = 0 ) const {}
114 virtual void printOneLine( std::ostream &os, int indent = 0 ) const {}
[51b73452]115
[d1625f8]116 virtual Expression *build() const { return expr; }
[bdd516a]117 private:
[e04ef3a]118 bool extension = false;
[d1625f8]119 Expression *expr;
[e04ef3a]120};
121
122template< typename T >
123struct maybeBuild_t<Expression, T> {
124 static inline Expression * doit( const T *orig ) {
125 if ( orig ) {
126 Expression *p = orig->build();
127 p->set_extension( orig->get_extension() );
128 return p;
129 } else {
130 return 0;
131 } // if
132 }
[51b73452]133};
134
[7bf7fb9]135//##############################################################################
136
[d1625f8]137Expression *build_constantInteger( std::string &str );
138Expression *build_constantFloat( std::string &str );
139Expression *build_constantChar( std::string &str );
140ConstantExpr *build_constantStr( std::string &str );
[7bf7fb9]141
142//##############################################################################
[ca35c51]143
[d1625f8]144NameExpr *build_varref( const std::string *name, bool labelp = false );
[51b73452]145
[7bf7fb9]146//##############################################################################
147
[d1625f8]148Expression *build_typevalue( DeclarationNode *decl );
[51b73452]149
[7bf7fb9]150//##############################################################################
151
[d9e2280]152enum class OperKinds {
153 // diadic
[7bf7fb9]154 SizeOf, AlignOf, OffsetOf, Plus, Minus, Mul, Div, Mod, Or, And,
[d9e2280]155 BitOr, BitAnd, Xor, Cast, LShift, RShift, LThan, GThan, LEThan, GEThan, Eq, Neq,
156 Assign, MulAssn, DivAssn, ModAssn, PlusAssn, MinusAssn, LSAssn, RSAssn, AndAssn, ERAssn, OrAssn,
157 Index, Range,
158 // monadic
159 UnPlus, UnMinus, AddressOf, PointTo, Neg, BitNeg, Incr, IncrPost, Decr, DecrPost, LabelAddress,
160 Ctor, Dtor,
[51b73452]161};
162
[d1625f8]163Expression *build_cast( DeclarationNode * decl_node, ExpressionNode *expr_node );
164Expression *build_fieldSel( ExpressionNode *expr_node, NameExpr *member );
165Expression *build_pfieldSel( ExpressionNode *expr_node, NameExpr *member );
[064e3ff]166Expression *build_addressOf( ExpressionNode *expr_node );
[d1625f8]167Expression *build_sizeOfexpr( ExpressionNode *expr_node );
168Expression *build_sizeOftype( DeclarationNode *decl_node );
169Expression *build_alignOfexpr( ExpressionNode *expr_node );
170Expression *build_alignOftype( DeclarationNode *decl_node );
171Expression *build_offsetOf( DeclarationNode *decl_node, NameExpr *member );
[51e076e]172Expression *build_and( ExpressionNode *expr_node1, ExpressionNode *expr_node2 );
173Expression *build_and_or( ExpressionNode *expr_node1, ExpressionNode *expr_node2, bool kind );
[d9e2280]174Expression *build_unary_val( OperKinds op, ExpressionNode *expr_node );
175Expression *build_unary_ptr( OperKinds op, ExpressionNode *expr_node );
176Expression *build_binary_val( OperKinds op, ExpressionNode *expr_node1, ExpressionNode *expr_node2 );
177Expression *build_binary_ptr( OperKinds op, ExpressionNode *expr_node1, ExpressionNode *expr_node2 );
[51e076e]178Expression *build_cond( ExpressionNode *expr_node1, ExpressionNode *expr_node2, ExpressionNode *expr_node3 );
179Expression *build_comma( ExpressionNode *expr_node1, ExpressionNode *expr_node2 );
[d1625f8]180Expression *build_attrexpr( NameExpr *var, ExpressionNode * expr_node );
181Expression *build_attrtype( NameExpr *var, DeclarationNode * decl_node );
182Expression *build_tuple( ExpressionNode * expr_node = 0 );
183Expression *build_func( ExpressionNode * function, ExpressionNode * expr_node );
[d9e2280]184Expression *build_range( ExpressionNode * low, ExpressionNode *high );
[064e3ff]185
[7bf7fb9]186//##############################################################################
[51b73452]187
[d1625f8]188Expression *build_asm( ExpressionNode *inout, ConstantExpr *constraint, ExpressionNode *operand );
[7f5566b]189
[7bf7fb9]190//##############################################################################
191
[7f5566b]192class LabelNode : public ExpressionNode {
193 public:
194 virtual Expression *build() const { return NULL; }
[d1625f8]195 virtual LabelNode *clone() const { assert( false ); return new LabelNode( *this ); }
[7f5566b]196
[7bf7fb9]197 virtual void print( std::ostream &os, int indent = 0) const;
198 virtual void printOneLine( std::ostream &os, int indent = 0) const;
[7f5566b]199
[0f8e4ac]200 const std::list< Label > &get_labels() const { return labels; };
[d1625f8]201 void append_label( std::string * label ) { labels.push_back( *label ); delete label; }
[7f5566b]202 private:
[0f8e4ac]203 std::list< Label > labels;
[7f5566b]204};
205
[7bf7fb9]206//##############################################################################
207
[d1625f8]208Expression *build_valexpr( StatementNode *s );
209
210//##############################################################################
211
212Expression *build_compoundLiteral( DeclarationNode *decl_node, InitializerNode *kids );
[51b73452]213
[7bf7fb9]214//##############################################################################
215
[51b73452]216class TypeData;
217
[bdd516a]218class DeclarationNode : public ParseNode {
219 public:
[1db21619]220 enum Qualifier { Const, Restrict, Volatile, Lvalue, Atomic };
[68cd1ce]221 enum StorageClass { Extern, Static, Auto, Register, Inline, Fortran, Noreturn, Threadlocal, NoStorageClass, };
[b87a5ed]222 enum BasicType { Char, Int, Float, Double, Void, Bool, Complex, Imaginary };
[68cd1ce]223 enum Modifier { Signed, Unsigned, Short, Long };
[4040425]224 enum Aggregate { Struct, Union, Trait };
[b87a5ed]225 enum TypeClass { Type, Dtype, Ftype };
[90c3b1c]226 enum BuiltinType { Valist };
[b87a5ed]227
[974906e2]228 static const char *storageName[];
[b87a5ed]229 static const char *qualifierName[];
230 static const char *basicTypeName[];
231 static const char *modifierName[];
[68cd1ce]232 static const char *aggregateName[];
[b87a5ed]233 static const char *typeClassName[];
[90c3b1c]234 static const char *builtinTypeName[];
[b87a5ed]235
[7f5566b]236 static DeclarationNode *newFunction( std::string *name, DeclarationNode *ret, DeclarationNode *param, StatementNode *body, bool newStyle = false );
[b87a5ed]237 static DeclarationNode *newQualifier( Qualifier );
238 static DeclarationNode *newStorageClass( StorageClass );
239 static DeclarationNode *newBasicType( BasicType );
240 static DeclarationNode *newModifier( Modifier );
241 static DeclarationNode *newForall( DeclarationNode *);
242 static DeclarationNode *newFromTypedef( std::string *);
[5d125e4]243 static DeclarationNode *newAggregate( Aggregate kind, const std::string *name, ExpressionNode *actuals, DeclarationNode *fields, bool body );
[b87a5ed]244 static DeclarationNode *newEnum( std::string *name, DeclarationNode *constants );
245 static DeclarationNode *newEnumConstant( std::string *name, ExpressionNode *constant );
246 static DeclarationNode *newName( std::string *);
[59db689]247 static DeclarationNode *newFromTypeGen( std::string *, ExpressionNode *params );
[b87a5ed]248 static DeclarationNode *newTypeParam( TypeClass, std::string *);
[4040425]249 static DeclarationNode *newTrait( std::string *name, DeclarationNode *params, DeclarationNode *asserts );
250 static DeclarationNode *newTraitUse( std::string *name, ExpressionNode *params );
[b87a5ed]251 static DeclarationNode *newTypeDecl( std::string *name, DeclarationNode *typeParams );
252 static DeclarationNode *newPointer( DeclarationNode *qualifiers );
253 static DeclarationNode *newArray( ExpressionNode *size, DeclarationNode *qualifiers, bool isStatic );
254 static DeclarationNode *newVarArray( DeclarationNode *qualifiers );
255 static DeclarationNode *newBitfield( ExpressionNode *size );
256 static DeclarationNode *newTuple( DeclarationNode *members );
257 static DeclarationNode *newTypeof( ExpressionNode *expr );
[59db689]258 static DeclarationNode *newAttr( std::string *, ExpressionNode *expr );
259 static DeclarationNode *newAttr( std::string *, DeclarationNode *type );
[90c3b1c]260 static DeclarationNode *newBuiltinType( BuiltinType );
[b87a5ed]261
262 DeclarationNode *addQualifiers( DeclarationNode *);
263 DeclarationNode *copyStorageClasses( DeclarationNode *);
264 DeclarationNode *addType( DeclarationNode *);
265 DeclarationNode *addTypedef();
266 DeclarationNode *addAssertions( DeclarationNode *);
267 DeclarationNode *addName( std::string *);
268 DeclarationNode *addBitfield( ExpressionNode *size );
269 DeclarationNode *addVarArgs();
270 DeclarationNode *addFunctionBody( StatementNode *body );
271 DeclarationNode *addOldDeclList( DeclarationNode *list );
272 DeclarationNode *addPointer( DeclarationNode *qualifiers );
273 DeclarationNode *addArray( DeclarationNode *array );
274 DeclarationNode *addNewPointer( DeclarationNode *pointer );
275 DeclarationNode *addNewArray( DeclarationNode *array );
276 DeclarationNode *addParamList( DeclarationNode *list );
277 DeclarationNode *addIdList( DeclarationNode *list ); // old-style functions
278 DeclarationNode *addInitializer( InitializerNode *init );
279
280 DeclarationNode *cloneType( std::string *newName );
281 DeclarationNode *cloneType( DeclarationNode *existing );
282 DeclarationNode *cloneType( int ) { return cloneType( ( std::string *)0 ); }
283 DeclarationNode *cloneBaseType( std::string *newName );
284 DeclarationNode *cloneBaseType( DeclarationNode *newdecl );
285
[de62360d]286 DeclarationNode *appendList( DeclarationNode * );
[b87a5ed]287
288 DeclarationNode *clone() const;
[7bf7fb9]289 void print( std::ostream &os, int indent = 0 ) const;
290 void printList( std::ostream &os, int indent = 0 ) const;
[b87a5ed]291
292 Declaration *build() const;
293 ::Type *buildType() const;
294
295 bool get_hasEllipsis() const;
[5f2f2d7]296 const std::string &get_name() const { return name; }
[b87a5ed]297 LinkageSpec::Type get_linkage() const { return linkage; }
298 DeclarationNode *extractAggregate() const;
[90c3b1c]299 ExpressionNode *get_enumeratorValue() const { return enumeratorValue; }
[b87a5ed]300
[7305915]301 bool get_extension() const { return extension; }
302 DeclarationNode *set_extension( bool exten ) { extension = exten; return this; }
303
[b87a5ed]304 DeclarationNode();
305 ~DeclarationNode();
[bdd516a]306 private:
[68cd1ce]307 StorageClass buildStorageClass() const;
[de62360d]308 bool buildFuncSpecifier( StorageClass key ) const;
[b87a5ed]309
310 TypeData *type;
311 std::string name;
312 std::list< StorageClass > storageClasses;
[1db21619]313 std::list< std::string > attributes;
[b87a5ed]314 ExpressionNode *bitfieldWidth;
[90c3b1c]315 ExpressionNode *enumeratorValue;
[b87a5ed]316 InitializerNode *initializer;
317 bool hasEllipsis;
318 LinkageSpec::Type linkage;
[7305915]319 bool extension = false;
[b87a5ed]320
321 static UniqueName anonymous;
[1db21619]322}; // DeclarationNode
[51b73452]323
[d1625f8]324Type *buildType( TypeData *type );
325
[7bf7fb9]326//##############################################################################
327
[51b73452]328class StatementNode : public ParseNode {
[bdd516a]329 public:
[974906e2]330 enum Type { Exp, If, Switch, Case, Default, Choose, Fallthru,
[b87a5ed]331 While, Do, For,
332 Goto, Continue, Break, Return, Throw,
333 Try, Catch, Finally, Asm,
334 Decl
335 };
[51b73452]336
[59db689]337 StatementNode();
[7f5566b]338 StatementNode( const std::string *name );
339 StatementNode( Type t, ExpressionNode *control = 0, StatementNode *block = 0 );
340 StatementNode( Type t, std::string *target );
[b87a5ed]341 StatementNode( DeclarationNode *decl );
[51b73452]342
[59db689]343 ~StatementNode();
[51b73452]344
[59db689]345 static StatementNode *newCatchStmt( DeclarationNode *d = 0, StatementNode *s = 0, bool catchRestP = false );
[51b73452]346
[2f22cc4]347 StatementNode *set_block( StatementNode *b ) { block = b; return this; }
[1db21619]348 StatementNode *get_block() const { return block; }
349
350 void set_control( ExpressionNode *c ) { control = c; }
351 ExpressionNode *get_control() const { return control; }
[51b73452]352
[1db21619]353 StatementNode::Type get_type() const { return type; }
[51b73452]354
[2f22cc4]355 virtual StatementNode *add_label( const std::string * );
356 virtual std::list<std::string> get_labels() const { return labels; }
[51b73452]357
[b87a5ed]358 void addDeclaration( DeclarationNode *newDecl ) { decl = newDecl; }
359 void setCatchRest( bool newVal ) { isCatchRest = newVal; }
[51b73452]360
[b87a5ed]361 std::string get_target() const;
[51b73452]362
[00c32e9]363 // StatementNode *add_controlexp( ExpressionNode * );
[b87a5ed]364 StatementNode *append_block( StatementNode * );
365 StatementNode *append_last_case( StatementNode * );
[51b73452]366
[7bf7fb9]367 void print( std::ostream &os, int indent = 0) const;
[b87a5ed]368 virtual StatementNode *clone() const;
369 virtual Statement *build() const;
[bdd516a]370 private:
[b87a5ed]371 static const char *StType[];
372 Type type;
373 ExpressionNode *control;
374 StatementNode *block;
[1db21619]375 std::list<std::string> labels;
[b87a5ed]376 std::string *target; // target label for jump statements
377 DeclarationNode *decl;
378 bool isCatchRest;
[1db21619]379}; // StatementNode
[51b73452]380
[2f22cc4]381class StatementNode2 : public StatementNode {
382 public:
383 StatementNode2() {}
384 StatementNode2( Statement *stmt ) : stmt( stmt ) {}
385 virtual ~StatementNode2() {}
386
387 virtual StatementNode2 *clone() const { assert( false ); return nullptr; }
388 virtual Statement *build() const { return stmt; }
389
390 virtual StatementNode2 *add_label( const std::string * name ) {
391 stmt->get_labels().emplace_back( *name );
392 return this;
393 }
394 virtual std::list<std::string> get_labels() const { assert( false ); return StatementNode::get_labels(); }
395
396 virtual void print( std::ostream &os, int indent = 0 ) {}
397 virtual void printList( std::ostream &os, int indent = 0 ) {}
398 private:
399 Statement *stmt;
400}; // StatementNode
401
402struct ForCtl {
403 ForCtl( ExpressionNode *expr, ExpressionNode *condition, ExpressionNode *change ) :
404 init( new StatementNode( StatementNode::Exp, expr ) ), condition( condition ), change( change ) {}
405 ForCtl( DeclarationNode *decl, ExpressionNode *condition, ExpressionNode *change ) :
406 init( new StatementNode( decl ) ), condition( condition ), change( change ) {}
407
408 StatementNode *init;
409 ExpressionNode *condition;
410 ExpressionNode *change;
411};
412
413Statement *build_if( ExpressionNode *ctl, StatementNode *then_stmt, StatementNode *else_stmt );
414Statement *build_switch( ExpressionNode *ctl, StatementNode *stmt );
415Statement *build_while( ExpressionNode *ctl, StatementNode *stmt, bool kind = false );
416Statement *build_for( ForCtl *forctl, StatementNode *stmt );
[321f55d]417Statement *build_branch( std::string identifier, BranchStmt::Type kind );
418Statement *build_case( ExpressionNode *ctl );
419Statement *build_default();
[2f22cc4]420
[7bf7fb9]421//##############################################################################
422
[51b73452]423class CompoundStmtNode : public StatementNode {
[bdd516a]424 public:
[59db689]425 CompoundStmtNode();
426 CompoundStmtNode( const std::string * );
[b87a5ed]427 CompoundStmtNode( StatementNode * );
428 ~CompoundStmtNode();
[51b73452]429
[b87a5ed]430 void add_statement( StatementNode * );
[51b73452]431
[7bf7fb9]432 void print( std::ostream &os, int indent = 0 ) const;
[b87a5ed]433 virtual Statement *build() const;
[bdd516a]434 private:
[b87a5ed]435 StatementNode *first, *last;
[51b73452]436};
437
[7bf7fb9]438//##############################################################################
439
[7f5566b]440class AsmStmtNode : public StatementNode {
441 public:
[d1625f8]442 AsmStmtNode( Type, bool voltile, ConstantExpr *instruction, ExpressionNode *output = 0, ExpressionNode *input = 0, ExpressionNode *clobber = 0, LabelNode *gotolabels = 0 );
[7f5566b]443 ~AsmStmtNode();
444
[7bf7fb9]445 void print( std::ostream &os, int indent = 0 ) const;
[7f5566b]446 Statement *build() const;
447 private:
448 bool voltile;
[d1625f8]449 ConstantExpr *instruction;
[7f5566b]450 ExpressionNode *output, *input;
[d1625f8]451 ExpressionNode *clobber;
[0f8e4ac]452 std::list< Label > gotolabels;
[7f5566b]453};
454
[7bf7fb9]455//##############################################################################
456
[51b73452]457template< typename SynTreeType, typename NodeType >
[2f22cc4]458void buildList( const NodeType *firstNode, std::list< SynTreeType * > &outputList ) {
[b87a5ed]459 SemanticError errors;
460 std::back_insert_iterator< std::list< SynTreeType *> > out( outputList );
461 const NodeType *cur = firstNode;
462
463 while ( cur ) {
464 try {
[e04ef3a]465// SynTreeType *result = dynamic_cast< SynTreeType *>( maybeBuild<typename std::result_of<decltype(&NodeType::build)(NodeType)>::type>( cur ) );
466 SynTreeType *result = dynamic_cast< SynTreeType *>( maybeBuild<typename std::pointer_traits<decltype(cur->build())>::element_type>( cur ) );
[b87a5ed]467 if ( result ) {
468 *out++ = result;
469 } else {
470 } // if
471 } catch( SemanticError &e ) {
472 errors.append( e );
473 } // try
474 cur = dynamic_cast< NodeType *>( cur->get_link() );
475 } // while
[a32b204]476 if ( ! errors.isEmpty() ) {
[b87a5ed]477 throw errors;
478 } // if
[51b73452]479}
480
481// in DeclarationNode.cc
[59db689]482void buildList( const DeclarationNode *firstNode, std::list< Declaration * > &outputList );
[bdd516a]483void buildList( const DeclarationNode *firstNode, std::list< DeclarationWithType *> &outputList );
[59db689]484void buildTypeList( const DeclarationNode *firstNode, std::list< Type * > &outputList );
[51b73452]485
[bdd516a]486#endif // PARSENODE_H
[51b73452]487
488// Local Variables: //
[b87a5ed]489// tab-width: 4 //
490// mode: c++ //
491// compile-command: "make install" //
[51b73452]492// End: //
Note: See TracBrowser for help on using the repository browser.