// Do miscellaneous tree rewrites to keep the backend happy #include "AST.h" #include "st-field.h" #include "decls.h" #include "code-util.h" #include "domain-decls.h" TreeNode *TreeNode::rewrite( const FieldContext *context ) { const int count = arity(); for (int replace = 0; replace < count; ++replace) child( replace, child( replace )->rewrite( context ) ); return this; } TreeNode *CompileUnitNode::rewrite( const FieldContext * ) { FieldContext context; context.currentPackage = thePackage; return TreeNode::rewrite( &context ); } TreeNode *TemplateDeclNode::rewrite( const FieldContext * ) { return this; } TreeNode *ClassDeclNode::rewrite( const FieldContext *context ) { FieldContext subcontext( *context ); subcontext.currentClass = decl()->asType(); return TreeNode::rewrite( &subcontext ); } static bool inImmutableConstructor = false; static ConstructorDeclNode *currentConstructor = NULL; bool rewroteConstructorReturn = false; TreeNode *ConstructorDeclNode::rewrite( const FieldContext *context ) { TypeNode *ct = decl()->container()->asType(); if (ct->isImmutable()) { // && !(isInSystemPackage(ct->decl(),"ti","internal") || isInSystemPackage(ct->decl(),"ti","domains"))){ // !(ct->isTitaniumBuiltinType() || ct->isTitaniumArrayType())) { // doesn't work - why? inImmutableConstructor = true; currentConstructor = this; // ensure we have a BlockNode body if (body()->absent()) body(new BlockNode(NULL, NULL, position())); if (!isBlockNode(body())) body(new BlockNode(cons(body()), NULL, position())); if (body()->stmts()->empty() || body()->stmts()->arity() == 0 || !isReturnNode(body()->stmts()->child(body()->stmts()->arity()-1))) { // no return node - add one (will be rewritten momentarily) llist* retstmt = cons((TreeNode *)(new ReturnNode(TreeNode::omitted, NULL, position()))); llist* bodyList = appendTreeList(body()->stmts(), retstmt); body()->stmts(new TreeListNode(bodyList, position())); } TreeNode *t = TreeNode::rewrite( context ); currentConstructor = NULL; inImmutableConstructor = false; return t; } else return TreeNode::rewrite( context ); } Common::Modifiers relevantThisFlags( const TreeNode &function ); TreeNode *ReturnNode::rewrite( const FieldContext *context ) { if (inImmutableConstructor) { // return; => return this; TreeNode *t = TreeNode::rewrite( context ); assert(t->expr()->absent()); t->expr(new ThisNode(TreeNode::omitted, context->currentClass, relevantThisFlags(*currentConstructor), position())); rewroteConstructorReturn = true; return t; } else return TreeNode::rewrite( context ); } TreeNode *ThisFieldAccessNode::rewrite( const FieldContext *context ) { return new ObjectFieldAccessNode(new ThisNode(TreeNode::omitted, theClass(), flags(), position()), simpName(), position()); } TreeNode *SuperFieldAccessNode::rewrite( const FieldContext * ) { ObjectFieldAccessNode* ofan = new ObjectFieldAccessNode(new ThisNode(TreeNode::omitted, theClass(), flags(), position()), simpName(), position()); ofan->isRewrittenSFAN(true); return ofan; } bool ObjectFieldAccessNode::isRewrittenSFAN() const { return _isRewrittenSFAN; } void ObjectFieldAccessNode::isRewrittenSFAN(bool val) { _isRewrittenSFAN = val; } TreeNode *AllocateNode::rewrite( const FieldContext *context ) { // rewrite: new (R) Domain(Domain copy) // to: Domain.copy_constructor(copy, R) int arity; if (dtype()->isDomainType()) { int arity = dtype()->tiArity(); TreeNode *myregion = region(); if (myregion->absent()) myregion = new NullPntrNode(position()); llist *myargs = appendTreeList(args(), cons(myregion)); myargs = dreverse(myargs); llist *tmp = copylist(myargs); TreeListNode *tln = new TreeListNode (tmp, position()); TypeNode *domaintype = DomainNDecl[arity-1]->asType(); const string *methodName = intern("copy_constructor"); Decl *method = getDomainMethodDecl(arity, methodName); TreeNode *result = new MethodCallNode( new TypeFieldAccessNode( domaintype, new NameNode(TreeNode::omitted, methodName, method, position()), position()), myargs, position()); return result->rewrite(context); } else return TreeNode::rewrite(context); } TreeNode *ArrayAccessNode::rewrite( const FieldContext *context ) { const TypeNode &arrayType = *array()->type(); assert( arrayType.isArrayType() ); TreeNode::rewrite( context ); if (arrayType.isJavaArrayType()) return new JavaArrayAccessNode( array(), index(), position() ); else if (arrayType.isTitaniumArrayType()) return new TitaniumArrayAccessNode( array(), index(), position() ); else if (arrayType.isPointType()) return new PointArrayAccessNode( array(), index(), position() ); else { fatal( "array access unexpectedly applied to " + arrayType.errorName() ); return this; } } bool VarDeclNode::needsDefaultInitialization() const { return _needsDefaultInitialization; } void VarDeclNode::needsDefaultInitialization(bool val) { _needsDefaultInitialization = val; } TreeNode *VarDeclNode::rewrite( const FieldContext *context ) { if (initExpr()->absent()) { assert(!(dtype()->modifiers() & Common::CompilerGenerated)); // signal this is a user-provided variable that needs default initialization // default initializers are applied during lowering needsDefaultInitialization(true); } else initExpr(initExpr()->rewrite( context )); return this; } TreeNode *StringConcatNode::rewrite( const FieldContext *context ) { TreeNode::rewrite( context ); return buildConcatTree( 0, *context )->rewrite( context ); } /* If you change this then you may also need to change how StringConcatAssignPreLoweringNodes are lowered. */ TreeNode *StringConcatAssignNode::rewrite( const FieldContext *context ) { TreeNode * const appends = buildConcatTree( cons( opnd0() ), *context ); AssignNode * const assign = new AssignNode( opnd0()->deepClone(), appends ); StringConcatAssignPreLoweringNode * const result = new StringConcatAssignPreLoweringNode(assign->rewrite(context)); result->type(opnd0()->type()); return result; } extern bool bounds_checking; TreeNode *AssertNode::rewrite( const FieldContext *context ) { if (bounds_checking) { TreeNode * result = new IfStmtNode(new NotNode(condition()), new ThrowNode(new AllocateNode(TreeNode::omitted, AssertionErrorDecl->asType(), (value()->absent() ? NULL : cons(value())), NULL, TreeNode::omitted, TreeNode::omitted)), TreeNode::omitted); // catch up with preceding static analysis phases FieldContext subcontext( *context ); result->resolveField( &subcontext, 0 ); return result->rewrite(context); } else return new EmptyStmtNode(); } TreeNode *SynchronizedNode::rewrite( const FieldContext *context ) { const SourcePosn &pos = position(); MonitorFetchNode * fetch; if (expr()->absent()) { fetch = (MonitorFetchNode *)new MonitorFetchClassNode( context->currentClass->decl(), pos ); } else { TreeNode *objexpr = expr(); // DOB: temporary hack-around for the fact that we don't generate full type headers for java arrays if (objexpr->type()->isJavaArrayType()) { objexpr = new CastNode(objexpr, ObjectDecl->asType()->withModifiers(objexpr->type()->modifiers()), pos); } fetch = (MonitorFetchNode *)new MonitorFetchInstanceNode( objexpr, pos ); } MonitorLockNode * const lock = new MonitorLockNode( fetch, pos ); MonitorUnlockNode * const unlock = new MonitorUnlockNode( fetch, pos ); FinallyNode * const finally = new FinallyNode( unlock, pos ); TryStmtNode * const attempt = new TryStmtNode( new TryNode( stmt(), pos ), 0, finally, pos ); llist< TreeNode * > *sequence = 0; push( sequence, attempt ); push( sequence, lock ); push( sequence, fetch ); BlockNode * const block = new BlockNode( sequence, NULL, pos ); return block->rewrite( context ); }