#include "AST.h" #include "UniqueId.h" #include "compiler.h" #include "decls.h" #include "delimit.h" #include "st-field.h" TreeNode *TreeNode::resolveConcat() { const int childCount = arity(); for (int sweep = 0; sweep < childCount; ++sweep) child( sweep, child( sweep )->resolveConcat() ); return this; } TreeNode *TemplateDeclNode::resolveConcat() { return this; } static void flatten( TreeNode &node, llist< TreeNode * > *&accumulator ) { if (node.type()->isStringType() && !strcmp( node.oper_name(), "PlusNode" )) { flatten( *node.opnd1(), accumulator ); flatten( *node.opnd0(), accumulator ); } else accumulator = cons( node.resolveConcat(), accumulator ); } static llist< TreeNode * > *flatten( TreeNode &node ) { llist< TreeNode * > *result = 0; flatten( node, result ); return result; } TreeNode *PlusNode::resolveConcat() { if (type()->isStringType()) return new StringConcatNode( flatten( *this ), position() ); else return this; } TreeNode *PlusAssignNode::resolveConcat() { if (type()->isStringType()) return new StringConcatAssignNode( opnd0(), flatten( *opnd1() ), position() ); else return this; } //////////////////////////////////////////////////////////////////////// MethodCallNode * StringConcatNode::buildMethodCall( ExprNode &primary, const string *symbol, llist *args ) const { // assemble the expression tree NameNode * const name = new NameNode( omitted, symbol, 0, where ); ObjectFieldAccessNode * const access = new ObjectFieldAccessNode( &primary, name, where ); return new MethodCallNode( access, args, where ); } MethodCallNode * StringConcatNode::buildToStringCall( ExprNode &primary ) const { static const string * const toString = intern( "toString" ); return buildMethodCall( primary, toString, 0 ); } ExprNode * StringConcatNode::buildConcatTree( llist *ctorArgs, const FieldContext &context ) const { // allocate a new StringBuffer TypeNode * const bufferType = StringBufferDecl->asType()->addModifiers( Local ); // TypeNode * const allocType = bufferType->clone(); AllocateNode * const allocate = new AllocateNode( TreeNode::omitted, bufferType, ctorArgs, 0, TreeNode::omitted, TreeNode::omitted, where); // build tree bottom up ExprNode *root = allocate; // append each fragment in turn, chaining return values static const string * const append = intern( "append" ); const int numFragments = addends()->arity(); for (unsigned fragment = 0; fragment < (unsigned) numFragments; ++fragment ) { TreeNode * arg = addends()->child( fragment ); if (arg->type()->isImmutable()) arg = buildToStringCall( static_cast< ExprNode & >(*arg) ); root = buildMethodCall( *root, append, cons( arg ) ); } // convert the end result to string root = buildToStringCall( *root ); // the new string is always local static TypeNode * const localString = StringDecl->asType()->addModifiers(Local); root = new CastNode( root, localString, where ); // catch up with preceding static analysis phases FieldContext subcontext( context ); root->resolveField( &subcontext, 0 ); return root; }