~ubuntu-branches/ubuntu/saucy/mozjs17/saucy

« back to all changes in this revision

Viewing changes to js/src/frontend/ParseNode.cpp

  • Committer: Package Import Robot
  • Author(s): Rico Tzschichholz
  • Date: 2013-05-25 12:24:23 UTC
  • Revision ID: package-import@ubuntu.com-20130525122423-zmxucrhtensw90xy
Tags: upstream-17.0.0
ImportĀ upstreamĀ versionĀ 17.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 
2
 * vim: set ts=8 sw=4 et tw=99:
 
3
 *
 
4
 * This Source Code Form is subject to the terms of the Mozilla Public
 
5
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 
6
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
7
 
 
8
#include "frontend/ParseNode.h"
 
9
#include "frontend/Parser.h"
 
10
 
 
11
#include "jsscriptinlines.h"
 
12
 
 
13
#include "frontend/ParseMaps-inl.h"
 
14
#include "frontend/ParseNode-inl.h"
 
15
#include "frontend/Parser-inl.h"
 
16
 
 
17
using namespace js;
 
18
using namespace js::frontend;
 
19
 
 
20
/*
 
21
 * Asserts to verify assumptions behind pn_ macros.
 
22
 */
 
23
#define pn_offsetof(m)  offsetof(ParseNode, m)
 
24
 
 
25
JS_STATIC_ASSERT(pn_offsetof(pn_link) == pn_offsetof(dn_uses));
 
26
 
 
27
#undef pn_offsetof
 
28
 
 
29
void
 
30
ParseNode::become(ParseNode *pn2)
 
31
{
 
32
    JS_ASSERT(!pn_defn);
 
33
    JS_ASSERT(!pn2->isDefn());
 
34
 
 
35
    JS_ASSERT(!pn_used);
 
36
    if (pn2->isUsed()) {
 
37
        ParseNode **pnup = &pn2->pn_lexdef->dn_uses;
 
38
        while (*pnup != pn2)
 
39
            pnup = &(*pnup)->pn_link;
 
40
        *pnup = this;
 
41
        pn_link = pn2->pn_link;
 
42
        pn_used = true;
 
43
        pn2->pn_link = NULL;
 
44
        pn2->pn_used = false;
 
45
    }
 
46
 
 
47
    pn_type = pn2->pn_type;
 
48
    pn_op = pn2->pn_op;
 
49
    pn_arity = pn2->pn_arity;
 
50
    pn_parens = pn2->pn_parens;
 
51
    pn_u = pn2->pn_u;
 
52
 
 
53
    /*
 
54
     * If any pointers are pointing to pn2, change them to point to this
 
55
     * instead, since pn2 will be cleared and probably recycled.
 
56
     */
 
57
    if (pn_arity == PN_LIST && !pn_head) {
 
58
        /* Empty list: fix up the pn_tail pointer. */
 
59
        JS_ASSERT(pn_count == 0);
 
60
        JS_ASSERT(pn_tail == &pn2->pn_head);
 
61
        pn_tail = &pn_head;
 
62
    }
 
63
 
 
64
    pn2->clear();
 
65
}
 
66
 
 
67
void
 
68
ParseNode::clear()
 
69
{
 
70
    pn_type = PNK_LIMIT;
 
71
    setOp(JSOP_NOP);
 
72
    pn_used = pn_defn = false;
 
73
    pn_arity = PN_NULLARY;
 
74
    pn_parens = false;
 
75
}
 
76
 
 
77
#ifdef DEBUG
 
78
void
 
79
ParseNode::checkListConsistency()
 
80
{
 
81
    JS_ASSERT(isArity(PN_LIST));
 
82
    ParseNode **tail;
 
83
    uint32_t count = 0;
 
84
    if (pn_head) {
 
85
        ParseNode *pn, *last;
 
86
        for (pn = last = pn_head; pn; last = pn, pn = pn->pn_next, count++)
 
87
            ;
 
88
        tail = &last->pn_next;
 
89
    } else {
 
90
        tail = &pn_head;
 
91
    }
 
92
    JS_ASSERT(pn_tail == tail);
 
93
    JS_ASSERT(pn_count == count);
 
94
}
 
