| Index: src/ast.cc
|
| ===================================================================
|
| --- src/ast.cc (revision 868)
|
| +++ src/ast.cc (working copy)
|
| @@ -29,6 +29,7 @@
|
|
|
| #include "ast.h"
|
| #include "scopes.h"
|
| +#include "string-stream.h"
|
|
|
| namespace v8 { namespace internal {
|
|
|
| @@ -37,14 +38,15 @@
|
| VariableProxySentinel VariableProxySentinel::identifier_proxy_(false);
|
| ValidLeftHandSideSentinel ValidLeftHandSideSentinel::instance_;
|
| Property Property::this_property_(VariableProxySentinel::this_proxy(), NULL, 0);
|
| -Call Call::sentinel_(NULL, NULL, false, 0);
|
| +Call Call::sentinel_(NULL, NULL, 0);
|
| +CallEval CallEval::sentinel_(NULL, NULL, 0);
|
|
|
|
|
| // ----------------------------------------------------------------------------
|
| // All the Accept member functions for each syntax tree node type.
|
|
|
| #define DECL_ACCEPT(type) \
|
| - void type::Accept(Visitor* v) { \
|
| + void type::Accept(AstVisitor* v) { \
|
| if (v->CheckStackOverflow()) return; \
|
| v->Visit##type(this); \
|
| }
|
| @@ -157,17 +159,17 @@
|
|
|
|
|
| // ----------------------------------------------------------------------------
|
| -// Implementation of Visitor
|
| +// Implementation of AstVisitor
|
|
|
|
|
| -void Visitor::VisitStatements(ZoneList<Statement*>* statements) {
|
| +void AstVisitor::VisitStatements(ZoneList<Statement*>* statements) {
|
| for (int i = 0; i < statements->length(); i++) {
|
| Visit(statements->at(i));
|
| }
|
| }
|
|
|
|
|
| -void Visitor::VisitExpressions(ZoneList<Expression*>* expressions) {
|
| +void AstVisitor::VisitExpressions(ZoneList<Expression*>* expressions) {
|
| for (int i = 0; i < expressions->length(); i++) {
|
| // The variable statement visiting code may pass NULL expressions
|
| // to this code. Maybe this should be handled by introducing an
|
| @@ -179,4 +181,204 @@
|
| }
|
|
|
|
|
| +// ----------------------------------------------------------------------------
|
| +// Regular expressions
|
| +
|
| +#define MAKE_ACCEPT(Name) \
|
| + void* RegExp##Name::Accept(RegExpVisitor* visitor, void* data) { \
|
| + return visitor->Visit##Name(this, data); \
|
| + }
|
| +FOR_EACH_REG_EXP_TREE_TYPE(MAKE_ACCEPT)
|
| +#undef MAKE_ACCEPT
|
| +
|
| +#define MAKE_TYPE_CASE(Name) \
|
| + RegExp##Name* RegExpTree::As##Name() { \
|
| + return NULL; \
|
| + } \
|
| + bool RegExpTree::Is##Name() { return false; }
|
| +FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
|
| +#undef MAKE_TYPE_CASE
|
| +
|
| +#define MAKE_TYPE_CASE(Name) \
|
| + RegExp##Name* RegExp##Name::As##Name() { \
|
| + return this; \
|
| + } \
|
| + bool RegExp##Name::Is##Name() { return true; }
|
| +FOR_EACH_REG_EXP_TREE_TYPE(MAKE_TYPE_CASE)
|
| +#undef MAKE_TYPE_CASE
|
| +
|
| +RegExpEmpty RegExpEmpty::kInstance;
|
| +
|
| +
|
| +// Convert regular expression trees to a simple sexp representation.
|
| +// This representation should be different from the input grammar
|
| +// in as many cases as possible, to make it more difficult for incorrect
|
| +// parses to look as correct ones which is likely if the input and
|
| +// output formats are alike.
|
| +class RegExpUnparser: public RegExpVisitor {
|
| + public:
|
| + RegExpUnparser();
|
| + void VisitCharacterRange(CharacterRange that);
|
| + SmartPointer<const char> ToString() { return stream_.ToCString(); }
|
| +#define MAKE_CASE(Name) virtual void* Visit##Name(RegExp##Name*, void* data);
|
| + FOR_EACH_REG_EXP_TREE_TYPE(MAKE_CASE)
|
| +#undef MAKE_CASE
|
| + private:
|
| + StringStream* stream() { return &stream_; }
|
| + HeapStringAllocator alloc_;
|
| + StringStream stream_;
|
| +};
|
| +
|
| +
|
| +RegExpUnparser::RegExpUnparser() : stream_(&alloc_) {
|
| +}
|
| +
|
| +
|
| +void* RegExpUnparser::VisitDisjunction(RegExpDisjunction* that, void* data) {
|
| + stream()->Add("(|");
|
| + for (int i = 0; i < that->alternatives()->length(); i++) {
|
| + stream()->Add(" ");
|
| + that->alternatives()->at(i)->Accept(this, data);
|
| + }
|
| + stream()->Add(")");
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void* RegExpUnparser::VisitAlternative(RegExpAlternative* that, void* data) {
|
| + stream()->Add("(:");
|
| + for (int i = 0; i < that->nodes()->length(); i++) {
|
| + stream()->Add(" ");
|
| + that->nodes()->at(i)->Accept(this, data);
|
| + }
|
| + stream()->Add(")");
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void RegExpUnparser::VisitCharacterRange(CharacterRange that) {
|
| + stream()->Add("%k", that.from());
|
| + if (!that.IsSingleton()) {
|
| + stream()->Add("-%k", that.to());
|
| + }
|
| +}
|
| +
|
| +
|
| +
|
| +void* RegExpUnparser::VisitCharacterClass(RegExpCharacterClass* that,
|
| + void* data) {
|
| + if (that->is_negated())
|
| + stream()->Add("^");
|
| + stream()->Add("[");
|
| + for (int i = 0; i < that->ranges()->length(); i++) {
|
| + if (i > 0) stream()->Add(" ");
|
| + VisitCharacterRange(that->ranges()->at(i));
|
| + }
|
| + stream()->Add("]");
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void* RegExpUnparser::VisitAssertion(RegExpAssertion* that, void* data) {
|
| + switch (that->type()) {
|
| + case RegExpAssertion::START_OF_INPUT:
|
| + stream()->Add("@^i");
|
| + break;
|
| + case RegExpAssertion::END_OF_INPUT:
|
| + stream()->Add("@$i");
|
| + break;
|
| + case RegExpAssertion::START_OF_LINE:
|
| + stream()->Add("@^l");
|
| + break;
|
| + case RegExpAssertion::END_OF_LINE:
|
| + stream()->Add("@$l");
|
| + break;
|
| + case RegExpAssertion::BOUNDARY:
|
| + stream()->Add("@b");
|
| + break;
|
| + case RegExpAssertion::NON_BOUNDARY:
|
| + stream()->Add("@B");
|
| + break;
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void* RegExpUnparser::VisitAtom(RegExpAtom* that, void* data) {
|
| + stream()->Add("'");
|
| + Vector<const uc16> chardata = that->data();
|
| + for (int i = 0; i < chardata.length(); i++) {
|
| + stream()->Add("%k", chardata[i]);
|
| + }
|
| + stream()->Add("'");
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void* RegExpUnparser::VisitText(RegExpText* that, void* data) {
|
| + if (that->elements()->length() == 1) {
|
| + that->elements()->at(0).data.u_atom->Accept(this, data);
|
| + } else {
|
| + stream()->Add("(!");
|
| + for (int i = 0; i < that->elements()->length(); i++) {
|
| + stream()->Add(" ");
|
| + that->elements()->at(i).data.u_atom->Accept(this, data);
|
| + }
|
| + stream()->Add(")");
|
| + }
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void* RegExpUnparser::VisitQuantifier(RegExpQuantifier* that, void* data) {
|
| + stream()->Add("(# %i ", that->min());
|
| + if (that->max() == RegExpQuantifier::kInfinity) {
|
| + stream()->Add("- ");
|
| + } else {
|
| + stream()->Add("%i ", that->max());
|
| + }
|
| + stream()->Add(that->is_greedy() ? "g " : "n ");
|
| + that->body()->Accept(this, data);
|
| + stream()->Add(")");
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void* RegExpUnparser::VisitCapture(RegExpCapture* that, void* data) {
|
| + stream()->Add("(^ ");
|
| + that->body()->Accept(this, data);
|
| + stream()->Add(")");
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void* RegExpUnparser::VisitLookahead(RegExpLookahead* that, void* data) {
|
| + stream()->Add("(-> ");
|
| + stream()->Add(that->is_positive() ? "+ " : "- ");
|
| + that->body()->Accept(this, data);
|
| + stream()->Add(")");
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void* RegExpUnparser::VisitBackReference(RegExpBackReference* that,
|
| + void* data) {
|
| + stream()->Add("(<- %i)", that->index());
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +void* RegExpUnparser::VisitEmpty(RegExpEmpty* that, void* data) {
|
| + stream()->Put('%');
|
| + return NULL;
|
| +}
|
| +
|
| +
|
| +SmartPointer<const char> RegExpTree::ToString() {
|
| + RegExpUnparser unparser;
|
| + Accept(&unparser, NULL);
|
| + return unparser.ToString();
|
| +}
|
| +
|
| +
|
| } } // namespace v8::internal
|
|
|