1// -*- c-basic-offset: 4 -*-
2/*
3 * This file is part of the KDE libraries
4 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
5 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
6 * Copyright (C) 2003, 2006, 2007 Apple Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 *
23 */
24
25#include "Parser.h"
26#include <config-kjs.h>
27
28#include "lexer.h"
29#include "nodes.h"
30#include <wtf/HashSet.h>
31#include <wtf/Vector.h>
32
33#ifdef KJS_VERBOSE
34#include <stdio.h>
35#endif
36
37extern int kjsyyparse();
38
39namespace KJS {
40
41Parser::Parser()
42 : m_sourceId(0)
43{
44}
45
46PassRefPtr<ProgramNode> Parser::parseProgram(const UString& sourceURL, int startingLineNumber,
47 const UChar* code, unsigned length,
48 int* sourceId, int* errLine, UString* errMsg)
49{
50 parse(sourceURL, startingLineNumber, code, length, sourceId, errLine, errMsg);
51 return m_progNode.release();
52}
53
54static HashSet<Node*>* nodeCycles;
55
56
57void Parser::noteNodeCycle(Node *node)
58{
59 if (!nodeCycles)
60 nodeCycles = new HashSet<Node*>;
61 nodeCycles->add(node);
62}
63
64void Parser::removeNodeCycle(Node *node)
65{
66 ASSERT(nodeCycles);
67 nodeCycles->remove(node);
68}
69
70static void clearNewNodes()
71{
72 if (nodeCycles) {
73 for (HashSet<Node*>::iterator it = nodeCycles->begin(); it != nodeCycles->end(); ++it)
74 (*it)->breakCycle();
75 delete nodeCycles;
76 nodeCycles = 0;
77 }
78 Node::clearNewNodes();
79}
80
81PassRefPtr<FunctionBodyNode> Parser::parseFunctionBody(const UString& sourceURL, int startingLineNumber,
82 const UChar* code, unsigned length,
83 int* sourceId, int* errLine, UString* errMsg)
84{
85 parse(sourceURL, startingLineNumber, code, length, sourceId, errLine, errMsg);
86 return m_progNode.release();
87}
88
89void Parser::parse(const UString& sourceURL, int startingLineNumber,
90 const UChar* code, unsigned length,
91 int* sourceId, int* errLine, UString* errMsg)
92{
93 pushFunctionContext(0);
94
95 ASSERT(!m_progNode);
96
97 if (errLine)
98 *errLine = -1;
99 if (errMsg)
100 *errMsg = 0;
101
102 Lexer& lexer = KJS::lexer();
103
104 lexer.setCode(sourceURL, startingLineNumber, code, length);
105 m_sourceId++;
106 if (sourceId)
107 *sourceId = m_sourceId;
108
109 // Enable this and the #define YYDEBUG in grammar.y to debug a parse error
110 //extern int kjsyydebug;
111 //kjsyydebug=1;
112
113 int parseError = kjsyyparse();
114
115 bool lexError = lexer.sawError();
116 lexer.clear();
117
118 clearNewNodes();
119
120 if (parseError || lexError) {
121 if (errLine)
122 *errLine = lexer.lineNo();
123 if (errMsg)
124 *errMsg = "Parse error";
125 m_progNode = 0;
126 return;
127 }
128
129#ifdef KJS_VERBOSE
130 fprintf( stderr, "%s\n", m_progNode->toString().ascii() );
131#endif
132}
133
134void Parser::didFinishParsing(PassRefPtr<ProgramNode> progNode)
135{
136 m_progNode = progNode;
137}
138
139Parser& parser()
140{
141 // ASSERT(JSLock::currentThreadIsHoldingLock());
142
143 static Parser staticParser;
144 return staticParser;
145}
146
147} // namespace KJS
148