95
#endif
 
96
 
 
97
/* Add |node| to |parser|'s free node list. */
 
98
void
 
99
ParseNodeAllocator::freeNode(ParseNode *pn)
 
100
{
 
101
    /* Catch back-to-back dup recycles. */
 
102
    JS_ASSERT(pn != freelist);
 
103
 
 
104
    /*
 
105
     * It's too hard to clear these nodes from the AtomDefnMaps, etc. that
 
106
     * hold references to them, so we never free them. It's our caller's job to
 
107
     * recognize and process these, since their children do need to be dealt
 
108
     * with.
 
109
     */
 
110
    JS_ASSERT(!pn->isUsed());
 
111
    JS_ASSERT(!pn->isDefn());
 
112
 
 
113
#ifdef DEBUG
 
114
    /* Poison the node, to catch attempts to use it without initializing it. */
 
115
    memset(pn, 0xab, sizeof(*pn));
 
116
#endif
 
117
 
 
118
    pn->pn_next = freelist;
 
119
    freelist = pn;
 
120
}
 
121
 
 
122
/*
 
123
 * A work pool of ParseNodes. The work pool is a stack, chained together
 
124
 * by nodes' pn_next fields. We use this to avoid creating deep C++ stacks
 
125
 * when recycling deep parse trees.
 
126
 *
 
127
 * Since parse nodes are probably allocated in something close to the order
 
128
 * they appear in a depth-first traversal of the tree, making the work pool
 
129
 * a stack should give us pretty good locality.
 
130
 */
 
131
class NodeStack {
 
132
  public:
 
133
    NodeStack() : top(NULL) { }
 
134
    bool empty() { return top == NULL; }
 
135
    void push(ParseNode *pn) {
 
136
        pn->pn_next = top;
 
137
        top = pn;
 
138
    }
 
139
    void pushUnlessNull(ParseNode *pn) { if (pn) push(pn); }
 
140
    /* Push the children of the PN_LIST node |pn| on the stack. */
 
141
    void pushList(ParseNode *pn) {
 
142
        /* This clobbers pn->pn_head if the list is empty; should be okay. */
 
143
        *pn->pn_tail = top;
 
144
        top = pn->pn_head;
 
145
    }
 
146
    ParseNode *pop() {
 
147
        JS_ASSERT(!empty());
 
148
        ParseNode *hold = top; /* my kingdom for a prog1 */
 
149
        top = top->pn_next;
 
150
        return hold;
 
151
    }
 
152
  private:
 
153
    ParseNode *top;
 
154
};
 
155
 
 
156
/*
 
157
 * Push the children of |pn| on |stack|. Return true if |pn| itself could be
 
158
 * safely recycled, or false if it must be cleaned later (pn_used and pn_defn
 
159
 * nodes, and all function nodes; see comments for CleanFunctionList in
 
160
 * SemanticAnalysis.cpp). Some callers want to free |pn|; others
 
161
 * (js::ParseNodeAllocator::prepareNodeForMutation) don't care about |pn|, and
 
162
 * just need to take care of its children.
 
163
 */
 
164
static bool
 
165
PushNodeChildren(ParseNode *pn, NodeStack *stack)
 
