kdelibs/kjs/nodes.cpp
2014-11-13 01:04:59 +02:00

1178 lines
31 KiB
C++

/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2007 Maksim Orlovich (maksim@kde.org)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "nodes.h"
#include <config-kjs.h>
#include "scriptfunction.h"
#include "CompileState.h"
#include <math.h>
#include <stdio.h>
#ifdef KJS_DEBUG_MEM
#include <typeinfo>
#endif
//#include <iostream>
#include "debugger.h"
#include "function_object.h"
#include "lexer.h"
#include "operations.h"
#include "package.h"
#include "PropertyNameArray.h"
#include <wtf/AlwaysInline.h>
#include <wtf/Assertions.h>
#include <wtf/HashSet.h>
#include <wtf/HashCountedSet.h>
#include <wtf/MathExtras.h>
#include "bytecode/machine.h"
namespace KJS {
// ------------------------------ Node -----------------------------------------
#ifndef NDEBUG
struct NodeCounter {
static unsigned count;
~NodeCounter()
{
if (count)
fprintf(stderr, "LEAK: %d KJS::Node\n", count);
}
};
unsigned NodeCounter::count = 0;
static NodeCounter nodeCounter;
#endif
static HashSet<Node*>* newNodes;
static HashCountedSet<Node*>* nodeExtraRefCounts;
Node::Node()
{
#ifndef NDEBUG
++NodeCounter::count;
#endif
m_line = lexer().lineNo();
if (!newNodes)
newNodes = new HashSet<Node*>;
newNodes->add(this);
}
Node::~Node()
{
#ifndef NDEBUG
--NodeCounter::count;
#endif
}
void Node::ref()
{
// bumping from 0 to 1 is just removing from the new nodes set
if (newNodes) {
HashSet<Node*>::iterator it = newNodes->find(this);
if (it != newNodes->end()) {
newNodes->remove(it);
ASSERT(!nodeExtraRefCounts || !nodeExtraRefCounts->contains(this));
return;
}
}
ASSERT(!newNodes || !newNodes->contains(this));
if (!nodeExtraRefCounts)
nodeExtraRefCounts = new HashCountedSet<Node*>;
nodeExtraRefCounts->add(this);
}
void Node::deref()
{
ASSERT(!newNodes || !newNodes->contains(this));
if (!nodeExtraRefCounts) {
delete this;
return;
}
HashCountedSet<Node*>::iterator it = nodeExtraRefCounts->find(this);
if (it == nodeExtraRefCounts->end())
delete this;
else
nodeExtraRefCounts->remove(it);
}
unsigned Node::refcount()
{
if (newNodes && newNodes->contains(this)) {
ASSERT(!nodeExtraRefCounts || !nodeExtraRefCounts->contains(this));
return 0;
}
ASSERT(!newNodes || !newNodes->contains(this));
if (!nodeExtraRefCounts)
return 1;
return 1 + nodeExtraRefCounts->count(this);
}
void Node::clearNewNodes()
{
if (!newNodes)
return;
#ifndef NDEBUG
HashSet<Node*>::iterator end = newNodes->end();
for (HashSet<Node*>::iterator it = newNodes->begin(); it != end; ++it)
ASSERT(!nodeExtraRefCounts || !nodeExtraRefCounts->contains(*it));
#endif
deleteAllValues(*newNodes);
delete newNodes;
newNodes = 0;
}
static void substitute(UString &string, const UString &substring)
{
int position = string.find("%s");
assert(position != -1);
UString newString = string.substr(0, position);
newString.append(substring);
newString.append(string.substr(position + 2));
string = newString;
}
static inline int currentSourceId(ExecState* exec)
{
return exec->currentBody()->sourceId();
}
static inline const UString& currentSourceURL(ExecState* exec)
{
return exec->currentBody()->sourceURL();
}
JSValue* Node::throwError(ExecState* exec, ErrorType e, const UString& msg)
{
return KJS::throwError(exec, e, msg, lineNo(), currentSourceId(exec), currentSourceURL(exec));
}
JSValue* Node::throwError(ExecState* exec, ErrorType e, const UString& msg, const Identifier& label)
{
UString message = msg;
substitute(message, label.ustring());
return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
}
JSValue* Node::throwUndefinedVariableError(ExecState* exec, const Identifier& ident)
{
return throwError(exec, ReferenceError, "Cannot find variable: %s", ident);
}
Node *Node::nodeInsideAllParens()
{
return this;
}
class VarDeclVisitor: public NodeVisitor {
private:
ExecState* m_exec;
public:
VarDeclVisitor(ExecState* exec) : m_exec(exec)
{}
virtual Node* visit(Node* node) {
node->processVarDecl(m_exec);
//Do not recurse inside function bodies, or things that
// syntactically can't contain declarations
if (!node->scanForDeclarations())
return 0;
return NodeVisitor::visit(node);
}
};
class FuncDeclVisitor: public NodeVisitor {
private:
ExecState* m_exec;
public:
FuncDeclVisitor(ExecState* exec) : m_exec(exec)
{}
virtual Node* visit(Node* node) {
node->processFuncDecl(m_exec);
if (!node->scanForDeclarations())
return 0;
return NodeVisitor::visit(node);
}
};
void Node::processDecls(ExecState *exec) {
VarDeclVisitor vVisit(exec);
vVisit.visit(this);
FuncDeclVisitor fVisit(exec);
fVisit.visit(this);
}
void Node::processVarDecl (ExecState*)
{}
void Node::processFuncDecl(ExecState*)
{}
// ------------------------------ NodeVisitor ----------------------------------
Node* NodeVisitor::visit(Node *node) {
node->recurseVisit(this);
return 0;
}
// ------------------------------ StatementNode --------------------------------
StatementNode::StatementNode()
: m_lastLine(-1)
{
m_line = -1;
}
void StatementNode::setLoc(int firstLine, int lastLine) const
{
m_line = firstLine;
m_lastLine = lastLine;
}
void StatementNode::hitStatement(ExecState* exec)
{
// The debugger is always non-zero here, since otherwise this won't be involved
exec->dynamicInterpreter()->debugger()->reportAtStatement(exec, currentSourceId(exec), firstLine(), lastLine());
}
// ------------------------------ GroupNode ------------------------------------
Node *GroupNode::nodeInsideAllParens()
{
Node *n = this;
do
n = static_cast<GroupNode *>(n)->group.get();
while (n->isGroupNode());
return n;
}
void GroupNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, group);
}
// ------------------------------ ElementNode ----------------------------------
void ElementNode::breakCycle()
{
next = 0;
}
void ElementNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, next);
recurseVisitLink(visitor, node);
}
// ------------------------------ ArrayNode ------------------------------------
void ArrayNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, element);
}
// ------------------------------ ObjectLiteralNode ----------------------------
void ObjectLiteralNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, list);
}
// ------------------------------ PropertyListNode -----------------------------
void PropertyListNode::breakCycle()
{
next = 0;
}
void PropertyListNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, node);
recurseVisitLink(visitor, next);
}
// ------------------------------ PropertyNode -----------------------------
void PropertyNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, name);
recurseVisitLink(visitor, assign);
}
// ------------------------------ BracketAccessorNode --------------------------------
void BracketAccessorNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr1);
recurseVisitLink(visitor, expr2);
}
// ------------------------------ DotAccessorNode --------------------------------
void DotAccessorNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
}
// ------------------------------ ArgumentListNode -----------------------------
void ArgumentListNode::breakCycle()
{
next = 0;
}
void ArgumentListNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, next);
recurseVisitLink(visitor, expr);
}
// ------------------------------ ArgumentsNode --------------------------------
void ArgumentsNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, list);
}
// ------------------------------ NewExprNode ----------------------------------
void NewExprNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
recurseVisitLink(visitor, args);
}
// ------------------------------ FunctionCallValueNode ------------------------
void FunctionCallValueNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
recurseVisitLink(visitor, args);
}
// ------------------------------ FunctionCallRerefenceNode --------------------
void FunctionCallReferenceNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
recurseVisitLink(visitor, args);
}
// ------------------------------ PostfixNode ----------------------------------
void PostfixNode::recurseVisit(NodeVisitor *visitor)
{
Node::recurseVisitLink(visitor, m_loc);
}
// ------------------------------ DeleteReferenceNode -------------------------------
void DeleteReferenceNode::recurseVisit(NodeVisitor *visitor)
{
Node::recurseVisitLink(visitor, loc);
}
// ------------------------------ DeleteValueNode -----------------------------------
void DeleteValueNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, m_expr);
}
// ------------------------------ VoidNode -------------------------------------
void VoidNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
}
// ------------------------------ TypeOfVarNode -----------------------------------
void TypeOfVarNode::recurseVisit(NodeVisitor *visitor)
{
Node::recurseVisitLink(visitor, loc);
}
// ------------------------------ TypeOfValueNode -----------------------------------
void TypeOfValueNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, m_expr);
}
// ------------------------------ PrefixNode ----------------------------------------
void PrefixNode::recurseVisit(NodeVisitor *visitor)
{
Node::recurseVisitLink(visitor, m_loc);
}
// ------------------------------ UnaryPlusNode --------------------------------
void UnaryPlusNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
}
// ------------------------------ NegateNode -----------------------------------
void NegateNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
}
// ------------------------------ BitwiseNotNode -------------------------------
void BitwiseNotNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
}
// ------------------------------ LogicalNotNode -------------------------------
void LogicalNotNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
}
// ------------------------ BinaryOperatorNode -------------------------------
void BinaryOperatorNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr1);
recurseVisitLink(visitor, expr2);
}
// ------------------------------ BinaryLogicalNode ----------------------------
void BinaryLogicalNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr1);
recurseVisitLink(visitor, expr2);
}
// ------------------------------ ConditionalNode ------------------------------
void ConditionalNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, logical);
recurseVisitLink(visitor, expr1);
recurseVisitLink(visitor, expr2);
}
// ------------------------------ AssignNode -----------------------------------
void AssignNode::recurseVisit(NodeVisitor *visitor)
{
Node::recurseVisitLink(visitor, m_loc);
Node::recurseVisitLink(visitor, m_right);
}
// ------------------------------ CommaNode ------------------------------------
void CommaNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr1);
recurseVisitLink(visitor, expr2);
}
// ------------------------------ AssignExprNode -------------------------------
void AssignExprNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
}
// ------------------------------ VarDeclNode ----------------------------------
VarDeclNode::VarDeclNode(const Identifier &id, AssignExprNode *in, Type t)
: varType(t), ident(id), init(in)
{
}
#if 0
// ECMA 12.2
JSValue *VarDeclNode::evaluate(ExecState *exec)
{
JSObject* variable = exec->variableObject();
JSValue* val;
if (init) {
val = init->evaluate(exec);
KJS_CHECKEXCEPTIONVALUE
} else {
// already declared? - check with getDirect so you can override
// built-in properties of the global object with var declarations.
// Also check for 'arguments' property. The 'arguments' cannot be found with
// getDirect, because it's created lazily by
// ActivationImp::getOwnPropertySlot.
// Since variable declarations are always in function scope, 'variable'
// will always contain instance of ActivationImp and ActivationImp will
// always have 'arguments' property
if (variable->getDirect(ident) || ident == exec->propertyNames().arguments)
return 0;
val = jsUndefined();
}
#ifdef KJS_VERBOSE
printInfo(exec,(UString("new variable ")+ident.ustring()).cstring().c_str(),val);
#endif
// We use Internal to bypass all checks in derived objects, e.g. so that
// "var location" creates a dynamic property instead of activating window.location.
int flags = Internal;
if (exec->codeType() != EvalCode)
flags |= DontDelete;
if (varType == VarDeclNode::Constant)
flags |= ReadOnly;
variable->put(exec, ident, val, flags);
return 0; //No useful value, not a true expr
}
#endif
void VarDeclNode::processVarDecl(ExecState *exec)
{
JSObject* variable = exec->variableObject();
// First, determine which flags we want to use..
int flags = DontDelete;
if (varType == VarDeclNode::Constant)
flags |= ReadOnly;
// Are we inside a function? If so, we fill in the symbol table
switch (exec->codeType()) {
case FunctionCode:
// Inside a function, we're just computing static information.
// so, just fill in the symbol table.
exec->currentBody()->addVarDecl(ident, flags, exec);
return;
case EvalCode:
// eval-injected variables can be deleted..
flags &= ~DontDelete;
// If a variable by this name already exists, don't clobber it -
// eval may be trying to inject a variable that already exists..
if (!variable->hasProperty(exec, ident)) {
variable->put(exec, ident, jsUndefined(), flags);
// eval injected a new local into scope! Better mark that down,
// so that NonLocalResolver stops skipping the local scope
variable->setLocalInjected();
}
break;
case GlobalCode:
// If a variable by this name already exists, don't clobber it -
// ### I am not sue this is needed for GlobalCode
if (!variable->hasProperty(exec, ident))
variable->put(exec, ident, jsUndefined(), flags);
};
}
void VarDeclNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, init);
}
// ------------------------------ VarDeclListNode ------------------------------
void VarDeclListNode::breakCycle()
{
next = 0;
}
void VarDeclListNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, var);
recurseVisitLink(visitor, next);
}
// ------------------------------ VarStatementNode -----------------------------
void VarStatementNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, next);
}
// ------------------------------ BlockNode ------------------------------------
BlockNode::BlockNode(SourceElementsNode *s)
{
if (s) {
source = s->next.release();
Parser::removeNodeCycle(source.get());
setLoc(s->firstLine(), s->lastLine());
} else {
source = 0;
}
}
void BlockNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, source);
}
// ------------------------------ ExprStatementNode ----------------------------
void ExprStatementNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
}
// ------------------------------ IfNode ---------------------------------------
void IfNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
recurseVisitLink(visitor, statement1);
recurseVisitLink(visitor, statement2);
}
// ------------------------------ DoWhileNode ----------------------------------
void DoWhileNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
recurseVisitLink(visitor, statement);
}
// ------------------------------ WhileNode ------------------------------------
void WhileNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
recurseVisitLink(visitor, statement);
}
// ------------------------------ ForNode --------------------------------------
void ForNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr1);
recurseVisitLink(visitor, expr2);
recurseVisitLink(visitor, expr3);
recurseVisitLink(visitor, statement);
}
// ------------------------------ ForInNode ------------------------------------
ForInNode::ForInNode(Node *l, Node *e, StatementNode *s)
: init(0L), lexpr(l), expr(e), varDecl(0L), statement(s)
{
}
ForInNode::ForInNode(const Identifier &i, AssignExprNode *in, Node *e, StatementNode *s)
: ident(i), init(in), expr(e), statement(s)
{
// for( var foo = bar in baz )
varDecl = new VarDeclNode(ident, init.get(), VarDeclNode::Variable);
lexpr = new VarAccessNode(ident);
}
void ForInNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, init);
recurseVisitLink(visitor, lexpr);
recurseVisitLink(visitor, expr);
recurseVisitLink(visitor, varDecl);
recurseVisitLink(visitor, statement);
}
// ------------------------------ ReturnNode -----------------------------------
void ReturnNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, value);
}
// ------------------------------ WithNode -------------------------------------
void WithNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
recurseVisitLink(visitor, statement);
}
// ------------------------------ CaseClauseNode -------------------------------
void CaseClauseNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
recurseVisitLink(visitor, source);
}
// ------------------------------ ClauseListNode -------------------------------
void ClauseListNode::breakCycle()
{
next = 0;
}
void ClauseListNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, clause);
recurseVisitLink(visitor, next);
}
// ------------------------------ CaseBlockNode --------------------------------
CaseBlockNode::CaseBlockNode(ClauseListNode *l1, CaseClauseNode *d,
ClauseListNode *l2)
{
if (l1) {
list1 = l1->next.release();
Parser::removeNodeCycle(list1.get());
} else {
list1 = 0;
}
def = d;
if (l2) {
list2 = l2->next.release();
Parser::removeNodeCycle(list2.get());
} else {
list2 = 0;
}
}
void CaseBlockNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, list1);
recurseVisitLink(visitor, def);
recurseVisitLink(visitor, list2);
}
// ------------------------------ SwitchNode -----------------------------------
void SwitchNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
recurseVisitLink(visitor, block);
}
// ------------------------------ LabelNode ------------------------------------
void LabelNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, statement);
}
// ------------------------------ ThrowNode ------------------------------------
void ThrowNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, expr);
}
// ------------------------------ TryNode --------------------------------------
void TryNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, tryBlock);
recurseVisitLink(visitor, catchBlock);
recurseVisitLink(visitor, finallyBlock);
}
// ------------------------------ ParameterNode --------------------------------
void ParameterNode::breakCycle()
{
next = 0;
}
void ParameterNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, next);
}
// ------------------------------ FunctionBodyNode -----------------------------
FunctionBodyNode::FunctionBodyNode(SourceElementsNode *s)
: BlockNode(s)
, m_sourceURL(lexer().sourceURL())
, m_sourceId(parser().sourceId())
, m_compType(NotCompiled)
, m_flags(parser().popFunctionContext())
{
setLoc(-1, -1);
}
void FunctionBodyNode::addVarDecl(const Identifier& ident, int attr, ExecState* exec)
{
// There is one nasty special case: ignore a 'var' declaration of 'arguments';
// it effectively doesn't do anything since the magic 'arguments' is already
// in scope anyway, and if we allocated a local, we would have to worry about
// keeping track of whether it was initialized or not on what is supposed to be the
// fast path. So we just make this go through the property map instead.
// Note that this does not matter for parameters or function declarations,
// since those overwrite the magic 'arguments' anyway.
if (ident == exec->propertyNames().arguments)
return;
(void)addSymbol(ident, attr);
}
void FunctionBodyNode::addFunDecl(const Identifier& ident, int attr, FuncDeclNode* funcDecl)
{
m_functionLocals.append(addSymbol(ident, attr, funcDecl));
}
void FunctionBodyNode::reserveSlot(size_t id, bool shouldMark)
{
ASSERT(id == m_symbolList.size());
m_symbolList.append(SymbolInfo(shouldMark ? 0 : DontMark, 0));
}
size_t FunctionBodyNode::addSymbol(const Identifier& ident, int flags, FuncDeclNode* funcDecl)
{
// We get symbols in the order specified in 10.1.3, but sometimes
// the later ones are supposed to lose. This -mostly- does not
// matter for us --- we primarily concern ourselves with name/ID
// mapping, but there is an issue of attributes and funcDecl's.
// However, the only flag that matters here is ReadOnly --
// everything else just has DontDelete set; and it's from const,
// so we can just ignore it on repetitions, since var/const should lose
// and are at the end.
//
// And for funcDecl, since functions win over everything, we always set it if non-zero
size_t oldId = m_symbolTable.get(ident.ustring().rep());
if (oldId != missingSymbolMarker()) {
if (funcDecl)
m_symbolList[oldId].funcDecl = funcDecl;
return oldId;
}
size_t id = m_symbolList.size(); //First entry gets 0, etc.
m_symbolTable.set(ident.ustring().rep(), id);
m_symbolList.append(SymbolInfo(flags, funcDecl));
return id;
}
void FunctionBodyNode::addSymbolOverwriteID(size_t id, const Identifier& ident, int flags)
{
ASSERT(id == m_symbolList.size());
// Remove previous one, if any
size_t oldId = m_symbolTable.get(ident.ustring().rep());
if (oldId != missingSymbolMarker())
m_symbolList[oldId].attr = DontMark;
// Add a new one
m_symbolTable.set(ident.ustring().rep(), id);
m_symbolList.append(SymbolInfo(flags, 0));
}
void FunctionBodyNode::addParam(const Identifier& ident)
{
m_paramList.append(ident);
}
Completion FunctionBodyNode::execute(ExecState *exec)
{
CodeType ctype = exec->codeType();
CompileType cmpType = exec->dynamicInterpreter()->debugger() ? Debug : Release;
compileIfNeeded(ctype, cmpType);
ASSERT(ctype != FunctionCode);
LocalStorage* store = new LocalStorage();
LocalStorageEntry* regs;
// Allocate enough space, and make sure to initialize things so we don't mark garbage
store->resize(m_symbolList.size());
regs = store->data();
for (size_t c = 0; c < m_symbolList.size(); ++c) {
regs[c].val.valueVal = jsUndefined();
regs[c].attributes = m_symbolList[c].attr;
}
exec->initLocalStorage(regs, m_symbolList.size());
JSValue* val = Machine::runBlock(exec, m_compiledCode);
Completion result;
if (exec->hadException())
result = Completion(Throw, exec->exception());
else
result = Completion(Normal, val);
exec->initLocalStorage(0, 0);
delete store;
exec->clearException();
return result;
}
void FunctionBodyNode::compile(CodeType ctype, CompileType compType)
{
m_compType = compType;
CompileState comp(ctype, compType, this, m_symbolList.size());
generateExecCode(&comp);
m_tearOffAtEnd = comp.needsClosures();
#if 0
fprintf(stderr, "\n\n");
fprintf(stderr, "\n---------------------------------\n\n");
fprintf(stderr, "%s", toString().ascii());
fprintf(stderr, "\n---------------------------------\n\n");
CodeGen::disassembleBlock(m_compiledCode);
fprintf(stderr, "\n---------------------------------\n\n");
#endif
}
// ------------------------------ FuncDeclNode ---------------------------------
// ECMA 13
void FuncDeclNode::processFuncDecl(ExecState *exec)
{
// See whether we just need to fill in the symbol table,
// or actually fiddle with objects.
int flags = Internal | DontDelete;
switch (exec->codeType()) {
case FunctionCode:
// Inside a function, just need symbol info
exec->currentBody()->addFunDecl(ident, flags, this);
return;
case EvalCode:
// eval-injected symbols can be deleted...
flags &= ~DontDelete;
// eval injected a new local into scope! Better mark that down,
// so that NonLocalResolver stops skipping the local scope
exec->variableObject()->setLocalInjected();
// fallthrough intentional
case GlobalCode:
exec->variableObject()->put(exec, ident, makeFunctionObject(exec), flags);
};
}
void FuncDeclNode::addParams()
{
for (ParameterNode *p = param.get(); p != 0L; p = p->nextParam())
body->addParam(p->ident());
}
FunctionImp* FuncDeclNode::makeFunctionObject(ExecState *exec)
{
// TODO: let this be an object with [[Class]] property "Function"
FunctionImp *func = new FunctionImp(exec, ident, body.get(), exec->scopeChain());
JSObject *proto = exec->lexicalInterpreter()->builtinObject()->construct(exec, List::empty());
proto->put(exec, exec->propertyNames().constructor, func, DontEnum);
// ECMA Edition 5.1r6 - 15.3.5.2 - [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false
func->put(exec, exec->propertyNames().prototype, proto, Internal|DontDelete|DontEnum);
func->put(exec, exec->propertyNames().length, jsNumber(body->numParams()), ReadOnly|DontDelete|DontEnum);
return func;
}
void FuncDeclNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, param);
recurseVisitLink(visitor, body);
}
// ------------------------------ FuncExprNode ---------------------------------
void FuncExprNode::addParams()
{
for(ParameterNode *p = param.get(); p != 0L; p = p->nextParam())
body->addParam(p->ident());
}
void FuncExprNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, param);
recurseVisitLink(visitor, body);
}
// ------------------------------ SourceElementsNode ---------------------------
SourceElementsNode::SourceElementsNode(StatementNode *s1)
: node(s1), next(this)
{
Parser::noteNodeCycle(this);
setLoc(s1->firstLine(), s1->lastLine());
}
SourceElementsNode::SourceElementsNode(SourceElementsNode *s1, StatementNode *s2)
: node(s2), next(s1->next)
{
s1->next = this;
setLoc(s1->firstLine(), s2->lastLine());
}
void SourceElementsNode::breakCycle()
{
next = 0;
}
void SourceElementsNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, node);
recurseVisitLink(visitor, next);
}
// ------------------------------ ProgramNode ----------------------------------
ProgramNode::ProgramNode(SourceElementsNode *s) : FunctionBodyNode(s)
{
}
// ------------------------------ PackageNameNode ------------------------------
void PackageNameNode::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, names);
}
Completion PackageNameNode::loadSymbol(ExecState* exec, bool wildcard)
{
Package* basePackage;
JSObject* baseObject;
if (names) {
PackageObject *pobj = names->resolvePackage(exec);
if (pobj == 0)
return Completion(Normal);
basePackage = pobj->package();
baseObject = pobj;
} else {
Interpreter* ip = exec->lexicalInterpreter();
basePackage = ip->globalPackage();
baseObject = ip->globalObject();
}
if (wildcard) {
// if a .* is specified the last identifier should
// denote another package name
PackageObject* pobj = resolvePackage(exec, baseObject, basePackage);
if (!pobj)
return Completion(Normal);
basePackage = pobj->package();
baseObject = pobj;
basePackage->loadAllSymbols(exec, baseObject);
} else {
basePackage->loadSymbol(exec, baseObject, id);
}
return Completion(Normal);
}
PackageObject* PackageNameNode::resolvePackage(ExecState* exec)
{
JSObject* baseObject;
Package* basePackage;
if (names) {
PackageObject* basePackageObject = names->resolvePackage(exec);
if (basePackageObject == 0)
return 0;
baseObject = basePackageObject;
basePackage = basePackageObject->package();
} else {
// first identifier is looked up in global object
Interpreter* ip = exec->lexicalInterpreter();
baseObject = ip->globalObject();
basePackage = ip->globalPackage();
}
return resolvePackage(exec, baseObject, basePackage);
}
PackageObject* PackageNameNode::resolvePackage(ExecState* exec,
JSObject* baseObject,
Package* basePackage)
{
PackageObject* res = 0;
// Let's see whether the package was already resolved previously.
JSValue* v = baseObject->get(exec, id);
if (v && !v->isUndefined()) {
if (!v->isObject()) {
// Symbol conflict
throwError(exec, GeneralError, "Invalid type of package %s", id);
return 0;
}
res = static_cast<PackageObject*>(v);
} else {
UString err;
Package *newBase = basePackage->loadSubPackage(id, &err);
if (newBase == 0) {
if (err.isEmpty()) {
throwError(exec, GeneralError, "Package not found");
} else {
throwError(exec, GeneralError, err);
}
return 0;
}
res = new PackageObject(newBase);
baseObject->put(exec, id, res);
}
return res;
}
void ImportStatement::processVarDecl(ExecState* exec)
{
// error out if package support is not activated
Package* glob = exec->lexicalInterpreter()->globalPackage();
if (!glob) {
throwError(exec, GeneralError,
"Package support disabled. Import failed.");
return;
}
// also error out if not used on top-level
if (exec->codeType() != GlobalCode) {
throwError(exec, GeneralError,
"Package imports may only occur at top level.");
return;
}
name->loadSymbol(exec, wld);
}
void ImportStatement::recurseVisit(NodeVisitor *visitor)
{
recurseVisitLink(visitor, name);
}
} //namespace KJS