Page MenuHomePhabricator

Add an `XHPAST::getNamespace()` method
ClosedPublic

Authored by joshuaspence on Nov 18 2015, 9:04 PM.
Tags
None
Referenced Files
F14017208: D14512.id35127.diff
Mon, Nov 4, 2:34 PM
F14008909: D14512.id35104.diff
Wed, Oct 30, 7:46 AM
F13996743: D14512.id35105.diff
Wed, Oct 23, 11:37 PM
F13996597: D14512.id.diff
Wed, Oct 23, 10:26 PM
F13992001: D14512.diff
Tue, Oct 22, 1:46 PM
F13978848: D14512.id35103.diff
Sat, Oct 19, 1:18 AM
F13977263: D14512.id35107.diff
Fri, Oct 18, 5:52 PM
F13975200: D14512.diff
Fri, Oct 18, 9:12 AM
Subscribers

Details

Summary

This throws away D14498 and starts again. Basically, the grammar of PHP does not allow namespace statements to be parsed consistently (see some discussion in D14506). Instead of complicating the grammar, move the logic of determining a node's namespace to the PHP representation of the AST.

Test Plan

Added unit tests.

Diff Detail

Repository
rPHU libphutil
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

joshuaspence retitled this revision from to Add an `XHPAST::getNamespace()` method.
joshuaspence updated this object.
joshuaspence edited the test plan for this revision. (Show Details)

I'd like to test this on some more complex input data, but I think that my logic is correct for basic cases.

The test data format is a bit hacky and I'm open to suggestions.

src/parser/xhpast/api/XHPASTNode.php
260

Err, this can be removed now :)

epriestley edited edge metadata.

Maybe simpler is:

  • Get all n_NAMESPACE from the tree.
  • Reverse them.
  • For each namespace:
    • If the namespace is after the node (its first namespace token is after the node's last token), continue to the next namespace (the declaration is later in the file).
    • If the namespace has a body but the node is not in the body (the node's last token is not in the namespace's token range), continue to the next namespace.
    • Return the namespace (this is the preceding body-free namespace, or a bodied namespace containing the node).
  • Return null if you get this far.

I think your implementation is also fine, it's maybe just a little harder to reason about, especially with the exit condition being shifting null off the list. I think we end up with a huge pile of nulls in $nodes? Might be a little unintuitive if this gets touched in the future. But there's test coverage so this isn't really perilous or anything.

support/xhpast/xhpast.cpp
15

Haha, this makes sense but let's use 5.8.1 just so we aren't traveling back in time?

This revision is now accepted and ready to land.Nov 18 2015, 9:21 PM

(Coverage seems totally reasonable to me.)

(Coverage seems totally reasonable to me.)

Yeah actually I think that I've coverage almost everything except for this:

<?php

namespace X {
  namespace Y {
    class Z {}
  }
}

But this isn't valid PHP anyway (although XHPAST parses it fine).

I also like this better than D14506 for solving the problem, PHP's grammar makes this not a particularly great fit for solving via AST construction.

I'll try your way and see how that looks.

The new method is somewhat more complex, so I'd appreciate another look at it. I think that the added complexity is okay because it is in the form of new methods (AASTNode::isBefore(), AASTNode::isAfter() and AASTNode::containsDescendant()), which should be more useful generally.

Seems good to me -- those pieces seem reasonable and I think the logic is a little easier to understand now with them broken out.

src/parser/aast/api/AASTNode.php
44–52

Or $this->getTree()->getRootNode() or whatever?

joshuaspence marked an inline comment as done.

Remove getRootNode() method

src/parser/xhpast/api/XHPASTNode.php
291

We generally seem to avoid static methods... should I remove static here?

joshuaspence updated this object.
joshuaspence edited the test plan for this revision. (Show Details)
This revision was automatically updated to reflect the committed changes.
vrana added inline comments.
src/parser/xhpast/api/XHPASTNode.php
273

You probably meant $namespace->getNamespaceName(). getNamespaceName doesn't accept any parameters.