166
{
 
167
    switch (pn->getArity()) {
 
168
      case PN_FUNC:
 
169
        /*
 
170
         * Function nodes are linked into the function box tree, and may appear
 
171
         * on method lists. Both of those lists are singly-linked, so trying to
 
172
         * update them now could result in quadratic behavior when recycling
 
173
         * trees containing many functions; and the lists can be very long. So
 
174
         * we put off cleaning the lists up until just before function
 
175
         * analysis, when we call CleanFunctionList.
 
176
         *
 
177
         * In fact, we can't recycle the parse node yet, either: it may appear
 
178
         * on a method list, and reusing the node would corrupt that. Instead,
 
179
         * we clear its pn_funbox pointer to mark it as deleted;
 
180
         * CleanFunctionList recycles it as well.
 
181
         *
 
182
         * We do recycle the nodes around it, though, so we must clear pointers
 
183
         * to them to avoid leaving dangling references where someone can find
 
184
         * them.
 
185
         */
 
186
        pn->pn_funbox = NULL;
 
187
        stack->pushUnlessNull(pn->pn_body);
 
188
        pn->pn_body = NULL;
 
189
        return false;
 
190
 
 
191
      case PN_NAME:
 
192
        /*
 
193
         * Because used/defn nodes appear in AtomDefnMaps and elsewhere, we
 
194
         * don't recycle them. (We'll recover their storage when we free the
 
195
         * temporary arena.) However, we do recycle the nodes around them, so
 
196
         * clean up the pointers to avoid dangling references. The top-level
 
197
         * decls table carries references to them that later iterations through
 
198
         * the compileScript loop may find, so they need to be neat.
 
199
         *
 
200
         * pn_expr and pn_lexdef share storage; the latter isn't an owning
 
201
         * reference.
 
202
         */
 
203
        if (!pn->isUsed()) {
 
204
            stack->pushUnlessNull(pn->pn_expr);
 
205
            pn->pn_expr = NULL;
 
206
        }
 
207
        return !pn->isUsed() && !pn->isDefn();
 
208
 
 
209
      case PN_LIST:
 
210
        pn->checkListConsistency();
 
211
        stack->pushList(pn);
 
212
        break;
 
213
      case PN_TERNARY:
 
214
        stack->pushUnlessNull(pn->pn_kid1);
 
215
        stack->pushUnlessNull(pn->pn_kid2);
 
216
        stack->pushUnlessNull(pn->pn_kid3);
 
217
        break;
 
218
      case PN_BINARY:
 
219
        if (pn->pn_left != pn->pn_right)
 
220
            stack->pushUnlessNull(pn->pn_left);
 
221
        stack->pushUnlessNull(pn->pn_right);
 
222
        break;
 
223
      case PN_UNARY:
 
224
        stack->pushUnlessNull(pn->pn_kid);
 
225
        break;
 
226
      case PN_NULLARY:
 
227
        /*
 
228
         * E4X function namespace nodes are PN_NULLARY, but can appear on use
 
229
         * lists.
 
230
         */
 
231
        return !pn->isUsed() && !pn->isDefn();
 
232
      default:
 
233
        ;
 
234
    }
 
235
 
 
236
    return true;
 
237
}
 
238
 
 
239
/*
 
240
 * Prepare |pn| to be mutated in place into a new kind of node. Recycle all
 
241
 * |pn|'s recyclable children (but not |pn| itself!), and disconnect it from
 
242
 * metadata structures (the function box tree).
 
243
 */
 
244
void
 
245
ParseNodeAllocator::prepareNodeForMutation(ParseNode *pn)
 
246
{
 
247
    if (!pn->isArity(PN_NULLARY)) {
 
248
        /* Put |pn|'s children (but not |pn| itself) on a work stack. */
 
249
        NodeStack stack;
 
250
        PushNodeChildren(pn, &stack);
 
251
        /*
 
252
         * For each node on the work stack, push its children on the work stack,
 
253
         * and free the node if we can.
 
254
         */
 
255
        while (!stack.empty()) {
 
256
            pn = stack.pop();
 
257
            if (PushNodeChildren(pn, &stack))
 
258
                freeNode(pn);
 
259
        }
 
260
    }
 
261
}
 
