📄 nodes.cpp
字号:
/* * This file is part of the KDE libraries * Copyright (C) 1999-2001 Harri Porten (porten@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., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include "nodes.h"#include <assert.h>#include <stdio.h>#include <math.h>#include "kjs.h"#include "ustring.h"#include "lexer.h"#include "types.h"#include "internal.h"#include "operations.h"#include "regexp_object.h"#include "debugger.h"using namespace KJS;#ifdef KJS_DEBUGGER#define KJS_BREAKPOINT if (!hitStatement()) return Completion(Normal);#define KJS_ABORTPOINT if (abortStatement()) return Completion(Normal);#else#define KJS_BREAKPOINT#define KJS_ABORTPOINT#endifint Node::nodeCount = 0;Node* Node::first = 0;Node::Node(){ assert(Lexer::curr()); line = Lexer::curr()->lineNo(); nodeCount++; // cout << "Node()" << endl; // create a list of allocated objects. Makes // deleting (even after a parse error) quite easy next = first; prev = 0L; if (first) first->prev = this; first = this;}Node::~Node(){ // cout << "~Node()" << endl; if (next) next->prev = prev; if (prev) prev->next = next; nodeCount--;}void Node::deleteAllNodes(){ Node *tmp, *n = first; while ((tmp = n)) { n = n->next; delete tmp; } first = 0L; // assert(nodeCount == 0);}KJSO Node::throwError(ErrorType e, const char *msg){ return Error::create(e, msg, lineNo());}#ifdef KJS_DEBUGGERvoid StatementNode::setLoc(int line0, int line1){ l0 = line0; l1 = line1; sid = KJScriptImp::current()->sourceId();}bool StatementNode::hitStatement(){ if (KJScriptImp::current()->debugger()) return KJScriptImp::current()->debugger()->hit(firstLine(), breakPoint); else return true;}// return true if the debugger wants us to stop at this pointbool StatementNode::abortStatement(){ if (KJScriptImp::current()->debugger() && KJScriptImp::current()->debugger()->mode() == Debugger::Stop) return true; return false;}bool Node::setBreakpoint(Node *firstNode, int id, int line, bool set){ while (firstNode) { if (firstNode->setBreakpoint(id, line, set) && line >= 0) // line<0 for all return true; firstNode = firstNode->next; } return false;}/** * Try to set or delete a breakpoint depending on the value of set. * The call will return true if successful, i.e. if line is inside * of the statement's range. Additionally, a breakpoint had to * be set already if you tried to delete with set=false. */bool StatementNode::setBreakpoint(int id, int line, bool set){ // in our source unit and line range ? if (id != sid || ((line < l0 || line > l1) && line >= 0)) return false; if (!set && !breakPoint) return false; breakPoint = set; return true;}#endifKJSO NullNode::evaluate(){ return Null();}KJSO BooleanNode::evaluate(){ return Boolean(value);}KJSO NumberNode::evaluate(){ return Number(value);}KJSO StringNode::evaluate(){ return String(value);}KJSO RegExpNode::evaluate(){ List list; String p(pattern); String f(flags); list.append(p); list.append(f); // very ugly KJSO r = Global::current().get("RegExp"); RegExpObject *r2 = (RegExpObject*)r.imp(); return r2->construct(list);}// ECMA 11.1.1KJSO ThisNode::evaluate(){ return Context::current()->thisValue();}// ECMA 11.1.2 & 10.1.4KJSO ResolveNode::evaluate(){ assert(Context::current()); const List *chain = Context::current()->pScopeChain(); assert(chain); ListIterator scope = chain->begin(); while (scope != chain->end()) { if (scope->hasProperty(ident)) {// cout << "Resolve: found '" << ident.ascii() << "'"// << " type " << scope->get(ident).imp()->typeInfo()->name << endl; return Reference(*scope, ident); } scope++; } // identifier not found// cout << "Resolve: didn't find '" << ident.ascii() << "'" << endl; return Reference(Null(), ident);}// ECMA 11.1.4KJSO ArrayNode::evaluate(){ KJSO array; int length; int elisionLen = elision ? elision->evaluate().toInt32() : 0; if (element) { array = element->evaluate(); length = opt ? array.get("length").toInt32() : 0; } else { array = Object::create(ArrayClass); length = 0; } if (opt) array.put("length", Number(elisionLen + length), DontEnum | DontDelete); return array;}// ECMA 11.1.4KJSO ElementNode::evaluate(){ KJSO array, val; int length = 0; int elisionLen = elision ? elision->evaluate().toInt32() : 0; if (list) { array = list->evaluate(); val = node->evaluate().getValue(); length = array.get("length").toInt32(); } else { array = Object::create(ArrayClass); val = node->evaluate().getValue(); } array.putArrayElement(UString::from(elisionLen + length), val); return array;}// ECMA 11.1.4KJSO ElisionNode::evaluate(){ if (elision) return Number(elision->evaluate().toNumber().value() + 1); else return Number(1);}// ECMA 11.1.5KJSO ObjectLiteralNode::evaluate(){ if (list) return list->evaluate(); return Object::create(ObjectClass);}// ECMA 11.1.5KJSO PropertyValueNode::evaluate(){ KJSO obj; if (list) obj = list->evaluate(); else obj = Object::create(ObjectClass); KJSO n = name->evaluate(); KJSO a = assign->evaluate(); KJSO v = a.getValue(); obj.put(n.toString().value(), v); return obj;}// ECMA 11.1.5KJSO PropertyNode::evaluate(){ KJSO s; if (str.isNull()) { s = String(UString::from(numeric)); } else s = String(str); return s;}// ECMA 11.1.6KJSO GroupNode::evaluate(){ return group->evaluate();}// ECMA 11.2.1aKJSO AccessorNode1::evaluate(){ KJSO e1 = expr1->evaluate(); KJSO v1 = e1.getValue(); KJSO e2 = expr2->evaluate(); KJSO v2 = e2.getValue(); Object o = v1.toObject(); String s = v2.toString(); return Reference(o, s.value());}// ECMA 11.2.1bKJSO AccessorNode2::evaluate(){ KJSO e = expr->evaluate(); KJSO v = e.getValue(); KJSO o = v.toObject(); return Reference(o, ident);}// ECMA 11.2.2KJSO NewExprNode::evaluate(){ KJSO e = expr->evaluate(); KJSO v = e.getValue(); List *argList = args ? args->evaluateList() : 0; if (!v.isObject()) { delete argList; return throwError(TypeError, "Expression is no object. Cannot be new'ed"); } Constructor constr = Constructor::dynamicCast(v); if (constr.isNull()) { delete argList; return throwError(TypeError, "Expression is no constructor."); } if (!argList) argList = new List; KJSO res = constr.construct(*argList); delete argList; return res;}// ECMA 11.2.3KJSO FunctionCallNode::evaluate(){ KJSO e = expr->evaluate(); List *argList = args->evaluateList(); KJSO v = e.getValue(); if (!v.isObject()) {#ifndef NDEBUG printInfo("Failed function call attempt on", e);#endif delete argList; return throwError(TypeError, "Expression is no object. Cannot be called."); } if (!v.implementsCall()) {#ifndef NDEBUG printInfo("Failed function call attempt on", e);#endif delete argList; return throwError(TypeError, "Expression does not allow calls."); } KJSO o; if (e.isA(ReferenceType)) o = e.getBase(); else o = Null(); if (o.isA(ActivationType)) o = Null();#ifdef KJS_DEBUGGER steppingInto(true);#endif KJSO result = v.executeCall(o, argList);#ifdef KJS_DEBUGGER steppingInto(false);#endif delete argList; return result;}#ifdef KJS_DEBUGGERvoid FunctionCallNode::steppingInto(bool in){ Debugger *dbg = KJScriptImp::current()->debugger(); if (!dbg) return; if (in) { // before entering function. Don't step inside if 'Next' is chosen. previousMode = dbg->mode(); if (previousMode == Debugger::Next) dbg->setMode(Debugger::Continue); } else { // restore mode after leaving function dbg->setMode(previousMode); }}#endifKJSO ArgumentsNode::evaluate(){ assert(0); return KJSO(); // dummy, see evaluateList()}// ECMA 11.2.4List* ArgumentsNode::evaluateList(){ if (!list) return new List(); return list->evaluateList();}KJSO ArgumentListNode::evaluate(){ assert(0); return KJSO(); // dummy, see evaluateList()}// ECMA 11.2.4List* ArgumentListNode::evaluateList(){ KJSO e = expr->evaluate(); KJSO v = e.getValue(); if (!list) { List *l = new List(); l->append(v); return l; } List *l = list->evaluateList(); l->append(v); return l;}// ECMA 11.8KJSO RelationalNode::evaluate(){ KJSO e1 = expr1->evaluate(); KJSO v1 = e1.getValue(); KJSO e2 = expr2->evaluate(); KJSO v2 = e2.getValue(); bool b; if (oper == OpLess || oper == OpGreaterEq) { int r = relation(v1, v2); if (r < 0) b = false; else b = (oper == OpLess) ? (r == 1) : (r == 0); } else if (oper == OpGreater || oper == OpLessEq) { int r = relation(v2, v1); if (r < 0) b = false; else b = (oper == OpGreater) ? (r == 1) : (r == 0); } else if (oper == OpIn) { /* Is all of this OK for host objects? */ if (!v2.isObject()) return throwError( TypeError, "Shift expression not an object into IN expression." ); b = v2.hasProperty(v1.toString().value()); } else { /* TODO: should apply to Function _objects_ only */ if (!v2.derivedFrom("Function")) return throwError(TypeError, "Called instanceof operator on non-function object." ); return hasInstance(v2, v1); /* TODO: make object member function */ } return Boolean(b);}// ECMA 11.9KJSO EqualNode::evaluate(){ KJSO e1 = expr1->evaluate(); KJSO e2 = expr2->evaluate(); KJSO v1 = e1.getValue(); KJSO v2 = e2.getValue(); bool result; if (oper == OpEqEq || oper == OpNotEq) { // == and != bool eq = equal(v1, v2); result = oper == OpEqEq ? eq : !eq; } else { // === and !== bool eq = strictEqual(v1, v2); result = oper == OpStrEq ? eq : !eq; } return Boolean(result);}// ECMA 11.10KJSO BitOperNode::evaluate(){ KJSO e1 = expr1->evaluate(); KJSO v1 = e1.getValue(); KJSO e2 = expr2->evaluate(); KJSO v2 = e2.getValue(); int i1 = v1.toInt32(); int i2 = v2.toInt32(); int result; if (oper == OpBitAnd) result = i1 & i2; else if (oper == OpBitXOr) result = i1 ^ i2; else result = i1 | i2; return Number(result);}// ECMA 11.11KJSO BinaryLogicalNode::evaluate(){ KJSO e1 = expr1->evaluate(); KJSO v1 = e1.getValue(); Boolean b1 = v1.toBoolean(); if ((!b1.value() && oper == OpAnd) || (b1.value() && oper == OpOr)) return v1; KJSO e2 = expr2->evaluate(); KJSO v2 = e2.getValue(); return v2;}// ECMA 11.12KJSO ConditionalNode::evaluate(){ KJSO e = logical->evaluate(); KJSO v = e.getValue(); Boolean b = v.toBoolean(); if (b.value()) e = expr1->evaluate(); else e = expr2->evaluate(); return e.getValue();}// ECMA 11.13KJSO AssignNode::evaluate(){ KJSO l, e, v; ErrorType err; if (oper == OpEqual) { l = left->evaluate(); e = expr->evaluate(); v = e.getValue(); } else { l = left->evaluate(); KJSO v1 = l.getValue(); e = expr->evaluate(); KJSO v2 = e.getValue(); int i1 = v1.toInt32(); int i2 = v2.toInt32(); switch (oper) { case OpMultEq: v = mult(v1, v2, '*'); break; case OpDivEq: v = mult(v1, v2, '/'); break; case OpPlusEq: v = add(v1, v2, '+'); break; case OpMinusEq: v = add(v1, v2, '-'); break; case OpLShift: v = Number(i1 <<= i2); break; case OpRShift: v = Number(i1 >>= i2); break; case OpURShift: i1 = v1.toUInt32(); v = Number(i1 >>= i2); break; case OpAndEq: v = Number(i1 &= i2); break; case OpXOrEq: v = Number(i1 ^= i2); break; case OpOrEq: v = Number(i1 |= i2); break; case OpModEq: v = Number(i1 %= i2); break; default: v = Undefined(); } err = l.putValue(v); }; err = l.putValue(v); if (err == NoError) return v; else return throwError(err, "Invalid reference.");}// ECMA 11.3KJSO PostfixNode::evaluate(){ KJSO e = expr->evaluate(); KJSO v = e.getValue(); Number n = v.toNumber(); double newValue = (oper == OpPlusPlus) ? n.value() + 1 : n.value() - 1; KJSO n2 = Number(newValue); e.putValue(n2); return n;}// ECMA 11.4.1KJSO DeleteNode::evaluate(){ KJSO e = expr->evaluate(); if (!e.isA(ReferenceType)) return Boolean(true); KJSO b = e.getBase(); UString n = e.getPropertyName(); bool ret = b.deleteProperty(n); return Boolean(ret);}// ECMA 11.4.2KJSO VoidNode::evaluate(){ KJSO dummy1 = expr->evaluate(); KJSO dummy2 = dummy1.getValue(); return Undefined();}// ECMA 11.4.3KJSO TypeOfNode::evaluate(){ const char *s = 0L; KJSO e = expr->evaluate(); if (e.isA(ReferenceType)) { KJSO b = e.getBase(); if (b.isA(NullType)) return String("undefined"); } KJSO v = e.getValue(); switch (v.type()) { case UndefinedType: s = "undefined"; break; case NullType: s = "object"; break; case BooleanType: s = "boolean"; break; case NumberType: s = "number"; break; case StringType: s = "string"; break; default: if (v.implementsCall()) s = "function"; else s = "object"; break; } return String(s);}// ECMA 11.4.4 and 11.4.5KJSO PrefixNode::evaluate(){ KJSO e = expr->evaluate(); KJSO v = e.getValue(); Number n = v.toNumber(); double newValue = (oper == OpPlusPlus) ? n.value() + 1 : n.value() - 1; KJSO n2 = Number(newValue); e.putValue(n2); return n2;}// ECMA 11.4.6KJSO UnaryPlusNode::evaluate(){ KJSO e = expr->evaluate(); KJSO v = e.getValue(); return v.toNumber();}// ECMA 11.4.7KJSO NegateNode::evaluate(){ KJSO e = expr->evaluate(); KJSO v = e.getValue(); Number n = v.toNumber(); double d = -n.value(); return Number(d);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -