Reviewed by Eric Seidel.
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Nov 2007 06:54:09 +0000 (06:54 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 16 Nov 2007 06:54:09 +0000 (06:54 +0000)
        Another round of grammar / parsing cleanup.

        1. Created distinct parser calls for parsing function bodies vs
        programs. This will help later with optimizing global variable access.

        2. Turned Parser into a singleton. Cleaned up Lexer's singleton
        interface.

        3. Modified Lexer to free a little more memory when done lexing. (Added
        FIXMEs for similar issues that I didn't fix.)

        4. Changed Lexer::makeIdentifier and Lexer::makeUString to start
        respecting the arguments passed to them. (No behavior change, but this
        problem could have caused serious problems for an unsuspecting user of
        these functions.)

        5. Removed KJS_DEBUG_MEM because it was bit-rotted.

        6. Removed Parser::prettyPrint because the same work was simpler to do
        at the call site.

        7. Some renames:

            "Parser::accept" => "Parser::didFinishParsing"
            "Parser::sid" => "Parser::m_sourceID"
            "Lexer::doneParsing" => "Lexer::clear"
            "sid" => "sourceId"
            "lineno" => "lineNo"

        * JavaScriptCore.exp:
        * kjs/Parser.cpp:
        (KJS::Parser::Parser):
        (KJS::Parser::parseProgram):
        (KJS::Parser::parseFunctionBody):
        (KJS::Parser::parse):
        (KJS::Parser::didFinishParsing):
        (KJS::parser):
        * kjs/Parser.h:
        (KJS::Parser::sourceId):
        * kjs/function.cpp:
        (KJS::GlobalFuncImp::callAsFunction):
        * kjs/function_object.cpp:
        (FunctionObjectImp::construct):
        * kjs/grammar.y:
        * kjs/interpreter.cpp:
        (KJS::Interpreter::checkSyntax):
        (KJS::Interpreter::evaluate):
        * kjs/interpreter.h:
        * kjs/lexer.cpp:
        (kjsyylex):
        (KJS::lexer):
        (KJS::Lexer::Lexer):
        (KJS::Lexer::~Lexer):
        (KJS::Lexer::scanRegExp):
        (KJS::Lexer::doneParsing):
        (KJS::Lexer::makeIdentifier):
        (KJS::Lexer::makeUString):
        * kjs/lexer.h:
        (KJS::Lexer::pattern):
        (KJS::Lexer::flags):
        (KJS::Lexer::sawError):
        * kjs/nodes.cpp:
        (KJS::Node::Node):
        (KJS::FunctionBodyNode::FunctionBodyNode):
        * kjs/nodes.h:
        * kjs/testkjs.cpp:
        (prettyPrintScript):
        (kjsmain):
        * kjs/ustring.cpp:
        * kjs/ustring.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@27842 268f45cc-cd09-0410-ab3c-d52691b4dbfc

16 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/kjs/Parser.cpp
JavaScriptCore/kjs/Parser.h
JavaScriptCore/kjs/function.cpp
JavaScriptCore/kjs/function_object.cpp
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/interpreter.cpp
JavaScriptCore/kjs/interpreter.h
JavaScriptCore/kjs/lexer.cpp
JavaScriptCore/kjs/lexer.h
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
JavaScriptCore/kjs/testkjs.cpp
JavaScriptCore/kjs/ustring.cpp
JavaScriptCore/kjs/ustring.h

index fdc505494f236407c5b53add4a72eb1bd8b868cb..6337ee796a0bdbe0391770ea20d6b53aa973f60b 100644 (file)
@@ -1,3 +1,78 @@
+2007-11-15  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Eric Seidel.
+
+        Another round of grammar / parsing cleanup.
+        
+        1. Created distinct parser calls for parsing function bodies vs
+        programs. This will help later with optimizing global variable access.
+        
+        2. Turned Parser into a singleton. Cleaned up Lexer's singleton 
+        interface.
+        
+        3. Modified Lexer to free a little more memory when done lexing. (Added
+        FIXMEs for similar issues that I didn't fix.)
+        
+        4. Changed Lexer::makeIdentifier and Lexer::makeUString to start 
+        respecting the arguments passed to them. (No behavior change, but this
+        problem could have caused serious problems for an unsuspecting user of
+        these functions.)
+        
+        5. Removed KJS_DEBUG_MEM because it was bit-rotted.
+        
+        6. Removed Parser::prettyPrint because the same work was simpler to do
+        at the call site.
+        
+        7. Some renames:
+        
+            "Parser::accept" => "Parser::didFinishParsing"
+            "Parser::sid" => "Parser::m_sourceID"
+            "Lexer::doneParsing" => "Lexer::clear"
+            "sid" => "sourceId"
+            "lineno" => "lineNo"
+        
+        * JavaScriptCore.exp:
+        * kjs/Parser.cpp:
+        (KJS::Parser::Parser):
+        (KJS::Parser::parseProgram):
+        (KJS::Parser::parseFunctionBody):
+        (KJS::Parser::parse):
+        (KJS::Parser::didFinishParsing):
+        (KJS::parser):
+        * kjs/Parser.h:
+        (KJS::Parser::sourceId):
+        * kjs/function.cpp:
+        (KJS::GlobalFuncImp::callAsFunction):
+        * kjs/function_object.cpp:
+        (FunctionObjectImp::construct):
+        * kjs/grammar.y:
+        * kjs/interpreter.cpp:
+        (KJS::Interpreter::checkSyntax):
+        (KJS::Interpreter::evaluate):
+        * kjs/interpreter.h:
+        * kjs/lexer.cpp:
+        (kjsyylex):
+        (KJS::lexer):
+        (KJS::Lexer::Lexer):
+        (KJS::Lexer::~Lexer):
+        (KJS::Lexer::scanRegExp):
+        (KJS::Lexer::doneParsing):
+        (KJS::Lexer::makeIdentifier):
+        (KJS::Lexer::makeUString):
+        * kjs/lexer.h:
+        (KJS::Lexer::pattern):
+        (KJS::Lexer::flags):
+        (KJS::Lexer::sawError):
+        * kjs/nodes.cpp:
+        (KJS::Node::Node):
+        (KJS::FunctionBodyNode::FunctionBodyNode):
+        * kjs/nodes.h:
+        * kjs/testkjs.cpp:
+        (prettyPrintScript):
+        (kjsmain):
+        * kjs/ustring.cpp:
+        * kjs/ustring.h:
+
 2007-11-15  Oliver Hunt  <oliver@apple.com>
 
         Reviewed by Darin.
index a3cecd56dc866cbee0863f240ed2acbae1c515d8..fe5aa7951af4861794ab00bb9f4c3d39ab4ad7af 100644 (file)
@@ -163,6 +163,7 @@ __ZN3KJS19InternalFunctionImp4infoE
 __ZN3KJS19InternalFunctionImpC2EPNS_17FunctionPrototypeERKNS_10IdentifierE
 __ZN3KJS4List15expandAndAppendEPNS_7JSValueE
 __ZN3KJS4List7markSetEv
+__ZN3KJS4Node5derefEv
 __ZN3KJS6JSCell9getObjectEv
 __ZN3KJS6JSCellnwEm
 __ZN3KJS6JSLock12DropAllLocksC1Ev
@@ -172,7 +173,8 @@ __ZN3KJS6JSLock4lockEv
 __ZN3KJS6JSLock6unlockEv
 __ZN3KJS6JSLock9lockCountEv
 __ZN3KJS6Lookup9findEntryEPKNS_9HashTableERKNS_10IdentifierE
-__ZN3KJS6Parser11prettyPrintERKNS_7UStringEPiPS1_
+__ZN3KJS6Parser12parseProgramERKNS_7UStringEiPKNS_5UCharEjPiS7_PS1_
+__ZN3KJS6parserEv
 __ZN3KJS7CStringD1Ev
 __ZN3KJS7UString3Rep4nullE
 __ZN3KJS7UString3Rep7destroyEv
@@ -206,6 +208,7 @@ __ZN3KJS8JSObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
 __ZN3KJS8JSObject14deletePropertyEPNS_9ExecStateEj
 __ZN3KJS8JSObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
 __ZN3KJS8JSObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE
+__ZN3KJS8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRPNS_7JSValueE
 __ZN3KJS8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPPNS_7JSValueE
 __ZN3KJS8JSObject3putEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEi
 __ZN3KJS8JSObject3putEPNS_9ExecStateEjPNS_7JSValueEi
@@ -246,6 +249,7 @@ __ZNK3KJS13ArrayInstance7getItemEj
 __ZNK3KJS19InternalFunctionImp14implementsCallEv
 __ZNK3KJS19InternalFunctionImp21implementsHasInstanceEv
 __ZNK3KJS4List8getSliceEiRS0_
+__ZNK3KJS4Node8toStringEv
 __ZNK3KJS6JSCell17getTruncatedInt32ERi
 __ZNK3KJS6JSCell17getTruncatedInt32ERi
 __ZNK3KJS6JSCell18getTruncatedUInt32ERj
@@ -270,7 +274,6 @@ __ZNK3KJS8Bindings8Instance10rootObjectEv
 __ZNK3KJS8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE
 __ZNK3KJS8JSObject12defaultValueEPNS_9ExecStateENS_6JSTypeE
 __ZNK3KJS8JSObject14implementsCallEv
-__ZN3KJS8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRPNS_7JSValueE
 __ZNK3KJS8JSObject19implementsConstructEv
 __ZNK3KJS8JSObject21implementsHasInstanceEv
 __ZNK3KJS8JSObject3getEPNS_9ExecStateERKNS_10IdentifierE
index 2f64f8323acf37ded4cb4952343616614a525cfc..8eef050099b3a241b5b8fb758a689fb65c826891 100644 (file)
@@ -3,7 +3,7 @@
  *  This file is part of the KDE libraries
  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2003, 2006 Apple Computer, Inc.
+ *  Copyright (C) 2003, 2006, 2007 Apple Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
 #include <wtf/HashSet.h>
 #include <wtf/Vector.h>
 
-extern int kjsyyparse();
-
 namespace KJS {
 
-int Parser::sid = 0;
+Parser::Parser()
+    : m_sourceId(0)
+{
+}
 
-static RefPtr<ProgramNode>* progNode;
+PassRefPtr<ProgramNode> Parser::parseProgram(const UString& sourceURL, int startingLineNumber,
+    const UChar* code, unsigned length,
+    int* sourceId, int* errLine, UString* errMsg)
+{
+    parse(sourceURL, startingLineNumber, code, length, sourceId, errLine, errMsg);
+    return m_progNode.release();
+}
 
-PassRefPtr<ProgramNode> Parser::parse(const UString& sourceURL, int startingLineNumber,
+PassRefPtr<FunctionBodyNode> Parser::parseFunctionBody(const UString& sourceURL, int startingLineNumber,
     const UChar* code, unsigned length,
     int* sourceId, int* errLine, UString* errMsg)
 {
+    parse(sourceURL, startingLineNumber, code, length, sourceId, errLine, errMsg);
+    return m_progNode.release();
+}
+
+void Parser::parse(const UString& sourceURL, int startingLineNumber,
+    const UChar* code, unsigned length,
+    int* sourceId, int* errLine, UString* errMsg)
+{
+    ASSERT(!m_progNode);
+
     if (errLine)
         *errLine = -1;
     if (errMsg)
         *errMsg = 0;
-    if (!progNode)
-        progNode = new RefPtr<ProgramNode>;
+        
+    Lexer& lexer = KJS::lexer();
 
-    Lexer::curr()->setCode(sourceURL, startingLineNumber, code, length);
-    *progNode = 0;
-    sid++;
+    lexer.setCode(sourceURL, startingLineNumber, code, length);
+    m_sourceId++;
     if (sourceId)
-        *sourceId = sid;
-
-    // Enable this and the #define YYDEBUG in grammar.y to debug a parse error
-    //extern int kjsyydebug;
-    //kjsyydebug=1;
+        *sourceId = m_sourceId;
 
     int parseError = kjsyyparse();
-    bool lexError = Lexer::curr()->sawError();
-    Lexer::curr()->doneParsing();
-    PassRefPtr<ProgramNode> prog = progNode->release();
-    *progNode = 0;
+    bool lexError = lexer.sawError();
+    lexer.clear();
 
     Node::clearNewNodes();
 
     if (parseError || lexError) {
-        int eline = Lexer::curr()->lineNo();
         if (errLine)
-            *errLine = eline;
+            *errLine = lexer.lineNo();
         if (errMsg)
             *errMsg = "Parse error";
-        return 0;
+        m_progNode = 0;
     }
-
-    return prog;
 }
 
-void Parser::accept(PassRefPtr<ProgramNode> prog)
+void Parser::didFinishParsing(PassRefPtr<ProgramNode> progNode)
 {
-    *progNode = prog;
+    m_progNode = progNode;
 }
 
-UString Parser::prettyPrint(const UString& code, int* errLine, UString* errMsg)
+Parser& parser()
 {
-    RefPtr<ProgramNode> progNode = parse(UString(), 0, code.data(), code.size(), 0, errLine, errMsg);
-    if (!progNode)
-        return 0;
-    
-    return progNode->toString();
-}
+    ASSERT(JSLock::currentThreadIsHoldingLock());
 
+    static Parser staticParser;
+    return staticParser;
 }
+
+} // namespace KJS
index 06c8936496baa8855577c7d4a2bcb5a0ce9d8f06..5ba916bce6cfb23996e77d552dddcbc55cb399b1 100644 (file)
@@ -3,7 +3,7 @@
  *  This file is part of the KDE libraries
  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2003, 2006 Apple Computer, Inc.
+ *  Copyright (C) 2003, 2006, 2007 Apple Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
 #define Parser_h
 
 #include <wtf/Forward.h>
+#include <wtf/RefPtr.h>
 
 namespace KJS {
 
-    class Node;
+    class FunctionBodyNode;
     class ProgramNode;
     class UString;
 
     struct UChar;
 
-    /**
-     * @internal
-     *
-     * Parses ECMAScript source code and converts into ProgramNode objects, which
-     * represent the root of a parse tree. This class provides a convenient workaround
-     * for the problem of the bison parser working in a static context.
-     */
-    class Parser {
+    class Parser : Noncopyable {
     public:
-        static PassRefPtr<ProgramNode> parse(const UString& sourceURL, int startingLineNumber,
+        PassRefPtr<ProgramNode> parseProgram(const UString& sourceURL, int startingLineNumber,
             const UChar* code, unsigned length,
             int* sourceId = 0, int* errLine = 0, UString* errMsg = 0);
 
-        static UString prettyPrint(const UString&, int* errLine = 0, UString* errMsg = 0);
+        PassRefPtr<FunctionBodyNode> parseFunctionBody(const UString& sourceURL, int startingLineNumber,
+            const UChar* code, unsigned length,
+            int* sourceId = 0, int* errLine = 0, UString* errMsg = 0);
+
+        int sourceId() { return m_sourceId; }
         
-        static void accept(PassRefPtr<ProgramNode>);
+        void didFinishParsing(PassRefPtr<ProgramNode>);
 
-        static void saveNewNode(Node*);
+    private:
+        friend Parser& parser();
+
+        Parser(); // Use parser() instead.
+        void parse(const UString& sourceURL, int startingLineNumber,
+            const UChar* code, unsigned length,
+            int* sourceId = 0, int* errLine = 0, UString* errMsg = 0);
 
-        static int sid;
+        int m_sourceId;
+        RefPtr<ProgramNode> m_progNode;
     };
+    
+    Parser& parser(); // Returns the singleton JavaScript parser.
 
-} // namespace
+} // namespace KJS
 
-#endif
+#endif // Parser_h
index fadd37af21536e750a7e604f25de680894b4e484..f445cd3301c3d2b348e4d5c38d3760623f395bfb 100644 (file)
@@ -77,13 +77,13 @@ JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const L
     newExec.setException(exec->exception());
 
   Debugger* dbg = exec->dynamicInterpreter()->debugger();
-  int sid = -1;
-  int lineno = -1;
+  int sourceId = -1;
+  int lineNo = -1;
   if (dbg) {
-    sid = body->sourceId();
-    lineno = body->firstLine();
+    sourceId = body->sourceId();
+    lineNo = body->firstLine();
 
-    bool cont = dbg->callEvent(&newExec,sid,lineno,this,args);
+    bool cont = dbg->callEvent(&newExec, sourceId, lineNo, this, args);
     if (!cont) {
       dbg->imp()->abort();
       return jsUndefined();
@@ -102,12 +102,12 @@ JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const L
   dbg = exec->dynamicInterpreter()->debugger();
 
   if (dbg) {
-    lineno = body->lastLine();
+    lineNo = body->lastLine();
 
     if (comp.complType() == Throw)
         newExec.setException(comp.value());
 
-    int cont = dbg->returnEvent(&newExec,sid,lineno,this);
+    int cont = dbg->returnEvent(&newExec, sourceId, lineNo, this);
     if (!cont) {
       dbg->imp()->abort();
       return jsUndefined();
@@ -761,21 +761,21 @@ JSValue* GlobalFuncImp::callAsFunction(ExecState* exec, JSObject* thisObj, const
       else {
         UString s = x->toString(exec);
         
-        int sid;
+        int sourceId;
         int errLine;
         UString errMsg;
-        RefPtr<ProgramNode> progNode(Parser::parse(UString(), 0, s.data(),s.size(),&sid,&errLine,&errMsg));
+        RefPtr<ProgramNode> progNode(parser().parseProgram(UString(), 0, s.data(), s.size(), &sourceId, &errLine, &errMsg));
 
         Debugger* dbg = exec->dynamicInterpreter()->debugger();
         if (dbg) {
-          bool cont = dbg->sourceParsed(exec, sid, UString(), s, 0, errLine, errMsg);
+          bool cont = dbg->sourceParsed(exec, sourceId, UString(), s, 0, errLine, errMsg);
           if (!cont)
             return jsUndefined();
         }
 
         // no program node means a syntax occurred
         if (!progNode)
-          return throwError(exec, SyntaxError, errMsg, errLine, sid, NULL);
+          return throwError(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
 
         bool switchGlobal = thisObj && thisObj != exec->dynamicInterpreter()->globalObject();
           
index 922db9b91716bd40fa52bf5ffa31112969440b46..33d3f70d52f020c3a5646feac1bf248f3744f076 100644 (file)
@@ -185,16 +185,16 @@ JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const
   }
 
   // parse the source code
-  int sid;
+  int sourceId;
   int errLine;
   UString errMsg;
-  RefPtr<ProgramNode> progNode = Parser::parse(sourceURL, lineNumber, body.data(),body.size(),&sid,&errLine,&errMsg);
+  RefPtr<FunctionBodyNode> functionBody = parser().parseFunctionBody(sourceURL, lineNumber, body.data(), body.size(), &sourceId, &errLine, &errMsg);
 
   // notify debugger that source has been parsed
   Debugger *dbg = exec->dynamicInterpreter()->debugger();
   if (dbg) {
     // send empty sourceURL to indicate constructed code
-    bool cont = dbg->sourceParsed(exec, sid, UString(), body, lineNumber, errLine, errMsg);
+    bool cont = dbg->sourceParsed(exec, sourceId, UString(), body, lineNumber, errLine, errMsg);
     if (!cont) {
       dbg->imp()->abort();
       return new JSObject();
@@ -202,16 +202,15 @@ JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const
   }
 
   // no program node == syntax error - throw a syntax error
-  if (!progNode)
+  if (!functionBody)
     // we can't return a Completion(Throw) here, so just set the exception
     // and return it
-    return throwError(exec, SyntaxError, errMsg, errLine, sid, sourceURL);
+    return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL);
 
   ScopeChain scopeChain;
   scopeChain.push(exec->lexicalInterpreter()->globalObject());
-  FunctionBodyNode *bodyNode = progNode.get();
 
-  FunctionImp* fimp = new FunctionImp(exec, functionName, bodyNode, scopeChain);
+  FunctionImp* fimp = new FunctionImp(exec, functionName, functionBody.get(), scopeChain);
   
   // parse parameter list. throw syntax error on illegal identifiers
   int len = p.size();
@@ -231,11 +230,11 @@ JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const
           while (i < len && *c == ' ')
               c++, i++;
           if (i == len) {
-              bodyNode->addParam(Identifier(param));
+              functionBody->addParam(Identifier(param));
               params++;
               break;
           } else if (*c == ',') {
-              bodyNode->addParam(Identifier(param));
+              functionBody->addParam(Identifier(param));
               params++;
               c++, i++;
               continue;
index 0a2bb821cf73f757ec80b288fe7c44005f4d012e..d8589e82fe4c7fa978aa817523b4b3f59befa1ee 100644 (file)
@@ -42,7 +42,8 @@
 #define YYENABLE_NLS 0
 
 /* default values for bison */
-#define YYDEBUG 0
+#define YYDEBUG 0 // Set to 1 to debug a parse error.
+#define kjsyydebug 0 // Set to 1 to debug a parse error.
 #if !PLATFORM(DARWIN)
     // avoid triggering warnings in older bison
 #define YYERROR_VERBOSE
@@ -220,14 +221,16 @@ Literal:
   | NUMBER                              { $$ = makeNumberNode($1); }
   | STRING                              { $$ = new StringNode($1); }
   | '/' /* regexp */                    {
-                                            Lexer *l = Lexer::curr();
-                                            if (!l->scanRegExp()) YYABORT;
-                                            $$ = new RegExpNode(l->pattern, l->flags);
+                                            Lexer& l = lexer();
+                                            if (!l.scanRegExp())
+                                                YYABORT;
+                                            $$ = new RegExpNode(l.pattern(), l.flags());
                                         }
   | DIVEQUAL /* regexp with /= */       {
-                                            Lexer *l = Lexer::curr();
-                                            if (!l->scanRegExp()) YYABORT;
-                                            $$ = new RegExpNode("=" + l->pattern, l->flags);
+                                            Lexer& l = lexer();
+                                            if (!l.scanRegExp())
+                                                YYABORT;
+                                            $$ = new RegExpNode("=" + l.pattern(), l.flags());
                                         }
 ;
 
@@ -876,8 +879,8 @@ FunctionBody:
 ;
 
 Program:
-    /* not in spec */                   { Parser::accept(new ProgramNode(new SourceElements)); }
-    | SourceElements                    { Parser::accept(new ProgramNode($1->release())); }
+    /* not in spec */                   { parser().didFinishParsing(new ProgramNode(new SourceElements)); }
+    | SourceElements                    { parser().didFinishParsing(new ProgramNode($1->release())); }
 ;
 
 SourceElements:
@@ -1090,5 +1093,5 @@ int yyerror(const char *)
 /* may we automatically insert a semicolon ? */
 static bool allowAutomaticSemicolon()
 {
-    return yychar == '}' || yychar == 0 || Lexer::curr()->prevTerminator();
+    return yychar == '}' || yychar == 0 || lexer().prevTerminator();
 }
index ef3664805137b07961b82b06e61425e8cbf712a0..a338a4daa9f893411c93d1a3199e80e5e26364b8 100644 (file)
@@ -308,7 +308,7 @@ Completion Interpreter::checkSyntax(const UString& sourceURL, int startingLineNu
 
     int errLine;
     UString errMsg;
-    RefPtr<ProgramNode> progNode = Parser::parse(sourceURL, startingLineNumber, code, codeLength, 0, &errLine, &errMsg);
+    RefPtr<ProgramNode> progNode = parser().parseProgram(sourceURL, startingLineNumber, code, codeLength, 0, &errLine, &errMsg);
     if (!progNode)
         return Completion(Throw, Error::create(&m_globalExec, SyntaxError, errMsg, errLine, 0, sourceURL));
     return Completion(Normal);
@@ -328,21 +328,21 @@ Completion Interpreter::evaluate(const UString& sourceURL, int startingLineNumbe
         return Completion(Throw, Error::create(&m_globalExec, GeneralError, "Recursion too deep"));
     
     // parse the source code
-    int sid;
+    int sourceId;
     int errLine;
     UString errMsg;
-    RefPtr<ProgramNode> progNode = Parser::parse(sourceURL, startingLineNumber, code, codeLength, &sid, &errLine, &errMsg);
+    RefPtr<ProgramNode> progNode = parser().parseProgram(sourceURL, startingLineNumber, code, codeLength, &sourceId, &errLine, &errMsg);
     
     // notify debugger that source has been parsed
     if (m_debugger) {
-        bool cont = m_debugger->sourceParsed(&m_globalExec, sid, sourceURL, UString(code, codeLength), startingLineNumber, errLine, errMsg);
+        bool cont = m_debugger->sourceParsed(&m_globalExec, sourceId, sourceURL, UString(code, codeLength), startingLineNumber, errLine, errMsg);
         if (!cont)
             return Completion(Break);
     }
     
     // no program node means a syntax error occurred
     if (!progNode)
-        return Completion(Throw, Error::create(&m_globalExec, SyntaxError, errMsg, errLine, sid, sourceURL));
+        return Completion(Throw, Error::create(&m_globalExec, SyntaxError, errMsg, errLine, sourceId, sourceURL));
     
     m_globalExec.clearException();
     
@@ -604,20 +604,6 @@ void Interpreter::mark()
         m_UriErrorPrototype->mark();
 }
 
-#ifdef KJS_DEBUG_MEM
-#include "lexer.h"
-void Interpreter::finalCheck()
-{
-  fprintf(stderr,"Interpreter::finalCheck()\n");
-  Collector::collect();
-
-  Node::finalCheck();
-  Collector::finalCheck();
-  Lexer::globalClear();
-  UString::globalClear();
-}
-#endif
-
 static bool printExceptions = false;
 
 bool Interpreter::shouldPrintExceptions()
index d03dbcf958601f451f3b0ba0f1ea0e084c29b979..24fefe3c100184ef63f7f1d0d7d925a9413dbf37 100644 (file)
@@ -291,13 +291,6 @@ namespace KJS {
      */
     virtual void mark();
 
-#ifdef KJS_DEBUG_MEM
-    /**
-     * @internal
-     */
-    static void finalCheck();
-#endif
-
     static bool shouldPrintExceptions();
     static void setShouldPrintExceptions(bool);
 
index 09c12607d609df088bcf661b66efc6a56551943f..0bdccd6177f8069644819ab9b8ed32d4dc06145e 100644 (file)
@@ -51,15 +51,24 @@ extern YYLTYPE kjsyylloc; // global bison variable holding token info
 // a bridge for yacc from the C world to C++
 int kjsyylex()
 {
-  return Lexer::curr()->lex();
+  return lexer().lex();
 }
 
 namespace KJS {
 
-static Lexer* currLexer = 0;
-
 static bool isDecimalDigit(int);
 
+Lexer& lexer()
+{
+    ASSERT(JSLock::currentThreadIsHoldingLock());
+
+    // FIXME: We'd like to avoid calling new here, but we don't currently 
+    // support tearing down the Lexer at app quit time, since that would involve
+    // tearing down its UString data members without holding the JSLock.
+    static Lexer* staticLexer = new Lexer;
+    return *staticLexer;
+}
+
 Lexer::Lexer()
   : yylineno(1),
     size8(128), size16(128), restrKeyword(false),
@@ -75,33 +84,14 @@ Lexer::Lexer()
   // allocate space for read buffers
   buffer8 = new char[size8];
   buffer16 = new KJS::UChar[size16];
-  currLexer = this;
 }
 
 Lexer::~Lexer()
 {
-  doneParsing();
   delete [] buffer8;
   delete [] buffer16;
 }
 
-Lexer *Lexer::curr()
-{
-  if (!currLexer) {
-    // create singleton instance
-    currLexer = new Lexer();
-  }
-  return currLexer;
-}
-
-#ifdef KJS_DEBUG_MEM
-void Lexer::globalClear()
-{
-  delete currLexer;
-  currLexer = 0L;
-}
-#endif
-
 void Lexer::setCode(const UString &sourceURL, int startingLineNumber, const KJS::UChar *c, unsigned int len)
 {
   yylineno = 1 + startingLineNumber;
@@ -785,6 +775,7 @@ unsigned char Lexer::convertHex(int c1, int c2)
 
 KJS::UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4)
 {
+  // FIXME: This conversion is lossy. See http://bugs.webkit.org/show_bug.cgi?id=4920.
   return KJS::UChar((convertHex(c1) << 4) + convertHex(c2),
                (convertHex(c3) << 4) + convertHex(c4));
 }
@@ -850,7 +841,7 @@ bool Lexer::scanRegExp()
             !lastWasEscape && (current == '\\');
     }
     else { // end of regexp
-      pattern = UString(buffer16, pos16);
+      m_pattern = UString(buffer16, pos16);
       pos16 = 0;
       shift(1);
       break;
@@ -862,58 +853,57 @@ bool Lexer::scanRegExp()
     record16(current);
     shift(1);
   }
-  flags = UString(buffer16, pos16);
+  m_flags = UString(buffer16, pos16);
 
   return true;
 }
 
-
-void Lexer::doneParsing()
+void Lexer::clear()
 {
-  for (unsigned i = 0; i < numIdentifiers; i++) {
+  for (unsigned i = 0; i < numIdentifiers; i++)
     delete identifiers[i];
-  }
   fastFree(identifiers);
   identifiers = 0;
   numIdentifiers = 0;
   identifiersCapacity = 0;
 
-  for (unsigned i = 0; i < numStrings; i++) {
+  for (unsigned i = 0; i < numStrings; i++)
     delete strings[i];
-  }
   fastFree(strings);
   strings = 0;
   numStrings = 0;
   stringsCapacity = 0;
+  
+  m_pattern = 0;
+  m_flags = 0;
+  m_sourceURL = 0;
 }
 
 const int initialCapacity = 64;
 const int growthFactor = 2;
 
-// FIXME: this completely ignores its parameters, instead using buffer16 and pos16 - wtf?
-Identifier *Lexer::makeIdentifier(KJS::UChar*, unsigned int)
+Identifier* Lexer::makeIdentifier(KJS::UChar* buffer, unsigned int pos)
 {
   if (numIdentifiers == identifiersCapacity) {
     identifiersCapacity = (identifiersCapacity == 0) ? initialCapacity : identifiersCapacity *growthFactor;
     identifiers = (KJS::Identifier **)fastRealloc(identifiers, sizeof(KJS::Identifier *) * identifiersCapacity);
   }
 
-  KJS::Identifier *identifier = new KJS::Identifier(buffer16, pos16);
+  KJS::Identifier *identifier = new KJS::Identifier(buffer, pos);
   identifiers[numIdentifiers++] = identifier;
   return identifier;
 }
  
-// FIXME: this completely ignores its parameters, instead using buffer16 and pos16 - wtf?
-UString *Lexer::makeUString(KJS::UChar*, unsigned int)
+UString* Lexer::makeUString(KJS::UChar* buffer, unsigned int pos)
 {
   if (numStrings == stringsCapacity) {
     stringsCapacity = (stringsCapacity == 0) ? initialCapacity : stringsCapacity *growthFactor;
     strings = (UString **)fastRealloc(strings, sizeof(UString *) * stringsCapacity);
   }
 
-  UString *string = new UString(buffer16, pos16);
+  UString *string = new UString(buffer, pos);
   strings[numStrings++] = string;
   return string;
 }
 
-}
+} // namespace KJS
index 9bddf8e48698eb4dd94d34ac843fc61f4c1761de..c7acd27ec0d9fd48483989fe42c86be0578028e7 100644 (file)
@@ -2,6 +2,7 @@
 /*
  *  This file is part of the KDE libraries
  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ *  Copyright (C) 2007 Apple Inc.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Library General Public
  *
  */
 
-#ifndef _KJSLEXER_H_
-#define _KJSLEXER_H_
+#ifndef Lexer_h
+#define Lexer_h
 
 #include "ustring.h"
 
-
 namespace KJS {
 
   class Identifier;
-
   class RegExp;
 
-  class Lexer {
+  class Lexer : Noncopyable {
   public:
-    Lexer();
-    ~Lexer();
-    static Lexer *curr();
-
     void setCode(const UString &sourceURL, int startingLineNumber, const UChar *c, unsigned int len);
     int lex();
 
@@ -75,14 +70,30 @@ namespace KJS {
                  Bad };
 
     bool scanRegExp();
-    UString pattern, flags;
+    const UString& pattern() const { return m_pattern; }
+    const UString& flags() const { return m_flags; }
+
+    static unsigned char convertHex(int);
+    static unsigned char convertHex(int c1, int c2);
+    static UChar convertUnicode(int c1, int c2, int c3, int c4);
+    static bool isIdentStart(int);
+    static bool isIdentPart(int);
+    static bool isHexDigit(int);
+
+    bool sawError() const { return error; }
+
+    void clear();
 
   private:
+    friend Lexer& lexer();
+    Lexer();
+    ~Lexer();
+    
     int yylineno;
     UString m_sourceURL;
     bool done;
-    char *buffer8;
-    UChar *buffer16;
+    char *buffer8; // FIXME: This buffer is never deallocated.
+    UChar *buffer16; // FIXME: This buffer is never deallocated.
     unsigned int size8, size16;
     unsigned int pos8, pos16;
     bool terminator;
@@ -109,25 +120,6 @@ namespace KJS {
     int matchPunctuator(int c1, int c2, int c3, int c4);
     static unsigned short singleEscape(unsigned short);
     static unsigned short convertOctal(int c1, int c2, int c3);
-  public:
-    static unsigned char convertHex(int);
-    static unsigned char convertHex(int c1, int c2);
-    static UChar convertUnicode(int c1, int c2, int c3, int c4);
-    static bool isIdentStart(int);
-    static bool isIdentPart(int);
-    static bool isHexDigit(int);
-
-#ifdef KJS_DEBUG_MEM
-    /**
-     * Clear statically allocated resources
-     */
-    static void globalClear();
-#endif
-
-    bool sawError() const { return error; }
-    void doneParsing();
-
-  private:
 
     void record8(int);
     void record16(int);
@@ -154,12 +146,13 @@ namespace KJS {
     KJS::Identifier **identifiers;
     unsigned int numIdentifiers;
     unsigned int identifiersCapacity;
-
-    // for future extensions
-    class LexerPrivate;
-    LexerPrivate *priv;
+    
+    UString m_pattern;
+    UString m_flags;
   };
+  
+  Lexer& lexer(); // Returns the singletone JavaScript lexer.
 
-} // namespace
+} // namespace KJS
 
-#endif
+#endif // Lexer_h
index 4b97e553798e811fbd848d74a21313f37d0ab60e..1e0ac9732df43acda689fbe53979b9623a6701c1 100644 (file)
@@ -132,7 +132,7 @@ Node::Node()
 #ifndef NDEBUG
     ++NodeCounter::count;
 #endif
-  m_line = Lexer::curr()->lineNo();
+  m_line = lexer().lineNo();
   if (!newNodes)
       newNodes = new HashSet<Node*>;
   newNodes->add(this);
@@ -145,7 +145,7 @@ Node::Node(JSType expectedReturn)
 #ifndef NDEBUG
     ++NodeCounter::count;
 #endif
-    m_line = Lexer::curr()->lineNo();
+    m_line = lexer().lineNo();
     if (!newNodes)
         newNodes = new HashSet<Node*>;
     newNodes->add(this);
@@ -4412,8 +4412,8 @@ Completion TryNode::execute(ExecState *exec)
 
 FunctionBodyNode::FunctionBodyNode(SourceElements* children)
     : BlockNode(children)
-    , m_sourceURL(Lexer::curr()->sourceURL())
-    , m_sourceId(Parser::sid)
+    , m_sourceURL(lexer().sourceURL())
+    , m_sourceId(parser().sourceId())
     , m_initializedDeclarationStacks(false)
     , m_initializedSymbolTable(false)
     , m_optimizedResolveNodes(false)
index ce2d902c40bc828d07e336ae84772480b43c1ea3..aa10317ae0010437bb18ec5f73ab3da4f9c0051c 100644 (file)
@@ -49,6 +49,7 @@
 namespace KJS {
 
     class FuncDeclNode;
+    class Node;
     class PropertyListNode;
     class SourceStream;
     class VarDeclNode;
index 7bf864f1ed02127bd1b6a8efd7314afe9d0418c9..9d4178d9b64620b28e7fe7e2059344824fe67b41 100644 (file)
 
 #include "config.h"
 
+#include "JSGlobalObject.h"
 #include "JSLock.h"
 #include "Parser.h"
 #include "collector.h"
-#include "JSGlobalObject.h"
+#include "nodes.h"
 #include "object.h"
 #include "protect.h"
 #include <math.h>
@@ -245,13 +246,14 @@ static bool prettyPrintScript(const UString& fileName, const Vector<char>& scrip
 {
   int errLine = 0;
   UString errMsg;
-  UString s = Parser::prettyPrint(script.data(), &errLine, &errMsg);
-  if (s.isNull()) {
+  UString scriptUString(script.data());
+  RefPtr<ProgramNode> programNode = parser().parseProgram(fileName, 0, scriptUString.data(), scriptUString.size(), 0, &errLine, &errMsg);
+  if (!programNode) {
     fprintf(stderr, "%s:%d: %s.\n", fileName.UTF8String().c_str(), errLine, errMsg.UTF8String().c_str());
     return false;
   }
   
-  printf("%s\n", s.UTF8String().c_str());
+  printf("%s\n", programNode->toString().UTF8String().c_str());
   return true;
 }
 
@@ -313,9 +315,6 @@ int kjsmain(int argc, char** argv)
   Collector::collect();
 #endif
 
-#ifdef KJS_DEBUG_MEM
-  Interpreter::finalCheck();
-#endif
   return success ? 0 : 3;
 }
 
index 5544aeae2e09005409cc6268574d831939b3b469..b99a29e223912755bcd5eec1b4ca108fcdf085a3 100644 (file)
@@ -176,7 +176,7 @@ static unsigned short almostUChar;
 UString::Rep UString::Rep::null = { 0, 0, 1, 0, 0, &UString::Rep::null, 0, 0, 0, 0, 0 };
 UString::Rep UString::Rep::empty = { 0, 0, 1, 0, 0, &UString::Rep::empty, reinterpret_cast<UChar*>(&almostUChar), 0, 0, 0, 0 };
 const int normalStatBufferSize = 4096;
-static char *statBuffer = 0;
+static char *statBuffer = 0; // FIXME: This buffer is never deallocated.
 static int statBufferSize = 0;
 
 PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar *d, int l)
@@ -886,15 +886,6 @@ char *UString::ascii() const
   return statBuffer;
 }
 
-#ifdef KJS_DEBUG_MEM
-void UString::globalClear()
-{
-  delete [] statBuffer;
-  statBuffer = 0;
-  statBufferSize = 0;
-}
-#endif
-
 UString &UString::operator=(const char *c)
 {
     if (!c) {
index 412514ba12f818cf795c343acb30a94f1d4a758a..86267ce7946886902569cc25990cd2bb156f50e0 100644 (file)
@@ -382,12 +382,6 @@ namespace KJS {
      * Static instance of a null string.
      */
     static const UString &null();
-#ifdef KJS_DEBUG_MEM
-    /**
-     * Clear statically allocated resources.
-     */
-    static void globalClear();
-#endif
 
     Rep* rep() const { return m_rep.get(); }
     UString(PassRefPtr<Rep> r) : m_rep(r) { ASSERT(m_rep); }