262
 
 
263
/*
 
264
 * Return the nodes in the subtree |pn| to the parser's free node list, for
 
265
 * reallocation.
 
266
 *
 
267
 * Note that all functions in |pn| that are not enclosed by other functions
 
268
 * in |pn| must be direct children of |pc|, because we only clean up |pc|'s
 
269
 * function and method lists. You must not reach into a function and
 
270
 * recycle some part of it (unless you've updated |pc|->functionList, the
 
271
 * way js_FoldConstants does).
 
272
 */
 
273
ParseNode *
 
274
ParseNodeAllocator::freeTree(ParseNode *pn)
 
275
{
 
276
    if (!pn)
 
277
        return NULL;
 
278
 
 
279
    ParseNode *savedNext = pn->pn_next;
 
280
 
 
281
    NodeStack stack;
 
282
    for (;;) {
 
283
        if (PushNodeChildren(pn, &stack))
 
284
            freeNode(pn);
 
285
        if (stack.empty())
 
286
            break;
 
287
        pn = stack.pop();
 
288
    }
 
289
 
 
290
    return savedNext;
 
291
}
 
292
 
 
293
/*
 
294
 * Allocate a ParseNode from parser's node freelist or, failing that, from
 
295
 * cx's temporary arena.
 
296
 */
 
297
void *
 
298
ParseNodeAllocator::allocNode()
 
299
{
 
300
    if (ParseNode *pn = freelist) {
 
301
        freelist = pn->pn_next;
 
302
        return pn;
 
303
    }
 
304
 
 
305
    void *p = cx->tempLifoAlloc().alloc(sizeof (ParseNode));
 
306
    if (!p)
 
307
        js_ReportOutOfMemory(cx);
 
308
    return p;
 
309
}
 
310
 
 
311
/* used only by static create methods of subclasses */
 
312
 
 
313
ParseNode *
 
314
ParseNode::create(ParseNodeKind kind, ParseNodeArity arity, Parser *parser)
 
315
{
 
316
    const Token &tok = parser->tokenStream.currentToken();
 
317
    return parser->new_<ParseNode>(kind, JSOP_NOP, arity, tok.pos);
 
318
}
 
319
 
 
320
ParseNode *
 
321
ParseNode::append(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right)
 
322
{
 
323
    if (!left || !right)
 
324
        return NULL;
 
325
 
 
326
    JS_ASSERT(left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC));
 
327
 
 
328
    if (left->pn_arity != PN_LIST) {
 
329
        ParseNode *pn1 = left->pn_left, *pn2 = left->pn_right;
 
330
        left->setArity(PN_LIST);
 
331
        left->pn_parens = false;
 
332
        left->initList(pn1);
 
333
        left->append(pn2);
 
334
        if (kind == PNK_ADD) {
 
335
            if (pn1->isKind(PNK_STRING))
 
336
                left->pn_xflags |= PNX_STRCAT;
 
337
            else if (!pn1->isKind(PNK_NUMBER))
 
338
                left->pn_xflags |= PNX_CANTFOLD;
 
339
            if (pn2->isKind(PNK_STRING))
 
340
                left->pn_xflags |= PNX_STRCAT;
 
341
            else if (!pn2->isKind(PNK_NUMBER))
 
342
                left->pn_xflags |= PNX_CANTFOLD;
 
343
        }
 
344
    }
 
345
    left->append(right);
 
346
    left->pn_pos.end = right->pn_pos.end;
 
347
    if (kind == PNK_ADD) {
 
348
        if (right->isKind(PNK_STRING))
 
349
            left->pn_xflags |= PNX_STRCAT;
 
350
        else if (!right->isKind(PNK_NUMBER))
 
351
            left->pn_xflags |= PNX_CANTFOLD;
 
352
    }
 
353
 
 
354
    return left;
 
355
}
 
356
 
 
357
ParseNode *
 
358
ParseNode::newBinaryOrAppend(ParseNodeKind kind, JSOp op, ParseNode *left, ParseNode *right,
 
359
                             Parser *parser)
 
360
{
 
361
    if (!left || !right)
 
362
        return NULL;
 
363
 
 
364
    /*
 
365
     * Flatten a left-associative (left-heavy) tree of a given operator into
 
366
     * a list to reduce js::FoldConstants and js::frontend::EmitTree recursion.
 
367
     */
 
368
    if (left->isKind(kind) && left->isOp(op) && (js_CodeSpec[op].format & JOF_LEFTASSOC))
 
369
        return append(kind, op, left, right);
 
370
 
 
371
    /*
 
372
     * Fold constant addition immediately, to conserve node space and, what's
 
373
     * more, so js::FoldConstants never sees mixed addition and concatenation
 
374
     * operations with more than one leading non-string operand in a PN_LIST
 
375
     * generated for expressions such as 1 + 2 + "pt" (which should evaluate
 
376
     * to "3pt", not "12pt").
 
377
     */
 
378
    if (kind == PNK_ADD &&
 
379
        left->isKind(PNK_NUMBER) &&
 
380
        right->isKind(PNK_NUMBER) &&
 
381
        parser->foldConstants)
 
382
    {
 
383
        left->pn_dval += right->pn_dval;
 
384
        left->pn_pos.end = right->pn_pos.end;
 
385
        parser->freeTree(right);
 
386
        return left;
 
387
    }
 
388
 
 
389
    return parser->new_<BinaryNode>(kind, op, left, right);
 
390
}
 
391
 
 
392
// Nb: unlike most functions that are passed a Parser, this one gets a
 
393
// SharedContext passed in separately, because in this case |pc| may not equal
 
394
// |parser->pc|.
 
395
NameNode *
 
396
NameNode::create(ParseNodeKind kind, JSAtom *atom, Parser *parser, ParseContext *pc)
 
397
{
 
398
    ParseNode *pn = ParseNode::create(kind, PN_NAME, parser);
 
399
    if (pn) {
 
400
        pn->pn_atom = atom;
 
401
        ((NameNode *)pn)->initCommon(pc);
 
402
    }
 
403
    return (NameNode *)pn;
 
404
}
 
405
 
 
406
const char js_argument_str[] = "argument";
 
407
const char js_variable_str[] = "variable";
 
408
const char js_unknown_str[]  = "unknown";
 
409
 
 
410
const char *
 
411
Definition::kindString(Kind kind)
 
412
{
 
413
    static const char *table[] = {
 
414
        js_var_str, js_const_str, js_let_str,
 
415
        js_function_str, js_argument_str, js_unknown_str
 
416
    };
 
417
 
 
418
    JS_ASSERT(unsigned(kind) <= unsigned(ARG));
 
419
    return table[kind];
 
420
}
 
421
 
 
422
#if JS_HAS_DESTRUCTURING
 
423
 
 
424
/*
 
425
 * This function assumes the cloned tree is for use in the same statement and
 
426
 * binding context as the original tree.
 
427
 */
 
428
static ParseNode *
 
429
CloneParseTree(ParseNode *opn, Parser *parser)
 
430
{
 
431
    ParseContext *pc = parser->pc;
 
432
 
 
433
    JS_CHECK_RECURSION(pc->sc->context, return NULL);
 
434
 
 
435
    ParseNode *pn = parser->new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
 
436
                                            opn->pn_pos);
 
437
    if (!pn)
 
438
        return NULL;
 
439
    pn->setInParens(opn->isInParens());
 
440
    pn->setDefn(opn->isDefn());
 
441
    pn->setUsed(opn->isUsed());
 
442
 
 
443
    switch (pn->getArity()) {
 
444
#define NULLCHECK(e)    JS_BEGIN_MACRO if (!(e)) return NULL; JS_END_MACRO
 
445
 
 
446
      case PN_FUNC:
 
447
        NULLCHECK(pn->pn_funbox =
 
448
                  parser->newFunctionBox(opn->pn_funbox->object, pc, opn->pn_funbox->strictModeState));
 
449
        NULLCHECK(pn->pn_body = CloneParseTree(opn->pn_body, parser));
 
450
        pn->pn_cookie = opn->pn_cookie;
 
451
        pn->pn_dflags = opn->pn_dflags;
 
452
        pn->pn_blockid = opn->pn_blockid;
 
453
        break;
 
454
 
 
455
      case PN_LIST:
 
456
        pn->makeEmpty();
 
457
        for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
 
458
            ParseNode *pn2;
 
459
            NULLCHECK(pn2 = CloneParseTree(opn2, parser));
 
460
            pn->append(pn2);
 
461
        }
 
462
        pn->pn_xflags = opn->pn_xflags;
 
463
        break;
 
464
 
 
465
      case PN_TERNARY:
 
466
        NULLCHECK(pn->pn_kid1 = CloneParseTree(opn->pn_kid1, parser));
 
467
        NULLCHECK(pn->pn_kid2 = CloneParseTree(opn->pn_kid2, parser));
 
468
        NULLCHECK(pn->pn_kid3 = CloneParseTree(opn->pn_kid3, parser));
 
469
        break;
 
470
 
 
471
      case PN_BINARY:
 
472
        NULLCHECK(pn->pn_left = CloneParseTree(opn->pn_left, parser));
 
473
        if (opn->pn_right != opn->pn_left)
 
474
            NULLCHECK(pn->pn_right = CloneParseTree(opn->pn_right, parser));
 
475
        else
 
476
            pn->pn_right = pn->pn_left;
 
477
        pn->pn_pval = opn->pn_pval;
 
478
        pn->pn_iflags = opn->pn_iflags;
 
479
        break;
 
480
 
 
481
      case PN_UNARY:
 
482
        NULLCHECK(pn->pn_kid = CloneParseTree(opn->pn_kid, parser));
 
483
        pn->pn_hidden = opn->pn_hidden;
 
484
        break;
 
485
 
 
486
      case PN_NAME:
 
487
        // PN_NAME could mean several arms in pn_u, so copy the whole thing.
 
488
        pn->pn_u = opn->pn_u;
 
489
        if (opn->isUsed()) {
 
490
            /*
 
491
             * The old name is a use of its pn_lexdef. Make the clone also be a
 
492
             * use of that definition.
 
493
             */
 
494
            Definition *dn = pn->pn_lexdef;
 
495
 
 
496
            pn->pn_link = dn->dn_uses;
 
497
            dn->dn_uses = pn;
 
498
        } else if (opn->pn_expr) {
 
499
            NULLCHECK(pn->pn_expr = CloneParseTree(opn->pn_expr, parser));
 
500
 
 
501
            /*
 
502
             * If the old name is a definition, the new one has pn_defn set.
 
503
             * Make the old name a use of the new node.
 
504
             */
 
505
            if (opn->isDefn()) {
 
506
                opn->setDefn(false);
 
507
                LinkUseToDef(opn, (Definition *) pn);
 
508
            }
 
509
        }
 
510
        break;
 
511
 
 
512
      case PN_NULLARY:
 
513
        // Even PN_NULLARY may have data (xmlpi for E4X -- what a botch).
 
514
        pn->pn_u = opn->pn_u;
 
515
        break;
 
516
 
 
517
#undef NULLCHECK
 
518
    }
 
519
    return pn;
 
520
}
 
521
 
 
522
#endif /* JS_HAS_DESTRUCTURING */
 
523
 
 
524
/*
 
525
 * Used by Parser::forStatement and comprehensionTail to clone the TARGET in
 
526
 *   for (var/const/let TARGET in EXPR)
 
527
 *
 
528
 * opn must be the pn_head of a node produced by Parser::variables, so its form
 
529
 * is known to be LHS = NAME | [LHS] | {id:LHS}.
 
530
 *
 
531
 * The cloned tree is for use only in the same statement and binding context as
 
532
 * the original tree.
 
533
 */
 
534
ParseNode *
 
535
frontend::CloneLeftHandSide(ParseNode *opn, Parser *parser)
 
536
{
 
537
    ParseNode *pn = parser->new_<ParseNode>(opn->getKind(), opn->getOp(), opn->getArity(),
 
538
                                            opn->pn_pos);
 
539
    if (!pn)
 
540
        return NULL;
 
541
    pn->setInParens(opn->isInParens());
 
542
    pn->setDefn(opn->isDefn());
 
543
    pn->setUsed(opn->isUsed());
 
544
 
 
545
#if JS_HAS_DESTRUCTURING
 
546
    if (opn->isArity(PN_LIST)) {
 
547
        JS_ASSERT(opn->isKind(PNK_RB) || opn->isKind(PNK_RC));
 
548
        pn->makeEmpty();
 
549
        for (ParseNode *opn2 = opn->pn_head; opn2; opn2 = opn2->pn_next) {
 
550
            ParseNode *pn2;
 
551
            if (opn->isKind(PNK_RC)) {
 
552
                JS_ASSERT(opn2->isArity(PN_BINARY));
 
553
                JS_ASSERT(opn2->isKind(PNK_COLON));
 
554
 
 
555
                ParseNode *tag = CloneParseTree(opn2->pn_left, parser);
 
556
                if (!tag)
 
557
                    return NULL;
 
558
                ParseNode *target = CloneLeftHandSide(opn2->pn_right, parser);
 
559
                if (!target)
 
560
                    return NULL;
 
561
 
 
562
                pn2 = parser->new_<BinaryNode>(PNK_COLON, JSOP_INITPROP, opn2->pn_pos, tag, target);
 
563
            } else if (opn2->isArity(PN_NULLARY)) {
 
564
                JS_ASSERT(opn2->isKind(PNK_COMMA));
 
565
                pn2 = CloneParseTree(opn2, parser);
 
566
            } else {
 
567
                pn2 = CloneLeftHandSide(opn2, parser);
 
568
            }
 
569
 
 
570
            if (!pn2)
 
571
                return NULL;
 
572
            pn->append(pn2);
 
573
        }
 
574
        pn->pn_xflags = opn->pn_xflags;
 
575
        return pn;
 
576
    }
 
577
#endif
 
578
 
 
579
    JS_ASSERT(opn->isArity(PN_NAME));
 
580
    JS_ASSERT(opn->isKind(PNK_NAME));
 
581
 
 
582
    /* If opn is a definition or use, make pn a use. */
 
583
    pn->pn_u.name = opn->pn_u.name;
 
584
    pn->setOp(JSOP_SETNAME);
 
585
    if (opn->isUsed()) {
 
586
        Definition *dn = pn->pn_lexdef;
 
587
 
 
588
        pn->pn_link = dn->dn_uses;
 
589
        dn->dn_uses = pn;
 
590
    } else {
 
591
        pn->pn_expr = NULL;
 
592
        if (opn->isDefn()) {
 
593
            /* We copied some definition-specific state into pn. Clear it out. */
 
594
            pn->pn_cookie.makeFree();
 
595
            pn->pn_dflags &= ~PND_BOUND;
 
596
            pn->setDefn(false);
 
597
 
 
598
            LinkUseToDef(pn, (Definition *) opn);
 
599
        }
 
600
    }
 
601
    return pn;
 
602
}
 
603
 
 
604
#ifdef DEBUG
 
605
void
 
606
frontend::DumpParseTree(ParseNode *pn, int indent)
 
607
{
 
608
    if (pn == NULL)
 
609
        fprintf(stderr, "()");
 
610
    else
 
611
        pn->dump(indent);
 
612
}
 
613
#endif