Bug 18774: SQUIRRELFISH: print meaningful error messages <https://bugs.webkit.org...
authoroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 19 Jul 2008 01:44:24 +0000 (01:44 +0000)
committeroliver@apple.com <oliver@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 19 Jul 2008 01:44:24 +0000 (01:44 +0000)
<rdar://problem/5769353> SQUIRRELFISH: JavaScript error messages are missing informative text

Reviewed by Cameron Zwarich

Add support for decent error messages in JavaScript.  This patch achieves this by providing
ensuring the common errors and exceptions have messages that provide the text of expression
that trigger the exception.  In addition it attaches a number of properties to the exception
object detailing where in the source the expression came from.

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

39 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/CodeBlock.h
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/CodeGenerator.h
JavaScriptCore/VM/ExceptionHelpers.cpp
JavaScriptCore/VM/ExceptionHelpers.h
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/kjs/DebuggerCallFrame.cpp
JavaScriptCore/kjs/Error.cpp
JavaScriptCore/kjs/Error.h
JavaScriptCore/kjs/JSGlobalObjectFunctions.cpp
JavaScriptCore/kjs/JSImmediate.cpp
JavaScriptCore/kjs/JSNotAnObject.h
JavaScriptCore/kjs/JSObject.h
JavaScriptCore/kjs/Parser.h
JavaScriptCore/kjs/SourceRange.h
JavaScriptCore/kjs/grammar.y
JavaScriptCore/kjs/lexer.cpp
JavaScriptCore/kjs/lexer.h
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/kjs/nodes.h
LayoutTests/ChangeLog
LayoutTests/fast/css/resources/font-face-descriptor-multiple-values-parsing.js
LayoutTests/fast/dom/SelectorAPI/dumpNodeList-expected.txt
LayoutTests/fast/forms/select-namedItem-expected.txt
LayoutTests/fast/js/exception-expression-offset.html [new file with mode: 0644]
LayoutTests/fast/js/resources/exception-expression-offset.js [new file with mode: 0644]
LayoutTests/fast/xsl/transform-xhr-doc-expected.txt
LayoutTests/http/tests/security/aboutBlank/xss-DENIED-navigate-opener-document-write-expected.txt
LayoutTests/http/tests/security/aboutBlank/xss-DENIED-navigate-opener-javascript-url-expected.txt
LayoutTests/http/tests/security/aboutBlank/xss-DENIED-set-opener-expected.txt
LayoutTests/http/tests/security/cross-frame-access-call.html
LayoutTests/platform/mac/fast/events/updateLayoutForHitTest-expected.txt
LayoutTests/platform/mac/svg/custom/createelement-expected.txt
LayoutTests/platform/mac/tables/mozilla/bugs/bug53690-1-expected.txt
LayoutTests/platform/mac/tables/mozilla_expected_failures/bugs/bug92868_1-expected.txt

index 72b93ea..aaf8498 100644 (file)
@@ -1,3 +1,138 @@
+2008-07-18  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Cameron Zwarich.
+
+        Bug 18774: SQUIRRELFISH: print meaningful error messages <https://bugs.webkit.org/show_bug.cgi?id=18774>
+        <rdar://problem/5769353> SQUIRRELFISH: JavaScript error messages are missing informative text
+
+        Add support for decent error messages in JavaScript.  This patch achieves this by providing
+        ensuring the common errors and exceptions have messages that provide the text of expression
+        that trigger the exception.  In addition it attaches a number of properties to the exception
+        object detailing where in the source the expression came from.
+
+        * JavaScriptCore.exp:
+        * VM/CodeBlock.cpp:
+        (KJS::CodeBlock::lineNumberForVPC):
+        (KJS::CodeBlock::expressionRangeForVPC): 
+            Function to recover the expression range for an instruction
+            that triggered an exception.
+        * VM/CodeBlock.h:
+        (KJS::ExpressionRangeInfo::):
+        (KJS::CodeBlock::CodeBlock):
+        * VM/CodeGenerator.cpp:
+        (KJS::CodeGenerator::emitCall):
+        (KJS::CodeGenerator::emitCallEval):
+            Emit call needed to be modified so to place the expression range info internally,
+            as the CodeGenerator emits the arguments nodes itself, rather than the various call
+            nodes.
+        * VM/CodeGenerator.h:
+        (KJS::CodeGenerator::emitExpressionInfo):
+            Record the expression range info.
+        * VM/ExceptionHelpers.cpp:
+        (KJS::createErrorMessage):
+        (KJS::createInvalidParamError):
+        (KJS::createUndefinedVariableError):
+        (KJS::createNotAConstructorError):
+        (KJS::createNotAFunctionError):
+        (KJS::createNotAnObjectErrorStub):
+        (KJS::createNotAnObjectError):
+            Rewrite all the code for the error messages so that they make use of the newly available
+            information.
+        * VM/ExceptionHelpers.h:
+        * VM/Machine.cpp:
+        (KJS::isNotObject):  Now needs vPC and codeBlock
+        (KJS::Machine::throwException):
+            New logic to handle the NotAnObjectErrorStub and to handle the absurd "no default value" edge case
+        (KJS::Machine::privateExecute):
+        * VM/Machine.h:
+        * kjs/DebuggerCallFrame.cpp:
+        (KJS::DebuggerCallFrame::evaluate):
+        * kjs/Error.cpp:
+        (KJS::Error::create):
+        * kjs/Error.h:
+        * kjs/JSGlobalObjectFunctions.cpp:
+        * kjs/JSImmediate.cpp:
+        (KJS::JSImmediate::toObject):
+        (KJS::JSImmediate::prototype):
+            My changes to the JSNotAnObject constructor needed to be handled here.
+        * kjs/JSNotAnObject.h:
+        (KJS::JSNotAnObjectErrorStub::JSNotAnObjectErrorStub):
+        (KJS::JSNotAnObjectErrorStub::isNull):
+        (KJS::JSNotAnObjectErrorStub::isNotAnObjectErrorStub):
+            Added a JSNotAnObjectErrorStub class to ease the handling of toObject failure exceptions,
+            and potentially allow even more detailed error messages in future.
+        * kjs/JSObject.h:
+        * kjs/Parser.h:
+        (KJS::Parser::parse):
+        * kjs/SourceRange.h:
+        * kjs/grammar.y:
+            Large amounts of position propagation.
+        * kjs/lexer.cpp:
+        (KJS::Lexer::Lexer):
+        (KJS::Lexer::shift):
+        (KJS::Lexer::lex):
+            The lexer needed a few changes to be able to correctly track token character positions.
+        * kjs/lexer.h:
+        * kjs/nodes.cpp:
+        (KJS::ThrowableExpressionData::emitThrowError):
+        (KJS::StatementNode::StatementNode):
+        (KJS::ResolveNode::emitCode):
+        (KJS::BracketAccessorNode::emitCode):
+        (KJS::DotAccessorNode::emitCode):
+        (KJS::NewExprNode::emitCode):
+        (KJS::EvalFunctionCallNode::emitCode):
+        (KJS::FunctionCallValueNode::emitCode):
+        (KJS::FunctionCallResolveNode::emitCode):
+        (KJS::FunctionCallBracketNode::emitCode):
+        (KJS::FunctionCallDotNode::emitCode):
+        (KJS::PostfixResolveNode::emitCode):
+        (KJS::PostfixBracketNode::emitCode):
+        (KJS::PostfixDotNode::emitCode):
+        (KJS::DeleteResolveNode::emitCode):
+        (KJS::DeleteBracketNode::emitCode):
+        (KJS::DeleteDotNode::emitCode):
+        (KJS::PrefixResolveNode::emitCode):
+        (KJS::PrefixBracketNode::emitCode):
+        (KJS::PrefixDotNode::emitCode):
+        (KJS::ThrowableBinaryOpNode::emitCode):
+        (KJS::ReadModifyResolveNode::emitCode):
+        (KJS::AssignResolveNode::emitCode):
+        (KJS::AssignDotNode::emitCode):
+        (KJS::ReadModifyDotNode::emitCode):
+        (KJS::AssignBracketNode::emitCode):
+        (KJS::ReadModifyBracketNode::emitCode):
+        (KJS::ForInNode::ForInNode):
+        (KJS::ForInNode::emitCode):
+        (KJS::WithNode::emitCode):
+        (KJS::LabelNode::emitCode):
+        (KJS::ThrowNode::emitCode):
+        (KJS::ProgramNode::ProgramNode):
+        (KJS::ProgramNode::create):
+        (KJS::EvalNode::generateCode):
+        (KJS::FunctionBodyNode::create):
+        (KJS::FunctionBodyNode::generateCode):
+        (KJS::ProgramNode::generateCode):
+            All of these methods were handling the position information.  
+            Constructors and create methods were modified to store the information.
+            All the emitCall implementations listed needed to be updated to actually
+            record the position information we have so carefully collected.
+        * kjs/nodes.h:
+        (KJS::ThrowableExpressionData::ThrowableExpressionData):
+        (KJS::ThrowableExpressionData::setExceptionSourceRange):
+        (KJS::ThrowableExpressionData::divot):
+        (KJS::ThrowableExpressionData::startOffset):
+        (KJS::ThrowableExpressionData::endOffset):
+        (KJS::ThrowableSubExpressionData::ThrowableSubExpressionData):
+        (KJS::ThrowableSubExpressionData::setSubexpressionInfo):
+        (KJS::ThrowablePrefixedSubExpressionData::ThrowablePrefixedSubExpressionData):
+        (KJS::ThrowablePrefixedSubExpressionData::setSubexpressionInfo):
+            ThrowableExpressionData is just a uniform mechanism for storing the position
+            information.
+        (KJS::ResolveNode::):
+        (KJS::PrePostResolveNode::):
+        (KJS::ThrowableBinaryOpNode::):
+        (KJS::WithNode::):
+
 2008-07-18  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Cameron Zwarich.
index b225aae..fe9ebc8 100644 (file)
@@ -92,7 +92,7 @@ __ZN3KJS11JSImmediate8toObjectEPKNS_7JSValueEPNS_9ExecStateE
 __ZN3KJS11JSImmediate8toStringEPKNS_7JSValueE
 __ZN3KJS11JSImmediate9prototypeEPKNS_7JSValueEPNS_9ExecStateE
 __ZN3KJS11ProfileNode4sortEPFbRKN3WTF6RefPtrIS0_EES5_E
-__ZN3KJS11ProgramNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairINS_10IdentifierEjELm16EEEPNS6_INS5_6RefPtrINS_12FuncDeclNodeEEELm16EEEbb
+__ZN3KJS11ProgramNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairINS_10IdentifierEjELm16EEEPNS6_INS5_6RefPtrINS_12FuncDeclNodeEEELm16EEEPNS_14SourceProviderEbb
 __ZN3KJS11PropertyMap11getLocationERKNS_10IdentifierE
 __ZN3KJS11PropertyMap11getLocationERKNS_10IdentifierERb
 __ZN3KJS11PropertyMap3putERKNS_10IdentifierEPNS_7JSValueEjb
index 0d702d1..0b54b73 100644 (file)
@@ -654,6 +654,7 @@ bool CodeBlock::getHandlerForVPC(const Instruction* vPC, Instruction*& target, i
 
 int CodeBlock::lineNumberForVPC(const Instruction* vPC)
 {
+    ASSERT(lineInfo.size());    
     unsigned instructionOffset = vPC - instructions.begin();
     ASSERT(instructionOffset < instructions.size());
 
@@ -669,8 +670,44 @@ int CodeBlock::lineNumberForVPC(const Instruction* vPC)
         else
             high = mid;
     }
-
     return lineInfo[low - 1].lineNumber;
 }
 
+int CodeBlock::expressionRangeForVPC(const Instruction* vPC, int& divot, int& startOffset, int& endOffset)
+{
+    unsigned instructionOffset = vPC - instructions.begin();
+    ASSERT(instructionOffset < instructions.size());
+
+    if (!expressionInfo.size()) {
+        // We didn't think anything could throw.  Apparently we were wrong.
+        startOffset = 0;
+        endOffset = 0;
+        divot = 0;
+        return lineNumberForVPC(vPC);
+    }
+
+    int low = 0;
+    int high = expressionInfo.size();
+    while (low < high) {
+        int mid = low + (high - low) / 2;
+        if (expressionInfo[mid].instructionOffset <= instructionOffset)
+            low = mid + 1;
+        else
+            high = mid;
+    }
+    
+    ASSERT(low);
+    if (!low) {
+        startOffset = 0;
+        endOffset = 0;
+        divot = 0;
+        return lineNumberForVPC(vPC);
+    }
+
+    startOffset = expressionInfo[low - 1].startOffset;
+    endOffset = expressionInfo[low - 1].endOffset;
+    divot = expressionInfo[low - 1].divotPoint + sourceOffset;
+    return lineNumberForVPC(vPC);
+}
+
 } // namespace KJS
index 80adb9a..6bdbe73 100644 (file)
@@ -33,6 +33,7 @@
 #include "Instruction.h"
 #include "JSGlobalObject.h"
 #include "nodes.h"
+#include "SourceRange.h"
 #include "ustring.h"
 #include <wtf/RefPtr.h>
 #include <wtf/Vector.h>
@@ -44,19 +45,29 @@ namespace KJS {
     static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); }
 
     struct HandlerInfo {
-        unsigned start;
-        unsigned end;
-        unsigned target;
-        unsigned scopeDepth;
+        uint32_t start;
+        uint32_t end;
+        uint32_t target;
+        uint32_t scopeDepth;
+    };
+
+    struct ExpressionRangeInfo {
+        enum { MaxOffset = (1 << 7) - 1, 
+               MaxDivot = (1 << 25) - 1
+        };
+        uint32_t instructionOffset : 25;
+        uint32_t divotPoint : 25;
+        uint32_t startOffset : 7;
+        uint32_t endOffset : 7;
     };
 
     struct LineInfo {
-        unsigned instructionOffset;
-        int lineNumber;
+        uint32_t instructionOffset;
+        int32_t lineNumber;
     };
 
     struct CodeBlock {
-        CodeBlock(ScopeNode* ownerNode_, CodeType codeType_)
+        CodeBlock(ScopeNode* ownerNode_, CodeType codeType_, PassRefPtr<SourceProvider> source_, unsigned sourceOffset_)
             : ownerNode(ownerNode_)
             , numTemporaries(0)
             , numVars(0)
@@ -65,11 +76,14 @@ namespace KJS {
             , needsFullScopeChain(ownerNode_->usesEval() || ownerNode_->needsClosure())
             , usesEval(ownerNode_->usesEval())
             , codeType(codeType_)
+            , source(source_)
+            , sourceOffset(sourceOffset_)
         {
         }
 
         void dump(ExecState*) const;
-        int lineNumberForVPC(const Instruction*);
+        int expressionRangeForVPC(const Instruction*, int& divot, int& startOffset, int& endOffset);
+        int lineNumberForVPC(const Instruction* vPC);
         bool getHandlerForVPC(const Instruction* vPC, Instruction*& target, int& scopeDepth);
         void mark();
 
@@ -83,6 +97,8 @@ namespace KJS {
         bool needsFullScopeChain;
         bool usesEval;
         CodeType codeType;
+        RefPtr<SourceProvider> source;
+        unsigned sourceOffset;
 
         Vector<Instruction> instructions;
 
@@ -93,6 +109,7 @@ namespace KJS {
         Vector<Register> registers;
         Vector<RefPtr<RegExp> > regexps;
         Vector<HandlerInfo> exceptionHandlers;
+        Vector<ExpressionRangeInfo> expressionInfo;
         Vector<LineInfo> lineInfo;
 
     private:
@@ -103,8 +120,8 @@ namespace KJS {
     // responsible for marking it.
 
     struct ProgramCodeBlock : public CodeBlock {
-        ProgramCodeBlock(ScopeNode* ownerNode_, CodeType codeType_, JSGlobalObject* globalObject_)
-            : CodeBlock(ownerNode_, codeType_)
+        ProgramCodeBlock(ScopeNode* ownerNode_, CodeType codeType_, JSGlobalObject* globalObject_, PassRefPtr<SourceProvider> source_)
+            : CodeBlock(ownerNode_, codeType_, source_, 0)
             , globalObject(globalObject_)
         {
             globalObject->codeBlocks().add(this);
@@ -120,8 +137,8 @@ namespace KJS {
     };
 
     struct EvalCodeBlock : public ProgramCodeBlock {
-        EvalCodeBlock(ScopeNode* ownerNode_, JSGlobalObject* globalObject_)
-            : ProgramCodeBlock(ownerNode_, EvalCode, globalObject_)
+        EvalCodeBlock(ScopeNode* ownerNode_, JSGlobalObject* globalObject_, PassRefPtr<SourceProvider> source_)
+            : ProgramCodeBlock(ownerNode_, EvalCode, globalObject_, source_)
         {
         }
     };
index 768ec47..07cb873 100644 (file)
@@ -849,17 +849,17 @@ RegisterID* CodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNod
     return r0;
 }
 
-RegisterID* CodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode)
+RegisterID* CodeGenerator::emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
 {
-    return emitCall(op_call, dst, func, base, argumentsNode);
+    return emitCall(op_call, dst, func, base, argumentsNode, divot, startOffset, endOffset);
 }
 
-RegisterID* CodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode)
+RegisterID* CodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
 {
-    return emitCall(op_call_eval, dst, func, base, argumentsNode);
+    return emitCall(op_call_eval, dst, func, base, argumentsNode, divot, startOffset, endOffset);
 }
 
-RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode)
+RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
 {
     ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
     
@@ -882,6 +882,7 @@ RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Register
         emitNode(argv.last().get(), n);
     }
 
+    emitExpressionInfo(divot, startOffset, endOffset);
     emitOpcode(opcodeID);
     instructions().append(dst->index());
     instructions().append(func->index());
index 133bd69..ee1b239 100644 (file)
@@ -182,6 +182,35 @@ namespace KJS {
             return emitNode(0, n);
         }
 
+        void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset)
+        { 
+            divot -= m_codeBlock->sourceOffset;
+            if (divot > ExpressionRangeInfo::MaxDivot) {
+                // Overflow has occurred, we can only give line number info for errors for this region
+                divot = 0;
+                startOffset = 0;
+                endOffset = 0;
+            } else if (startOffset > ExpressionRangeInfo::MaxOffset) {
+                // If the start offset is out of bounds we clear both offsets
+                // so we only get the divot marker.  Error message will have to be reduced
+                // to line and column number.
+                startOffset = 0;
+                endOffset = 0;
+            } else if (endOffset > ExpressionRangeInfo::MaxOffset) {
+                // The end offset is only used for additional context, and is much more likely
+                // to overflow (eg. function call arguments) so we are willing to drop it without
+                // dropping the rest of the range.
+                endOffset = 0;
+            }
+            
+            ExpressionRangeInfo info;
+            info.instructionOffset = instructions().size();
+            info.divotPoint = divot;
+            info.startOffset = startOffset;
+            info.endOffset = endOffset;
+            m_codeBlock->expressionInfo.append(info);
+        }
+        
         ALWAYS_INLINE bool leftHandSideNeedsCopy(bool rightHasAssignments, bool rightIsPure)
         {
             return (m_codeType != FunctionCode || m_codeBlock->needsFullScopeChain || rightHasAssignments) && !rightIsPure;
@@ -244,8 +273,8 @@ namespace KJS {
         RegisterID* emitPutGetter(RegisterID* base, const Identifier& property, RegisterID* value);
         RegisterID* emitPutSetter(RegisterID* base, const Identifier& property, RegisterID* value);
 
-        RegisterID* emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode*);
-        RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode*);
+        RegisterID* emitCall(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+        RegisterID* emitCallEval(RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
 
         RegisterID* emitReturn(RegisterID* src) { return emitUnaryNoDstOp(op_ret, src); } 
         RegisterID* emitEnd(RegisterID* src) { return emitUnaryNoDstOp(op_end, src); }
@@ -312,7 +341,7 @@ namespace KJS {
 
         typedef HashMap<RefPtr<UString::Rep>, int, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, IdentifierMapIndexHashTraits> IdentifierMap;
 
-        RegisterID* emitCall(OpcodeID, RegisterID*, RegisterID*, RegisterID*, ArgumentsNode*);
+        RegisterID* emitCall(OpcodeID, RegisterID*, RegisterID*, RegisterID*, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
 
         // Maps a register index in the symbol table to a RegisterID index in m_locals.
         int localsIndex(int registerIndex) { return -registerIndex - 1; }
index 81d97d9..46c7b59 100644 (file)
 #include "config.h"
 #include "ExceptionHelpers.h"
 
+#include "CodeBlock.h"
 #include "ExecState.h"
 #include "nodes.h"
 #include "JSObject.h"
+#include "JSNotAnObject.h"
 
 namespace KJS {
 
@@ -67,15 +69,6 @@ JSValue* createError(ExecState* exec, ErrorType e, const char* msg, const Identi
     return Error::create(exec, e, message, -1, -1, 0);
 }
 
-JSValue* createError(ExecState* exec, ErrorType e, const char* msg, JSValue* v, Node* expr)
-{
-    UString message = msg;
-    substitute(message, v->toString(exec));
-    if (expr)
-        substitute(message, expr->toString());
-    return Error::create(exec, e, message, -1, -1, 0);
-}
-
 JSValue* createError(ExecState* exec, ErrorType e, const char* msg, JSValue* v)
 {
     UString message = msg;
@@ -88,31 +81,137 @@ JSValue* createStackOverflowError(ExecState* exec)
     return createError(exec, RangeError, "Maximum call stack size exceeded.");
 }
 
-JSValue* createUndefinedVariableError(ExecState* exec, const Identifier& ident)
+JSValue* createUndefinedVariableError(ExecState* exec, const Identifier& ident, const Instruction* vPC, CodeBlock* codeBlock)
+{
+    int startOffset = 0;
+    int endOffset = 0;
+    int divotPoint = 0;
+    int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
+    UString message = "Can't find variable: ";
+    message.append(ident.ustring());
+    JSObject* exception = Error::create(exec, ReferenceError, message, line, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
+    exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
+    exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
+    exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
+    return exception;
+}
+    
+bool isStrWhiteSpace(UChar c);
+
+static UString createErrorMessage(ExecState* exec, CodeBlock* codeBlock, int, int expressionStart, int expressionStop, JSValue* value, UString error)
+{
+    if (!expressionStop || expressionStart > codeBlock->source->length()) {
+        UString errorText = value->toString(exec);
+        errorText.append(" is ");
+        errorText.append(error);
+        return errorText;
+    }
+
+    UString errorText = "Result of expression ";
+    
+    if (expressionStart < expressionStop) {
+        errorText.append('\'');
+        errorText.append(codeBlock->source->getRange(expressionStart, expressionStop));
+        errorText.append("' [");
+        errorText.append(value->toString(exec));
+        errorText.append("] is ");
+    } else {
+        // No range information, so give a few characters of context
+        const UChar* data = codeBlock->source->data();
+        int dataLength = codeBlock->source->length();
+        int start = expressionStart;
+        int stop = expressionStart;
+        // Get up to 20 characters of context to the left and right of the divot, clamping to the line.
+        // then strip whitespace.
+        while (start > 0 && (expressionStart - start < 20) && data[start - 1] != '\n')
+            start--;
+        while (start < (expressionStart - 1) && isStrWhiteSpace(data[start]))
+            start++;
+        while (stop < dataLength && (stop - expressionStart < 20) && data[stop] != '\n')
+            stop++;
+        while (stop > expressionStart && isStrWhiteSpace(data[stop]))
+            stop--;
+        errorText.append("near '...");
+        errorText.append(codeBlock->source->getRange(start, stop));
+        errorText.append("...' [");
+        errorText.append(value->toString(exec));
+        errorText.append("] is ");
+    }
+    errorText.append(error);
+    errorText.append(".");
+    return errorText;
+}
+
+JSValue* createInvalidParamError(ExecState* exec, const char* op, JSValue* value, const Instruction* vPC, CodeBlock* codeBlock)
+{
+    UString message = "not a valid argument for '";
+    message.append(op);
+    message.append("'");
+    
+    int startOffset = 0;
+    int endOffset = 0;
+    int divotPoint = 0;
+    int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
+    UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, message);
+    JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
+    exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
+    exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
+    exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
+    return exception;
+}
+
+JSValue* createNotAConstructorError(ExecState* exec, JSValue* value, const Instruction* vPC, CodeBlock* codeBlock)
 {
-    return createError(exec, ReferenceError, "Can't find variable: %s", ident);
+    int startOffset = 0;
+    int endOffset = 0;
+    int divotPoint = 0;
+    int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
+
+    // We're in a "new" expression, so we need to skip over the "new.." part
+    int startPoint = divotPoint - (startOffset ? startOffset - 4 : 0); // -4 for "new "
+    const UChar* data = codeBlock->source->data();
+    while (startPoint < divotPoint && isStrWhiteSpace(data[startPoint]))
+        startPoint++;
+    
+    UString errorMessage = createErrorMessage(exec, codeBlock, line, startPoint, divotPoint, value, "not a constructor");
+    JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
+    exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
+    exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
+    exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
+    return exception;
 }
 
-JSValue* createInvalidParamError(ExecState* exec, const char* op, JSValue* v)
+JSValue* createNotAFunctionError(ExecState* exec, JSValue* value, const Instruction* vPC, CodeBlock* codeBlock)
 {
-    UString message = "'%s' is not a valid argument for '%s'";
-    substitute(message,  v->toString(exec));
-    substitute(message, op);
-    return Error::create(exec, TypeError, message, -1, -1, 0);
+    int startOffset = 0;
+    int endOffset = 0;
+    int divotPoint = 0;
+    int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
+    UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, value, "not a function");
+    JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());    
+    exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
+    exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
+    exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
+    return exception;
 }
 
-JSValue* createNotAConstructorError(ExecState* exec, JSValue* value, Node* expr)
+JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState* exec, bool isNull)
 {
-    if (expr)
-        return createError(exec, TypeError, "Value %s (result of expression %s) is not a constructor. Cannot be used with new.", value, expr);
-    return createError(exec, TypeError, "Value %s is not a constructor. Cannot be used with new.", value);
+    return new (exec) JSNotAnObjectErrorStub(isNull);
 }
 
-JSValue* createNotAFunctionError(ExecState* exec, JSValue* value, Node* expr)
+JSObject* createNotAnObjectError(ExecState* exec, JSNotAnObjectErrorStub* error, const Instruction* vPC, CodeBlock* codeBlock)
 {
-    if (expr)
-        return createError(exec, TypeError, "Value %s (result of expression %s) does not allow function calls.", value, expr);
-    return createError(exec, TypeError, "Value %s does not allow function calls.", value);
+    int startOffset = 0;
+    int endOffset = 0;
+    int divotPoint = 0;
+    int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
+    UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, error->isNull() ? jsNull() : jsUndefined(), "not an object");
+    JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL());
+    exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
+    exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete);
+    exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
+    return exception;
 }
 
 } // namespace KJS
index 99846a3..a7f39e5 100644 (file)
 namespace KJS {
 
     class Node;
+    class CodeBlock;
+    class Instruction;
+    class JSNotAnObjectErrorStub;
 
     JSValue* createInterruptedExecutionException(ExecState* exec);
     JSValue* createStackOverflowError(ExecState*);
-    JSValue* createUndefinedVariableError(ExecState*, const Identifier&);
-    JSValue* createInvalidParamError(ExecState*, const char* op, JSValue*);
-    JSValue* createNotAConstructorError(ExecState*, JSValue*, Node* expr);
-    JSValue* createNotAFunctionError(ExecState*, JSValue*, Node* expr);
+    JSValue* createUndefinedVariableError(ExecState*, const Identifier&, const Instruction*, CodeBlock*);
+    JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState*, bool isNull);
+    JSValue* createInvalidParamError(ExecState*, const char* op, JSValue*, const Instruction*, CodeBlock*);
+    JSValue* createNotAConstructorError(ExecState*, JSValue*, const Instruction*, CodeBlock*);
+    JSValue* createNotAFunctionError(ExecState*, JSValue*, const Instruction*, CodeBlock*);
+    JSObject* createNotAnObjectError(ExecState*, JSNotAnObjectErrorStub*, const Instruction*, CodeBlock*);
 
 } // namespace KJS
 
index 1e6021e..b4fefa4 100644 (file)
@@ -38,6 +38,7 @@
 #include "JSActivation.h"
 #include "JSArray.h"
 #include "JSFunction.h"
+#include "JSNotAnObject.h"
 #include "JSPropertyNameIterator.h"
 #include "JSString.h"
 #include "ObjectPrototype.h"
@@ -221,7 +222,7 @@ static bool NEVER_INLINE resolve(ExecState* exec, Instruction* vPC, Register* r,
             return true;
         }
     } while (++iter != end);
-    exceptionValue = createUndefinedVariableError(exec, ident);
+    exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
     return false;
 }
 
@@ -251,7 +252,7 @@ static bool NEVER_INLINE resolve_skip(ExecState* exec, Instruction* vPC, Registe
             return true;
         }
     } while (++iter != end);
-    exceptionValue = createUndefinedVariableError(exec, ident);
+    exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
     return false;
 }
 
@@ -310,7 +311,7 @@ static bool NEVER_INLINE resolveBaseAndProperty(ExecState* exec, Instruction* vP
         ++iter;
     } while (iter != end);
 
-    exceptionValue = createUndefinedVariableError(exec, ident);
+    exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
     return false;
 }
 
@@ -353,7 +354,7 @@ static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, R
         ++iter;
     } while (iter != end);
 
-    exceptionValue = createUndefinedVariableError(exec, ident);
+    exceptionValue = createUndefinedVariableError(exec, ident, vPC, codeBlock);
     return false;
 }
 
@@ -429,11 +430,11 @@ ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNod
     return callDataScopeChain;
 }
 
-static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock*, JSValue* value, JSValue*& exceptionData)
+static NEVER_INLINE bool isNotObject(ExecState* exec, bool forInstanceOf, CodeBlock* codeBlock, const Instruction* vPC, JSValue* value, JSValue*& exceptionData)
 {
     if (value->isObject())
         return false;
-    exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value);
+    exceptionData = createInvalidParamError(exec, forInstanceOf ? "instanceof" : "in" , value, vPC, codeBlock);
     return true;
 }
 
@@ -619,22 +620,45 @@ NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionVa
     return true;
 }
 
-NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue* exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, Register*& k, ScopeChainNode*& scopeChain, Register*& r)
+NEVER_INLINE Instruction* Machine::throwException(ExecState* exec, JSValue*& exceptionValue, const Instruction* vPC, CodeBlock*& codeBlock, Register*& k, ScopeChainNode*& scopeChain, Register*& r, bool explicitThrow)
 {
     // Set up the exception object
 
     if (exceptionValue->isObject()) {
         JSObject* exception = static_cast<JSObject*>(exceptionValue);
-        if (!exception->hasProperty(exec, Identifier(exec, "line")) && !exception->hasProperty(exec, Identifier(exec, "sourceURL"))) {
-            exception->put(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)));
-            exception->put(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()));
-        }
-
-        if (exception->isWatchdogException()) {
-            while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, k, scopeChain, r)) {
-                 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
+        if (exception->isNotAnObjectErrorStub()) {
+            exception = createNotAnObjectError(exec, static_cast<JSNotAnObjectErrorStub*>(exception), vPC, codeBlock);
+            exceptionValue = exception;
+        } else {
+            if (!exception->hasProperty(exec, Identifier(exec, "line")) && 
+                !exception->hasProperty(exec, Identifier(exec, "sourceId")) && 
+                !exception->hasProperty(exec, Identifier(exec, "sourceURL")) && 
+                !exception->hasProperty(exec, Identifier(exec, expressionBeginOffsetPropertyName)) && 
+                !exception->hasProperty(exec, Identifier(exec, expressionCaretOffsetPropertyName)) && 
+                !exception->hasProperty(exec, Identifier(exec, expressionEndOffsetPropertyName))) {
+                if (explicitThrow) {
+                    int startOffset = 0;
+                    int endOffset = 0;
+                    int divotPoint = 0;
+                    int line = codeBlock->expressionRangeForVPC(vPC, divotPoint, startOffset, endOffset);
+                    exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, line), ReadOnly | DontDelete);
+                    
+                    // We only hit this path for error messages and throw statements, which don't have a specific failure position
+                    // So we just give the full range of the error/throw statement.
+                    exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete);
+                    exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete);
+                } else
+                    exception->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, codeBlock->lineNumberForVPC(vPC)), ReadOnly | DontDelete);
+                exception->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, codeBlock->ownerNode->sourceId()), ReadOnly | DontDelete);
+                exception->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL()), ReadOnly | DontDelete);
+            }
+            
+            if (exception->isWatchdogException()) {
+                while (unwindCallFrame(exec, exceptionValue, vPC, codeBlock, k, scopeChain, r)) {
+                    // Don't need handler checks or anything, we just want to unroll all the JS callframes possible.
+                }
+                return 0;
             }
-            return 0;
         }
     }
 
@@ -1576,7 +1600,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
         JSValue* baseVal = r[base].jsValue();
 
-        if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
+        if (isNotObject(exec, true, codeBlock, vPC, baseVal, exceptionValue))
             goto vm_throw;
 
         JSObject* baseObj = static_cast<JSObject*>(baseVal);
@@ -1612,7 +1636,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         int base = (++vPC)->u.operand;
 
         JSValue* baseVal = r[base].jsValue();
-        if (isNotObject(exec, vPC, codeBlock, baseVal, exceptionValue))
+        if (isNotObject(exec, false, codeBlock, vPC, baseVal, exceptionValue))
             goto vm_throw;
 
         JSObject* baseObj = static_cast<JSObject*>(baseVal);
@@ -2281,7 +2305,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
         ASSERT(callType == CallTypeNone);
 
-        exceptionValue = createNotAFunctionError(exec, v, 0);
+        exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
         goto vm_throw;
     }
     BEGIN_OPCODE(op_ret) {
@@ -2406,7 +2430,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
         ASSERT(constructType == ConstructTypeNone);
 
-        exceptionValue = createNotAConstructorError(exec, constrVal, 0);
+        exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
         goto vm_throw;
     }
     BEGIN_OPCODE(op_push_scope) {
@@ -2522,7 +2546,8 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
         int ex = (++vPC)->u.operand;
         exceptionValue = r[ex].jsValue();
-        handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, k, scopeChain, r);
+
+        handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, k, scopeChain, r, true);
         if (!handlerVPC) {
             *exception = exceptionValue;
             return jsNull();
@@ -2662,7 +2687,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             // cannot fathom if we don't assign to the exceptionValue before branching)
             exceptionValue = createInterruptedExecutionException(exec);
         }
-        handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, k, scopeChain, r);
+        handlerVPC = throwException(exec, exceptionValue, vPC, codeBlock, k, scopeChain, r, false);
         if (!handlerVPC) {
             *exception = exceptionValue;
             return jsNull();
index b33732d..f19557c 100644 (file)
@@ -132,7 +132,7 @@ namespace KJS {
         NEVER_INLINE void debug(ExecState*, const Instruction*, const CodeBlock*, ScopeChainNode*, Register*);
 
         NEVER_INLINE bool unwindCallFrame(ExecState*, JSValue*, const Instruction*&, CodeBlock*&, Register*&, ScopeChainNode*&, Register*&);
-        NEVER_INLINE Instruction* throwException(ExecState*, JSValue*, const Instruction*, CodeBlock*&, Register*&, ScopeChainNode*&, Register*&);
+        NEVER_INLINE Instruction* throwException(ExecState*, JSValue*&, const Instruction*, CodeBlock*&, Register*&, ScopeChainNode*&, Register*&, bool);
 
         Register* callFrame(ExecState*, JSFunction*) const;
 
index c55ce6c..2af5050 100644 (file)
@@ -80,9 +80,8 @@ JSValue* DebuggerCallFrame::evaluate(const UString& script, JSValue*& exception)
     int sourceId;
     int errLine;
     UString errMsg;
-
-    RefPtr<EvalNode> evalNode = newExec.parser()->parse<EvalNode>(&newExec, UString(), 1, UStringSourceProvider::create(script), &sourceId, &errLine, &errMsg);
-
+    RefPtr<SourceProvider> sourceProvider = UStringSourceProvider::create(script);
+    RefPtr<EvalNode> evalNode = newExec.parser()->parse<EvalNode>(&newExec, UString(), 1, sourceProvider, &sourceId, &errLine, &errMsg);
     if (!evalNode)
         return Error::create(&newExec, SyntaxError, errMsg, errLine, sourceId, 0);
 
index 5c31158..a2a6460 100644 (file)
 
 namespace KJS {
 
+const char* expressionBeginOffsetPropertyName = "expressionBeginOffset";
+const char* expressionCaretOffsetPropertyName = "expressionCaretOffset";
+const char* expressionEndOffsetPropertyName = "expressionEndOffset";
+
 JSObject* Error::create(ExecState* exec, ErrorType type, const UString& message, int lineNumber, int sourceId, const UString& sourceURL)
 {
     JSObject* constructor;
@@ -78,11 +82,11 @@ JSObject* Error::create(ExecState* exec, ErrorType type, const UString& message,
     JSObject* error = construct(exec, constructor, constructType, constructData, args);
 
     if (lineNumber != -1)
-        error->put(exec, Identifier(exec, "line"), jsNumber(exec, lineNumber));
+        error->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, lineNumber), ReadOnly | DontDelete);
     if (sourceId != -1)
-        error->put(exec, Identifier(exec, "sourceId"), jsNumber(exec, sourceId));
+        error->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, sourceId), ReadOnly | DontDelete);
     if (!sourceURL.isNull())
-        error->put(exec, Identifier(exec, "sourceURL"), jsString(exec, sourceURL));
+        error->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsString(exec, sourceURL), ReadOnly | DontDelete);
 
     return error;
 }
index 8018e6a..d242c6b 100644 (file)
@@ -42,7 +42,11 @@ namespace KJS {
         TypeError      = 5,
         URIError       = 6
     };
-
+    
+    extern const char* expressionBeginOffsetPropertyName;
+    extern const char* expressionCaretOffsetPropertyName;
+    extern const char* expressionEndOffsetPropertyName;
+    
     class Error {
     public:
         static JSObject* create(ExecState*, ErrorType, const UString& message, int lineNumber, int sourceId, const UString& sourceURL);
index 6a38e8b..294a57a 100644 (file)
@@ -136,7 +136,7 @@ static JSValue* decode(ExecState* exec, const ArgList& args, const char* doNotUn
     return jsString(exec, result);
 }
 
-static bool isStrWhiteSpace(unsigned short c)
+bool isStrWhiteSpace(unsigned short c)
 {
     switch (c) {
         case 0x0009:
index 3e3d251..edb5a69 100644 (file)
@@ -24,6 +24,7 @@
 #include "BooleanConstructor.h"
 #include "BooleanPrototype.h"
 #include "Error.h"
+#include "ExceptionHelpers.h"
 #include "JSGlobalObject.h"
 #include "JSNotAnObject.h"
 #include "NumberConstructor.h"
@@ -38,10 +39,10 @@ JSObject* JSImmediate::toObject(const JSValue* v, ExecState* exec)
         return constructNumberFromImmediateNumber(exec, const_cast<JSValue*>(v));
     if (isBoolean(v))
         return constructBooleanFromImmediateBoolean(exec, const_cast<JSValue*>(v));
-    if (v == jsNull())
-        return new (exec) JSNotAnObject(throwError(exec, TypeError, "Null value"));
-    ASSERT(v == jsUndefined());
-    return new (exec) JSNotAnObject(throwError(exec, TypeError, "Undefined value"));
+    
+    JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v == jsNull());
+    exec->setException(exception);
+    return new (exec) JSNotAnObject(exception);
 }
 
 JSObject* JSImmediate::prototype(const JSValue* v, ExecState* exec)
@@ -51,10 +52,10 @@ JSObject* JSImmediate::prototype(const JSValue* v, ExecState* exec)
         return exec->lexicalGlobalObject()->numberPrototype();
     if (isBoolean(v))
         return exec->lexicalGlobalObject()->booleanPrototype();
-    if (v == jsNull())
-        return new (exec) JSNotAnObject(throwError(exec, TypeError, "Null value"));
-    ASSERT(v == jsUndefined());
-    return new (exec) JSNotAnObject(throwError(exec, TypeError, "Undefined value"));
+
+    JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v == jsNull());
+    exec->setException(exception);
+    return new (exec) JSNotAnObject(exception);
 }
 
 UString JSImmediate::toString(const JSValue* v)
index 8d82dff..133f2d7 100644 (file)
 
 namespace KJS {
 
+    class JSNotAnObjectErrorStub : public JSObject {
+    public:
+        JSNotAnObjectErrorStub(bool isNull)
+            : m_isNull(isNull)
+        {
+        }
+        bool isNull() const { return m_isNull; }
+        bool isNotAnObjectErrorStub() const { return true; }
+    private:
+        bool m_isNull;
+    };
+    
     // This unholy class is used to allow us to avoid multiple exception checks
     // in certain SquirrelFish opcodes -- effectively it just silently consumes
     // any operations performed on the result of a failed toObject call.
     class JSNotAnObject : public JSObject {
     public:
-        JSNotAnObject(JSObject* exception)
+        JSNotAnObject(JSNotAnObjectErrorStub* exception)
             : m_exception(exception)
         {
         }
@@ -67,7 +79,7 @@ namespace KJS {
 
         virtual void getPropertyNames(ExecState*, PropertyNameArray&);
 
-        JSObject* m_exception;
+        JSNotAnObjectErrorStub* m_exception;
     };
 
 } // namespace KJS
index 3900aee..3aea262 100644 (file)
@@ -323,6 +323,8 @@ namespace KJS {
         virtual bool isVariableObject() const { return false; }
 
         virtual bool isWatchdogException() const { return false; }
+        
+        virtual bool isNotAnObjectErrorStub() const { return false; }
 
     protected:
         PropertyMap m_propertyMap;
index 2dc859d..9492ef0 100644 (file)
@@ -80,7 +80,8 @@ namespace KJS {
                                          int* sourceId, int* errLine, UString* errMsg)
     {
         m_sourceURL = sourceURL;
-        parse(exec, sourceURL, startingLineNumber, source, sourceId, errLine, errMsg);
+        RefPtr<SourceProvider> sourceProvider = source;
+        parse(exec, sourceURL, startingLineNumber, sourceProvider.get(), sourceId, errLine, errMsg);
         if (!m_sourceElements) {
             m_sourceURL = UString();
             return 0;
@@ -89,6 +90,7 @@ namespace KJS {
                                                      m_sourceElements.release().get(),
                                                      m_varDeclarations ? &m_varDeclarations->data : 0, 
                                                      m_funcDeclarations ? &m_funcDeclarations->data : 0,
+                                                     sourceProvider.get(),
                                                      m_usesEval,
                                                      m_needsClosure);
         m_varDeclarations = 0;
index ff0f9c3..3d329d9 100644 (file)
@@ -53,7 +53,9 @@ namespace KJS {
                 return UString();
             return m_sourceProvider->getRange(m_startChar, m_endChar);
         }
-
+        
+        SourceProvider* sourceProvider() const { return m_sourceProvider.get(); }
+        int startOffset() const { return m_startChar; }
     private:
         RefPtr<SourceProvider> m_sourceProvider;
         int m_startChar;
index f80826e..ec970c9 100644 (file)
@@ -57,18 +57,19 @@ static inline bool allowAutomaticSemicolon(KJS::Lexer&, int);
 #define LEXER (GLOBAL_DATA->lexer)
 
 #define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon(*LEXER, yychar)) YYABORT; } while (0)
+#define SET_EXCEPTION_LOCATION(node, start, divot, end) node->setExceptionSourceRange((divot), (divot) - (start), (end) - (divot))
 #define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line)
 
 using namespace KJS;
 using namespace std;
 
-static ExpressionNode* makeAssignNode(void*, ExpressionNode* loc, Operator, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments);
-static ExpressionNode* makePrefixNode(void*, ExpressionNode* expr, Operator);
-static ExpressionNode* makePostfixNode(void*, ExpressionNode* expr, Operator);
+static ExpressionNode* makeAssignNode(void*, ExpressionNode* loc, Operator, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end);
+static ExpressionNode* makePrefixNode(void*, ExpressionNode* expr, Operator, int start, int divot, int end);
+static ExpressionNode* makePostfixNode(void*, ExpressionNode* expr, Operator, int start, int divot, int end);
 static PropertyNode* makeGetterOrSetterPropertyNode(void*, const Identifier &getOrSet, const Identifier& name, ParameterNode*, FunctionBodyNode*, const SourceRange&);
-static ExpressionNodeInfo makeFunctionCallNode(void*, ExpressionNodeInfo func, ArgumentsNodeInfo);
+static ExpressionNodeInfo makeFunctionCallNode(void*, ExpressionNodeInfo func, ArgumentsNodeInfo, int start, int divot, int end);
 static ExpressionNode* makeTypeOfNode(void*, ExpressionNode*);
-static ExpressionNode* makeDeleteNode(void*, ExpressionNode*);
+static ExpressionNode* makeDeleteNode(void*, ExpressionNode*, int start, int divot, int end);
 static ExpressionNode* makeNegateNode(void*, ExpressionNode*);
 static NumberNode* makeNumberNode(void*, double);
 static StatementNode* makeVarStatementNode(void*, ExpressionNode*);
@@ -287,13 +288,19 @@ Literal:
                                             Lexer& l = *LEXER;
                                             if (!l.scanRegExp())
                                                 YYABORT;
-                                            $$ = createNodeFeatureInfo<ExpressionNode*>(new RegExpNode(GLOBAL_DATA, l.pattern(), l.flags()), 0);
+                                            RegExpNode* node = new RegExpNode(GLOBAL_DATA, l.pattern(), l.flags());
+                                            int size = l.pattern().size() + 2; // + 2 for the two /'s
+                                            SET_EXCEPTION_LOCATION(node, @1.first_column, @1.first_column + size, @1.first_column + size);
+                                            $$ = createNodeFeatureInfo<ExpressionNode*>(node, 0);
                                         }
   | DIVEQUAL /* regexp with /= */       {
                                             Lexer& l = *LEXER;
                                             if (!l.scanRegExp())
                                                 YYABORT;
-                                            $$ = createNodeFeatureInfo<ExpressionNode*>(new RegExpNode(GLOBAL_DATA, "=" + l.pattern(), l.flags()), 0);
+                                            RegExpNode* node = new RegExpNode(GLOBAL_DATA, l.pattern(), l.flags());
+                                            int size = l.pattern().size() + 2; // + 2 for the two /'s
+                                            SET_EXCEPTION_LOCATION(node, @1.first_column, @1.first_column + size, @1.first_column + size);
+                                            $$ = createNodeFeatureInfo<ExpressionNode*>(node, 0);
                                         }
 ;
 
@@ -327,7 +334,7 @@ PrimaryExprNoBrace:
     THISTOKEN                           { $$ = createNodeFeatureInfo<ExpressionNode*>(new ThisNode(GLOBAL_DATA), 0); }
   | Literal
   | ArrayLiteral
-  | IDENT                               { $$ = createNodeFeatureInfo<ExpressionNode*>(new ResolveNode(GLOBAL_DATA, *$1), 0); }
+  | IDENT                               { $$ = createNodeFeatureInfo<ExpressionNode*>(new ResolveNode(GLOBAL_DATA, *$1, @1.first_column), 0); }
   | '(' Expr ')'                        { $$ = $2; }
 ;
 
@@ -360,40 +367,75 @@ Elision:
 MemberExpr:
     PrimaryExpr
   | FunctionExpr                        { $$ = createNodeFeatureInfo<ExpressionNode*>($1.m_node, $1.m_featureInfo); }
-  | MemberExpr '[' Expr ']'             { $$ = createNodeFeatureInfo<ExpressionNode*>(new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
-  | MemberExpr '.' IDENT                { $$ = createNodeFeatureInfo<ExpressionNode*>(new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3), $1.m_featureInfo); }
-  | NEW MemberExpr Arguments            { $$ = createNodeFeatureInfo<ExpressionNode*>(new NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node), $2.m_featureInfo | $3.m_featureInfo); }
+  | MemberExpr '[' Expr ']'             { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo | $3.m_featureInfo); 
+                                        }
+  | MemberExpr '.' IDENT                { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo);
+                                        }
+  | NEW MemberExpr Arguments            { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @3.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $2.m_featureInfo | $3.m_featureInfo);
+                                        }
 ;
 
 MemberExprNoBF:
     PrimaryExprNoBrace
-  | MemberExprNoBF '[' Expr ']'         { $$ = createNodeFeatureInfo<ExpressionNode*>(new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
-  | MemberExprNoBF '.' IDENT            { $$ = createNodeFeatureInfo<ExpressionNode*>(new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3), $1.m_featureInfo); }
-  | NEW MemberExpr Arguments            { $$ = createNodeFeatureInfo<ExpressionNode*>(new NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node), $2.m_featureInfo | $3.m_featureInfo); }
+  | MemberExprNoBF '[' Expr ']'         { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo | $3.m_featureInfo); 
+                                        }
+  | MemberExprNoBF '.' IDENT            { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo);
+                                        }
+  | NEW MemberExpr Arguments            { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @3.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $2.m_featureInfo | $3.m_featureInfo);
+                                        }
 ;
 
 NewExpr:
     MemberExpr
-  | NEW NewExpr                         { $$ = createNodeFeatureInfo<ExpressionNode*>(new NewExprNode(GLOBAL_DATA, $2.m_node), $2.m_featureInfo); }
+  | NEW NewExpr                         { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $2.m_featureInfo); 
+                                        }
 ;
 
 NewExprNoBF:
     MemberExprNoBF
-  | NEW NewExpr                         { $$ = createNodeFeatureInfo<ExpressionNode*>(new NewExprNode(GLOBAL_DATA, $2.m_node), $2.m_featureInfo); }
+  | NEW NewExpr                         { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $2.m_featureInfo); 
+                                        }
 ;
 
 CallExpr:
-    MemberExpr Arguments                { $$ = makeFunctionCallNode(globalPtr, $1, $2); }
-  | CallExpr Arguments                  { $$ = makeFunctionCallNode(globalPtr, $1, $2); }
-  | CallExpr '[' Expr ']'               { $$ = createNodeFeatureInfo<ExpressionNode*>(new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
-  | CallExpr '.' IDENT                  { $$ = createNodeFeatureInfo<ExpressionNode*>(new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3), $1.m_featureInfo); }
+    MemberExpr Arguments                { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
+  | CallExpr Arguments                  { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
+  | CallExpr '[' Expr ']'               { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo | $3.m_featureInfo); 
+                                        }
+  | CallExpr '.' IDENT                  { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo); }
 ;
 
 CallExprNoBF:
-    MemberExprNoBF Arguments            { $$ = makeFunctionCallNode(globalPtr, $1, $2); }
-  | CallExprNoBF Arguments              { $$ = makeFunctionCallNode(globalPtr, $1, $2); }
-  | CallExprNoBF '[' Expr ']'           { $$ = createNodeFeatureInfo<ExpressionNode*>(new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
-  | CallExprNoBF '.' IDENT              { $$ = createNodeFeatureInfo<ExpressionNode*>(new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3), $1.m_featureInfo); }
+    MemberExprNoBF Arguments            { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
+  | CallExprNoBF Arguments              { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
+  | CallExprNoBF '[' Expr ']'           { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo | $3.m_featureInfo); 
+                                        }
+  | CallExprNoBF '.' IDENT              { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column);
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo); 
+                                        }
 ;
 
 Arguments:
@@ -422,24 +464,24 @@ LeftHandSideExprNoBF:
 
 PostfixExpr:
     LeftHandSideExpr
-  | LeftHandSideExpr PLUSPLUS           { $$ = createNodeFeatureInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus), $1.m_featureInfo | AssignFeature); }
-  | LeftHandSideExpr MINUSMINUS         { $$ = createNodeFeatureInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus), $1.m_featureInfo | AssignFeature); }
+  | LeftHandSideExpr PLUSPLUS           { $$ = createNodeFeatureInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus, @1.first_column, @1.last_column, @2.last_column), $1.m_featureInfo | AssignFeature); }
+  | LeftHandSideExpr MINUSMINUS         { $$ = createNodeFeatureInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus, @1.first_column, @1.last_column, @2.last_column), $1.m_featureInfo | AssignFeature); }
 ;
 
 PostfixExprNoBF:
     LeftHandSideExprNoBF
-  | LeftHandSideExprNoBF PLUSPLUS       { $$ = createNodeFeatureInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus), $1.m_featureInfo | AssignFeature); }
-  | LeftHandSideExprNoBF MINUSMINUS     { $$ = createNodeFeatureInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus), $1.m_featureInfo | AssignFeature); }
+  | LeftHandSideExprNoBF PLUSPLUS       { $$ = createNodeFeatureInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus, @1.first_column, @1.last_column, @2.last_column), $1.m_featureInfo | AssignFeature); }
+  | LeftHandSideExprNoBF MINUSMINUS     { $$ = createNodeFeatureInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus, @1.first_column, @1.last_column, @2.last_column), $1.m_featureInfo | AssignFeature); }
 ;
 
 UnaryExprCommon:
-    DELETETOKEN UnaryExpr               { $$ = createNodeFeatureInfo<ExpressionNode*>(makeDeleteNode(GLOBAL_DATA, $2.m_node), $2.m_featureInfo); }
+    DELETETOKEN UnaryExpr               { $$ = createNodeFeatureInfo<ExpressionNode*>(makeDeleteNode(GLOBAL_DATA, $2.m_node, @1.first_column, @2.last_column, @2.last_column), $2.m_featureInfo); }
   | VOIDTOKEN UnaryExpr                 { $$ = createNodeFeatureInfo<ExpressionNode*>(new VoidNode(GLOBAL_DATA, $2.m_node), $2.m_featureInfo); }
   | TYPEOF UnaryExpr                    { $$ = createNodeFeatureInfo<ExpressionNode*>(makeTypeOfNode(GLOBAL_DATA, $2.m_node), $2.m_featureInfo); }
-  | PLUSPLUS UnaryExpr                  { $$ = createNodeFeatureInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus), $2.m_featureInfo | AssignFeature); }
-  | AUTOPLUSPLUS UnaryExpr              { $$ = createNodeFeatureInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus), $2.m_featureInfo | AssignFeature); }
-  | MINUSMINUS UnaryExpr                { $$ = createNodeFeatureInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus), $2.m_featureInfo | AssignFeature); }
-  | AUTOMINUSMINUS UnaryExpr            { $$ = createNodeFeatureInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus), $2.m_featureInfo | AssignFeature); }
+  | PLUSPLUS UnaryExpr                  { $$ = createNodeFeatureInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_featureInfo | AssignFeature); }
+  | AUTOPLUSPLUS UnaryExpr              { $$ = createNodeFeatureInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_featureInfo | AssignFeature); }
+  | MINUSMINUS UnaryExpr                { $$ = createNodeFeatureInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_featureInfo | AssignFeature); }
+  | AUTOMINUSMINUS UnaryExpr            { $$ = createNodeFeatureInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_featureInfo | AssignFeature); }
   | '+' UnaryExpr                       { $$ = createNodeFeatureInfo<ExpressionNode*>(new UnaryPlusNode(GLOBAL_DATA, $2.m_node), $2.m_featureInfo); }
   | '-' UnaryExpr                       { $$ = createNodeFeatureInfo<ExpressionNode*>(makeNegateNode(GLOBAL_DATA, $2.m_node), $2.m_featureInfo); }
   | '~' UnaryExpr                       { $$ = createNodeFeatureInfo<ExpressionNode*>(new BitwiseNotNode(GLOBAL_DATA, $2.m_node), $2.m_featureInfo); }
@@ -506,8 +548,12 @@ RelationalExpr:
   | RelationalExpr '>' ShiftExpr        { $$ = createNodeFeatureInfo<ExpressionNode*>(new GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
   | RelationalExpr LE ShiftExpr         { $$ = createNodeFeatureInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
   | RelationalExpr GE ShiftExpr         { $$ = createNodeFeatureInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
-  | RelationalExpr INSTANCEOF ShiftExpr { $$ = createNodeFeatureInfo<ExpressionNode*>(new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
-  | RelationalExpr INTOKEN ShiftExpr    { $$ = createNodeFeatureInfo<ExpressionNode*>(new InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
+  | RelationalExpr INSTANCEOF ShiftExpr { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column);  
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo | $3.m_featureInfo); }
+  | RelationalExpr INTOKEN ShiftExpr    { InNode* node = new InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column);  
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo | $3.m_featureInfo); }
 ;
 
 RelationalExprNoIn:
@@ -517,7 +563,9 @@ RelationalExprNoIn:
   | RelationalExprNoIn LE ShiftExpr     { $$ = createNodeFeatureInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
   | RelationalExprNoIn GE ShiftExpr     { $$ = createNodeFeatureInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
   | RelationalExprNoIn INSTANCEOF ShiftExpr
-                                        { $$ = createNodeFeatureInfo<ExpressionNode*>(new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
+                                        { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column);  
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo | $3.m_featureInfo); }
 ;
 
 RelationalExprNoBF:
@@ -527,8 +575,13 @@ RelationalExprNoBF:
   | RelationalExprNoBF LE ShiftExpr     { $$ = createNodeFeatureInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
   | RelationalExprNoBF GE ShiftExpr     { $$ = createNodeFeatureInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
   | RelationalExprNoBF INSTANCEOF ShiftExpr
-                                        { $$ = createNodeFeatureInfo<ExpressionNode*>(new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
-  | RelationalExprNoBF INTOKEN ShiftExpr     { $$ = createNodeFeatureInfo<ExpressionNode*>(new InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo); }
+                                        { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column);  
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo | $3.m_featureInfo); }
+  | RelationalExprNoBF INTOKEN ShiftExpr 
+                                        { InNode* node = new InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column);  
+                                          $$ = createNodeFeatureInfo<ExpressionNode*>(node, $1.m_featureInfo | $3.m_featureInfo); }
 ;
 
 EqualityExpr:
@@ -666,19 +719,25 @@ ConditionalExprNoBF:
 AssignmentExpr:
     ConditionalExpr
   | LeftHandSideExpr AssignmentOperator AssignmentExpr
-                                        { $$ = createNodeFeatureInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_featureInfo & AssignFeature, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo | AssignFeature); }
+                                        { $$ = createNodeFeatureInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_featureInfo & AssignFeature, $3.m_featureInfo & AssignFeature, 
+                                                                                                     @1.first_column, @2.first_column + 1, @3.last_column), $1.m_featureInfo | $3.m_featureInfo | AssignFeature); 
+                                        }
 ;
 
 AssignmentExprNoIn:
     ConditionalExprNoIn
   | LeftHandSideExpr AssignmentOperator AssignmentExprNoIn
-                                        { $$ = createNodeFeatureInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_featureInfo & AssignFeature, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo | AssignFeature); }
+                                        { $$ = createNodeFeatureInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_featureInfo & AssignFeature, $3.m_featureInfo & AssignFeature, 
+                                                                                                     @1.first_column, @2.first_column + 1, @3.last_column), $1.m_featureInfo | $3.m_featureInfo | AssignFeature);
+                                        }
 ;
 
 AssignmentExprNoBF:
     ConditionalExprNoBF
   | LeftHandSideExprNoBF AssignmentOperator AssignmentExpr
-                                        { $$ = createNodeFeatureInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_featureInfo & AssignFeature, $3.m_featureInfo & AssignFeature), $1.m_featureInfo | $3.m_featureInfo | AssignFeature); }
+                                        { $$ = createNodeFeatureInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_featureInfo & AssignFeature, $3.m_featureInfo & AssignFeature,
+                                                                                                     @1.first_column, @2.first_column + 1, @3.last_column), $1.m_featureInfo | $3.m_featureInfo | AssignFeature); 
+                                        }
 ;
 
 AssignmentOperator:
@@ -752,7 +811,9 @@ VariableDeclarationList:
                                           $$.m_funcDeclarations = 0;
                                           $$.m_featureInfo = 0;
                                         }
-  | IDENT Initializer                   { $$.m_node = new AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_featureInfo & AssignFeature);
+  | IDENT Initializer                   { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.first_column + 1, @2.last_column);
+                                          $$.m_node = node;
                                           $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA);
                                           appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
                                           $$.m_funcDeclarations = 0;
@@ -766,7 +827,9 @@ VariableDeclarationList:
                                           $$.m_featureInfo = $1.m_featureInfo;
                                         }
   | VariableDeclarationList ',' IDENT Initializer
-                                        { $$.m_node = combineVarInitializers(GLOBAL_DATA, $1.m_node, new AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_featureInfo & AssignFeature));
+                                        { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @3.first_column, @4.first_column + 1, @4.last_column);
+                                          $$.m_node = combineVarInitializers(GLOBAL_DATA, $1.m_node, node);
                                           $$.m_varDeclarations = $1.m_varDeclarations;
                                           appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
                                           $$.m_funcDeclarations = 0;
@@ -781,7 +844,9 @@ VariableDeclarationListNoIn:
                                           $$.m_funcDeclarations = 0;
                                           $$.m_featureInfo = 0;
                                         }
-  | IDENT InitializerNoIn               { $$.m_node = new AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_featureInfo & AssignFeature);
+  | IDENT InitializerNoIn               { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.first_column + 1, @2.last_column);
+                                          $$.m_node = node;
                                           $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA);
                                           appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
                                           $$.m_funcDeclarations = 0;
@@ -795,7 +860,9 @@ VariableDeclarationListNoIn:
                                           $$.m_featureInfo = $1.m_featureInfo;
                                         }
   | VariableDeclarationListNoIn ',' IDENT InitializerNoIn
-                                        { $$.m_node = combineVarInitializers(GLOBAL_DATA, $1.m_node, new AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_featureInfo & AssignFeature));
+                                        { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_featureInfo & AssignFeature);
+                                          SET_EXCEPTION_LOCATION(node, @3.first_column, @4.first_column + 1, @4.last_column);
+                                          $$.m_node = combineVarInitializers(GLOBAL_DATA, $1.m_node, node);
                                           $$.m_varDeclarations = $1.m_varDeclarations;
                                           appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
                                           $$.m_funcDeclarations = 0;
@@ -887,17 +954,21 @@ IterationStatement:
                                             ExpressionNode* n = $3.m_node;
                                             if (!n->isLocation())
                                                 YYABORT;
-                                            $$ = createNodeDeclarationInfo<StatementNode*>(new ForInNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node), $7.m_varDeclarations, $7.m_funcDeclarations,
+                                            ForInNode* node = new ForInNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node);
+                                            SET_EXCEPTION_LOCATION(node, @3.first_column, @3.last_column, @5.last_column);
+                                            $$ = createNodeDeclarationInfo<StatementNode*>(node, $7.m_varDeclarations, $7.m_funcDeclarations,
                                                                                            $3.m_featureInfo | $5.m_featureInfo | $7.m_featureInfo);
                                             DBG($$.m_node, @1, @6);
                                         }
   | FOR '(' VAR IDENT INTOKEN Expr ')' Statement
-                                        { ForInNode *forIn = new ForInNode(GLOBAL_DATA, *$4, 0, $6.m_node, $8.m_node);
+                                        { ForInNode *forIn = new ForInNode(GLOBAL_DATA, *$4, 0, $6.m_node, $8.m_node, @5.first_column, @5.first_column - @4.first_column, @6.last_column - @5.first_column);
+                                          SET_EXCEPTION_LOCATION(forIn, @4.first_column, @5.first_column + 1, @6.last_column);
                                           appendToVarDeclarationList(GLOBAL_DATA, $8.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
                                           $$ = createNodeDeclarationInfo<StatementNode*>(forIn, $8.m_varDeclarations, $8.m_funcDeclarations, $6.m_featureInfo | $8.m_featureInfo);
                                           DBG($$.m_node, @1, @7); }
   | FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement
-                                        { ForInNode *forIn = new ForInNode(GLOBAL_DATA, *$4, $5.m_node, $7.m_node, $9.m_node);
+                                        { ForInNode *forIn = new ForInNode(GLOBAL_DATA, *$4, $5.m_node, $7.m_node, $9.m_node, @5.first_column, @5.first_column - @4.first_column, @5.last_column - @5.first_column);
+                                          SET_EXCEPTION_LOCATION(forIn, @4.first_column, @6.first_column + 1, @7.last_column);
                                           appendToVarDeclarationList(GLOBAL_DATA, $9.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
                                           $$ = createNodeDeclarationInfo<StatementNode*>(forIn, $9.m_varDeclarations, $9.m_funcDeclarations,
                                                                                          $5.m_featureInfo | $7.m_featureInfo | $9.m_featureInfo);
@@ -915,33 +986,57 @@ ExprNoInOpt:
 ;
 
 ContinueStatement:
-    CONTINUE ';'                        { $$ = createNodeDeclarationInfo<StatementNode*>(new ContinueNode(GLOBAL_DATA), 0, 0, 0);
+    CONTINUE ';'                        { ContinueNode* node = new ContinueNode(GLOBAL_DATA);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); 
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0);
                                           DBG($$.m_node, @1, @2); }
-  | CONTINUE error                      { $$ = createNodeDeclarationInfo<StatementNode*>(new ContinueNode(GLOBAL_DATA), 0, 0, 0);
+  | CONTINUE error                      { ContinueNode* node = new ContinueNode(GLOBAL_DATA);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); 
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0);
                                           DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
-  | CONTINUE IDENT ';'                  { $$ = createNodeDeclarationInfo<StatementNode*>(new ContinueNode(GLOBAL_DATA, *$2), 0, 0, 0);
+  | CONTINUE IDENT ';'                  { ContinueNode* node = new ContinueNode(GLOBAL_DATA, *$2);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); 
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0);
                                           DBG($$.m_node, @1, @3); }
-  | CONTINUE IDENT error                { $$ = createNodeDeclarationInfo<StatementNode*>(new ContinueNode(GLOBAL_DATA, *$2), 0, 0, 0);
+  | CONTINUE IDENT error                { ContinueNode* node = new ContinueNode(GLOBAL_DATA, *$2);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); 
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0);
                                           DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
 ;
 
 BreakStatement:
-    BREAK ';'                           { $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA), 0, 0, 0); DBG($$.m_node, @1, @2); }
-  | BREAK error                         { $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA), 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
-  | BREAK IDENT ';'                     { $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA, *$2), 0, 0, 0); DBG($$.m_node, @1, @3); }
-  | BREAK IDENT error                   { $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA, *$2), 0, 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
+    BREAK ';'                           { BreakNode* node = new BreakNode(GLOBAL_DATA);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column);
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0); DBG($$.m_node, @1, @2); }
+  | BREAK error                         { BreakNode* node = new BreakNode(GLOBAL_DATA);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column);
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA), 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+  | BREAK IDENT ';'                     { BreakNode* node = new BreakNode(GLOBAL_DATA, *$2);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0); DBG($$.m_node, @1, @3); }
+  | BREAK IDENT error                   { BreakNode* node = new BreakNode(GLOBAL_DATA, *$2);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA, *$2), 0, 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
 ;
 
 ReturnStatement:
-    RETURN ';'                          { $$ = createNodeDeclarationInfo<StatementNode*>(new ReturnNode(GLOBAL_DATA, 0), 0, 0, 0); DBG($$.m_node, @1, @2); }
-  | RETURN error                        { $$ = createNodeDeclarationInfo<StatementNode*>(new ReturnNode(GLOBAL_DATA, 0), 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
-  | RETURN Expr ';'                     { $$ = createNodeDeclarationInfo<StatementNode*>(new ReturnNode(GLOBAL_DATA, $2.m_node), 0, 0, $2.m_featureInfo); DBG($$.m_node, @1, @3); }
-  | RETURN Expr error                   { $$ = createNodeDeclarationInfo<StatementNode*>(new ReturnNode(GLOBAL_DATA, $2.m_node), 0, 0, $2.m_featureInfo); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
+    RETURN ';'                          { ReturnNode* node = new ReturnNode(GLOBAL_DATA, 0); 
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); 
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0); DBG($$.m_node, @1, @2); }
+  | RETURN error                        { ReturnNode* node = new ReturnNode(GLOBAL_DATA, 0); 
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); 
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+  | RETURN Expr ';'                     { ReturnNode* node = new ReturnNode(GLOBAL_DATA, $2.m_node); 
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_featureInfo); DBG($$.m_node, @1, @3); }
+  | RETURN Expr error                   { ReturnNode* node = new ReturnNode(GLOBAL_DATA, $2.m_node); 
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); 
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_featureInfo); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
 ;
 
 WithStatement:
-    WITH '(' Expr ')' Statement         { $$ = createNodeDeclarationInfo<StatementNode*>(new WithNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations,
-                                                                                         $3.m_featureInfo | $5.m_featureInfo);
+    WITH '(' Expr ')' Statement         { $$ = createNodeDeclarationInfo<StatementNode*>(new WithNode(GLOBAL_DATA, $3.m_node, $5.m_node, @3.last_column, @3.last_column - @3.first_column),
+                                                                                         $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_featureInfo | $5.m_featureInfo);
                                           DBG($$.m_node, @1, @4); }
 ;
 
@@ -991,12 +1086,20 @@ DefaultClause:
 
 LabelledStatement:
     IDENT ':' Statement                 { $3.m_node->pushLabel(*$1);
-                                          $$ = createNodeDeclarationInfo<StatementNode*>(new LabelNode(GLOBAL_DATA, *$1, $3.m_node), $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_featureInfo); }
+                                          LabelNode* node = new LabelNode(GLOBAL_DATA, *$1, $3.m_node);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_featureInfo); }
 ;
 
 ThrowStatement:
-    THROW Expr ';'                      { $$ = createNodeDeclarationInfo<StatementNode*>(new ThrowNode(GLOBAL_DATA, $2.m_node), 0, 0, $2.m_featureInfo); DBG($$.m_node, @1, @3); }
-  | THROW Expr error                    { $$ = createNodeDeclarationInfo<StatementNode*>(new ThrowNode(GLOBAL_DATA, $2.m_node), 0, 0, $2.m_featureInfo); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
+    THROW Expr ';'                      { ThrowNode* node = new ThrowNode(GLOBAL_DATA, $2.m_node);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_featureInfo); DBG($$.m_node, @1, @2);
+                                        }
+  | THROW Expr error                    { ThrowNode* node = new ThrowNode(GLOBAL_DATA, $2.m_node);
+                                          SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+                                          $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_featureInfo); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; 
+                                        }
 ;
 
 TryStatement:
@@ -1091,87 +1194,108 @@ SourceElement:
  
 %%
 
-static ExpressionNode* makeAssignNode(void* globalPtr, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments)
+static ExpressionNode* makeAssignNode(void* globalPtr, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end)
 {
     if (!loc->isLocation())
-        return new AssignErrorNode(GLOBAL_DATA, loc, op, expr);
+        return new AssignErrorNode(GLOBAL_DATA, loc, op, expr, divot, divot - start, end - divot);
 
     if (loc->isResolveNode()) {
         ResolveNode* resolve = static_cast<ResolveNode*>(loc);
-        if (op == OpEqual)
-            return new AssignResolveNode(GLOBAL_DATA, resolve->identifier(), expr, exprHasAssignments);
-        else
-            return new ReadModifyResolveNode(GLOBAL_DATA, resolve->identifier(), op, expr, exprHasAssignments);
+        if (op == OpEqual) {
+            AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, resolve->identifier(), expr, exprHasAssignments);
+            SET_EXCEPTION_LOCATION(node, start, divot, end);
+            return node;
+        } else
+            return new ReadModifyResolveNode(GLOBAL_DATA, resolve->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
     }
     if (loc->isBracketAccessorNode()) {
         BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc);
         if (op == OpEqual)
-            return new AssignBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments);
-        else
-            return new ReadModifyBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments);
+            return new AssignBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, divot, divot - start, end - divot);
+        else {
+            ReadModifyBracketNode* node = new ReadModifyBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, divot - start, end - divot);
+            node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+            return node;
+        }
     }
     ASSERT(loc->isDotAccessorNode());
     DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc);
     if (op == OpEqual)
-        return new AssignDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), expr, exprHasAssignments);
-    return new ReadModifyDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, expr, exprHasAssignments);
+        return new AssignDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), expr, exprHasAssignments, divot, divot - start, end - divot);
+
+    ReadModifyDotNode* node = new ReadModifyDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
+    node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+    return node;
 }
 
-static ExpressionNode* makePrefixNode(void* globalPtr, ExpressionNode* expr, Operator op)
-{ 
+static ExpressionNode* makePrefixNode(void* globalPtr, ExpressionNode* expr, Operator op, int start, int divot, int end)
+{
     if (!expr->isLocation())
-        return new PrefixErrorNode(GLOBAL_DATA, expr, op);
+        return new PrefixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot);
     
     if (expr->isResolveNode()) {
         ResolveNode* resolve = static_cast<ResolveNode*>(expr);
-        return new PrefixResolveNode(GLOBAL_DATA, resolve->identifier(), op);
+        return new PrefixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot);
     }
     if (expr->isBracketAccessorNode()) {
         BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
-        return new PrefixBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op);
+        PrefixBracketNode* node = new PrefixBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot);
+        node->setSubexpressionInfo(bracket->divot(), bracket->startOffset());
+        return node;
     }
     ASSERT(expr->isDotAccessorNode());
     DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
-    return new PrefixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op);
+    PrefixDotNode* node = new PrefixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
+    node->setSubexpressionInfo(dot->divot(), dot->startOffset());
+    return node;
 }
 
-static ExpressionNode* makePostfixNode(void* globalPtr, ExpressionNode* expr, Operator op)
+static ExpressionNode* makePostfixNode(void* globalPtr, ExpressionNode* expr, Operator op, int start, int divot, int end)
 { 
     if (!expr->isLocation())
-        return new PostfixErrorNode(GLOBAL_DATA, expr, op);
+        return new PostfixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot);
     
     if (expr->isResolveNode()) {
         ResolveNode* resolve = static_cast<ResolveNode*>(expr);
-        return new PostfixResolveNode(GLOBAL_DATA, resolve->identifier(), op);
+        return new PostfixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot);
     }
     if (expr->isBracketAccessorNode()) {
         BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
-        return new PostfixBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op);
+        PostfixBracketNode* node = new PostfixBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot);
+        node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+        return node;
+        
     }
     ASSERT(expr->isDotAccessorNode());
     DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
-    return new PostfixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op);
+    PostfixDotNode* node = new PostfixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
+    node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+    return node;
 }
 
-static ExpressionNodeInfo makeFunctionCallNode(void* globalPtr, ExpressionNodeInfo func, ArgumentsNodeInfo args)
+static ExpressionNodeInfo makeFunctionCallNode(void* globalPtr, ExpressionNodeInfo func, ArgumentsNodeInfo args, int start, int divot, int end)
 {
     FeatureInfo features = func.m_featureInfo | args.m_featureInfo;
     if (!func.m_node->isLocation())
-        return createNodeFeatureInfo<ExpressionNode*>(new FunctionCallValueNode(GLOBAL_DATA, func.m_node, args.m_node), features);
+        return createNodeFeatureInfo<ExpressionNode*>(new FunctionCallValueNode(GLOBAL_DATA, func.m_node, args.m_node, divot, divot - start, end - divot), features);
     if (func.m_node->isResolveNode()) {
         ResolveNode* resolve = static_cast<ResolveNode*>(func.m_node);
         const Identifier& identifier = resolve->identifier();
         if (identifier == GLOBAL_DATA->propertyNames->eval)
-            return createNodeFeatureInfo<ExpressionNode*>(new EvalFunctionCallNode(GLOBAL_DATA, args.m_node), EvalFeature | features);
-        return createNodeFeatureInfo<ExpressionNode*>(new FunctionCallResolveNode(GLOBAL_DATA, identifier, args.m_node), features);
+            return createNodeFeatureInfo<ExpressionNode*>(new EvalFunctionCallNode(GLOBAL_DATA, args.m_node, divot, divot - start, end - divot), EvalFeature | features);
+        return createNodeFeatureInfo<ExpressionNode*>(new FunctionCallResolveNode(GLOBAL_DATA, identifier, args.m_node, divot, divot - start, end - divot), features);
     }
     if (func.m_node->isBracketAccessorNode()) {
         BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func.m_node);
-        return createNodeFeatureInfo<ExpressionNode*>(new FunctionCallBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), args.m_node), features);
+        FunctionCallBracketNode* node = new FunctionCallBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), args.m_node, divot, divot - start, end - divot);
+        node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+        return createNodeFeatureInfo<ExpressionNode*>(node, features);
     }
     ASSERT(func.m_node->isDotAccessorNode());
     DotAccessorNode* dot = static_cast<DotAccessorNode*>(func.m_node);
-    return createNodeFeatureInfo<ExpressionNode*>(new FunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node), features);
+    FunctionCallDotNode* node = new FunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot);
+    node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+    return createNodeFeatureInfo<ExpressionNode*>(node, features);
 }
 
 static ExpressionNode* makeTypeOfNode(void* globalPtr, ExpressionNode* expr)
@@ -1183,21 +1307,21 @@ static ExpressionNode* makeTypeOfNode(void* globalPtr, ExpressionNode* expr)
     return new TypeOfValueNode(GLOBAL_DATA, expr);
 }
 
-static ExpressionNode* makeDeleteNode(void* globalPtr, ExpressionNode* expr)
+static ExpressionNode* makeDeleteNode(void* globalPtr, ExpressionNode* expr, int start, int divot, int end)
 {
     if (!expr->isLocation())
         return new DeleteValueNode(GLOBAL_DATA, expr);
     if (expr->isResolveNode()) {
         ResolveNode* resolve = static_cast<ResolveNode*>(expr);
-        return new DeleteResolveNode(GLOBAL_DATA, resolve->identifier());
+        return new DeleteResolveNode(GLOBAL_DATA, resolve->identifier(), divot, divot - start, end - divot);
     }
     if (expr->isBracketAccessorNode()) {
         BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
-        return new DeleteBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript());
+        return new DeleteBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), divot, divot - start, end - divot);
     }
     ASSERT(expr->isDotAccessorNode());
     DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
-    return new DeleteDotNode(GLOBAL_DATA, dot->base(), dot->identifier());
+    return new DeleteDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), divot, divot - start, end - divot);
 }
 
 static PropertyNode* makeGetterOrSetterPropertyNode(void* globalPtr, const Identifier& getOrSet, const Identifier& name, ParameterNode* params, FunctionBodyNode* body, const SourceRange& source)
index b55568a..5ea13fe 100644 (file)
@@ -74,6 +74,10 @@ Lexer::Lexer(JSGlobalData* globalData)
     , m_next1(0)
     , m_next2(0)
     , m_next3(0)
+    , m_currentOffset(0)
+    , m_nextOffset1(0)
+    , m_nextOffset2(0)
+    , m_nextOffset3(0)
     , m_globalData(globalData)
     , m_mainTable(KJS::mainTable)
 {
@@ -119,12 +123,17 @@ void Lexer::shift(unsigned p)
         m_current = m_next1;
         m_next1 = m_next2;
         m_next2 = m_next3;
+        m_currentOffset = m_nextOffset1;
+        m_nextOffset1 = m_nextOffset2;
+        m_nextOffset2 = m_nextOffset3;
         do {
             if (m_position >= m_length) {
+                m_nextOffset3 = m_position;
                 m_position++;
                 m_next3 = -1;
                 break;
             }
+            m_nextOffset3 = m_position;
             m_next3 = m_code[m_position++];
         } while (m_next3 == 0xFEFF);
     }
@@ -164,7 +173,7 @@ int Lexer::lex(void* p1, void* p2)
         token = m_stackToken;
         m_stackToken = 0;
     }
-
+    int startOffset = m_currentOffset;
     while (!m_done) {
         if (m_skipLF && m_current != '\n') // found \r but not \n afterwards
             m_skipLF = false;
@@ -177,6 +186,7 @@ int Lexer::lex(void* p1, void* p2)
         }
         switch (m_state) {
             case Start:
+                startOffset = m_currentOffset;
                 if (isWhiteSpace()) {
                     // do nothing
                 } else if (m_current == '/' && m_next1 == '/') {
@@ -521,7 +531,8 @@ int Lexer::lex(void* p1, void* p2)
     m_delimited = false;
     llocp->first_line = yylineno;
     llocp->last_line = yylineno;
-
+    llocp->first_column = startOffset;
+    llocp->last_column = m_currentOffset;
     switch (m_state) {
         case Eof:
             token = 0;
index eee1f39..6d4d84c 100644 (file)
@@ -133,7 +133,6 @@ namespace KJS {
 
         State m_state;
         unsigned int m_position;
-
         RefPtr<SourceProvider> m_source;
         const UChar* m_code;
         unsigned int m_length;
@@ -145,7 +144,12 @@ namespace KJS {
         int m_next1;
         int m_next2;
         int m_next3;
-
+        
+        int m_currentOffset;
+        int m_nextOffset1;
+        int m_nextOffset2;
+        int m_nextOffset3;
+        
         Vector<UString*> m_strings;
         Vector<KJS::Identifier*> m_identifiers;
 
index e5971a9..e325b07 100644 (file)
@@ -162,17 +162,19 @@ static void substitute(UString& string, const UString& substring)
     string = newString;
 }
 
-RegisterID* Node::emitThrowError(CodeGenerator& generator, ErrorType e, const char* msg)
+RegisterID* ThrowableExpressionData::emitThrowError(CodeGenerator& generator, ErrorType e, const char* msg)
 {
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalExec(), msg));
     generator.emitThrow(exception);
     return exception;
 }
 
-RegisterID* Node::emitThrowError(CodeGenerator& generator, ErrorType e, const char* msg, const Identifier& label)
+RegisterID* ThrowableExpressionData::emitThrowError(CodeGenerator& generator, ErrorType e, const char* msg, const Identifier& label)
 {
     UString message = msg;
     substitute(message, label.ustring());
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalExec(), message));
     generator.emitThrow(exception);
     return exception;
@@ -184,7 +186,6 @@ StatementNode::StatementNode(JSGlobalData* globalData)
     : Node(globalData)
     , m_lastLine(-1)
 {
-    m_line = -1;
 }
 
 void StatementNode::setLoc(int firstLine, int lastLine)
@@ -288,7 +289,8 @@ RegisterID* ResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
             return 0;
         return generator.moveToDestinationIfNeeded(dst, local);
     }
-
+    
+    generator.emitExpressionInfo(m_startOffset + m_ident.size(), m_ident.size(), 0);
     return generator.emitResolve(generator.finalDestination(dst), m_ident);
 }
 
@@ -375,7 +377,7 @@ RegisterID* BracketAccessorNode::emitCode(CodeGenerator& generator, RegisterID*
 {
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments, m_subscript->isPure(generator));
     RegisterID* property = generator.emitNode(m_subscript.get());
-
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property);
 }
 
@@ -384,6 +386,7 @@ RegisterID* BracketAccessorNode::emitCode(CodeGenerator& generator, RegisterID*
 RegisterID* DotAccessorNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RegisterID* base = generator.emitNode(m_base.get());
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     return generator.emitGetById(generator.finalDestination(dst), base, m_ident);
 }
 
@@ -400,6 +403,7 @@ RegisterID* ArgumentListNode::emitCode(CodeGenerator& generator, RegisterID* dst
 RegisterID* NewExprNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RegisterID* r0 = generator.emitNode(m_expr.get());
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     return generator.emitConstruct(generator.finalDestination(dst), r0, m_args.get());
 }
 
@@ -408,46 +412,50 @@ RegisterID* EvalFunctionCallNode::emitCode(CodeGenerator& generator, RegisterID*
     RefPtr<RegisterID> base = generator.tempDestination(dst);
     RegisterID* func = generator.newTemporary();
     generator.emitResolveWithBase(base.get(), func, generator.propertyNames().eval);
-    return generator.emitCallEval(generator.finalDestination(dst, base.get()), func, base.get(), m_args.get());
+    return generator.emitCallEval(generator.finalDestination(dst, base.get()), func, base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 RegisterID* FunctionCallValueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RegisterID* func = generator.emitNode(m_expr.get());
-    return generator.emitCall(generator.finalDestination(dst), func, 0, m_args.get());
+    return generator.emitCall(generator.finalDestination(dst), func, 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 RegisterID* FunctionCallResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     if (RegisterID* local = generator.registerForLocal(m_ident))
-        return generator.emitCall(generator.finalDestination(dst), local, 0, m_args.get());
+        return generator.emitCall(generator.finalDestination(dst), local, 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
 
     int index = 0;
     size_t depth = 0;
     if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
         RegisterID* func = generator.emitGetScopedVar(generator.newTemporary(), depth, index);
-        return generator.emitCall(generator.finalDestination(dst), func, 0, m_args.get());
+        return generator.emitCall(generator.finalDestination(dst), func, 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
     }
 
     RefPtr<RegisterID> base = generator.tempDestination(dst);
     RegisterID* func = generator.newTemporary();
+    int identifierStart = m_divot - m_startOffset;
+    generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0);
     generator.emitResolveFunction(base.get(), func, m_ident);
-    return generator.emitCall(generator.finalDestination(dst, base.get()), func, base.get(), m_args.get());
+    return generator.emitCall(generator.finalDestination(dst, base.get()), func, base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 RegisterID* FunctionCallBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> base = generator.emitNode(m_base.get());
     RegisterID* property = generator.emitNode(m_subscript.get());
+    generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
     RegisterID* function = generator.emitGetByVal(generator.newTemporary(), base.get(), property);
-    return generator.emitCall(generator.finalDestination(dst, base.get()), function, base.get(), m_args.get());
+    return generator.emitCall(generator.finalDestination(dst, base.get()), function, base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 RegisterID* FunctionCallDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> base = generator.emitNode(m_base.get());
+    generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
     RegisterID* function = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
-    return generator.emitCall(generator.finalDestination(dst, base.get()), function, base.get(), m_args.get());
+    return generator.emitCall(generator.finalDestination(dst, base.get()), function, base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 // ------------------------------ PostfixResolveNode ----------------------------------
@@ -491,6 +499,7 @@ RegisterID* PostfixResolveNode::emitCode(CodeGenerator& generator, RegisterID* d
         return oldValue;
     }
 
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     RefPtr<RegisterID> value = generator.newTemporary();
     RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident);
     RegisterID* oldValue;
@@ -510,6 +519,8 @@ RegisterID* PostfixBracketNode::emitCode(CodeGenerator& generator, RegisterID* d
 {
     RefPtr<RegisterID> base = generator.emitNode(m_base.get());
     RefPtr<RegisterID> property = generator.emitNode(m_subscript.get());
+
+    generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
     RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
     RegisterID* oldValue;
     if (dst == ignoredResult()) {
@@ -521,6 +532,7 @@ RegisterID* PostfixBracketNode::emitCode(CodeGenerator& generator, RegisterID* d
     } else {
         oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get());
     }
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     generator.emitPutByVal(base.get(), property.get(), value.get());
     return oldValue;
 }
@@ -530,6 +542,8 @@ RegisterID* PostfixBracketNode::emitCode(CodeGenerator& generator, RegisterID* d
 RegisterID* PostfixDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> base = generator.emitNode(m_base.get());
+
+    generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
     RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
     RegisterID* oldValue;
     if (dst == ignoredResult()) {
@@ -541,6 +555,7 @@ RegisterID* PostfixDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
     } else {
         oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get());
     }
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     generator.emitPutById(base.get(), m_ident, value.get());
     return oldValue;
 }
@@ -559,6 +574,7 @@ RegisterID* DeleteResolveNode::emitCode(CodeGenerator& generator, RegisterID* ds
     if (generator.registerForLocal(m_ident))
         return generator.emitLoad(generator.finalDestination(dst), false);
 
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident);
     return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident);
 }
@@ -569,6 +585,8 @@ RegisterID* DeleteBracketNode::emitCode(CodeGenerator& generator, RegisterID* ds
 {
     RefPtr<RegisterID> r0 = generator.emitNode(m_base.get());
     RefPtr<RegisterID> r1 = generator.emitNode(m_subscript.get());
+
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1.get());
 }
 
@@ -577,6 +595,8 @@ RegisterID* DeleteBracketNode::emitCode(CodeGenerator& generator, RegisterID* ds
 RegisterID* DeleteDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RegisterID* r0 = generator.emitNode(m_base.get());
+
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident);
 }
 
@@ -656,6 +676,7 @@ RegisterID* PrefixResolveNode::emitCode(CodeGenerator& generator, RegisterID* ds
         return generator.moveToDestinationIfNeeded(dst, propDst.get());;
     }
 
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     RefPtr<RegisterID> propDst = generator.tempDestination(dst);
     RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident);
     emitPreIncOrDec(generator, propDst.get(), m_operator);
@@ -670,11 +691,14 @@ RegisterID* PrefixBracketNode::emitCode(CodeGenerator& generator, RegisterID* ds
     RefPtr<RegisterID> base = generator.emitNode(m_base.get());
     RefPtr<RegisterID> property = generator.emitNode(m_subscript.get());
     RefPtr<RegisterID> propDst = generator.tempDestination(dst);
+
+    generator.emitExpressionInfo(m_divot + m_subexpressionDivotOffset, m_subexpressionStartOffset, m_endOffset - m_subexpressionDivotOffset);
     RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get());
     if (m_operator == OpPlusPlus)
         generator.emitPreInc(value);
     else
         generator.emitPreDec(value);
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     generator.emitPutByVal(base.get(), property.get(), value);
     return generator.moveToDestinationIfNeeded(dst, propDst.get());
 }
@@ -685,11 +709,14 @@ RegisterID* PrefixDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> base = generator.emitNode(m_base.get());
     RefPtr<RegisterID> propDst = generator.tempDestination(dst);
+
+    generator.emitExpressionInfo(m_divot + m_subexpressionDivotOffset, m_subexpressionStartOffset, m_endOffset - m_subexpressionDivotOffset);
     RegisterID* value = generator.emitGetById(propDst.get(), base.get(), m_ident);
     if (m_operator == OpPlusPlus)
         generator.emitPreInc(value);
     else
         generator.emitPreDec(value);
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     generator.emitPutById(base.get(), m_ident, value);
     return generator.moveToDestinationIfNeeded(dst, propDst.get());
 }
@@ -725,6 +752,14 @@ RegisterID* ReverseBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID*
     return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src2, src1.get());
 }
 
+RegisterID* ThrowableBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
+{
+    RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_term1.get(), m_rightHasAssignments, m_term2->isPure(generator));
+    RegisterID* src2 = generator.emitNode(m_term2.get());
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+    return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src1.get(), src2);
+}
+
 // ------------------------------ Binary Logical Nodes ----------------------------
 
 RegisterID* LogicalOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
@@ -846,8 +881,10 @@ RegisterID* ReadModifyResolveNode::emitCode(CodeGenerator& generator, RegisterID
     }
 
     RefPtr<RegisterID> src1 = generator.tempDestination(dst);
+    generator.emitExpressionInfo(m_divot - m_startOffset + m_ident.size(), m_ident.size(), 0);
     RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident);
     RegisterID* src2 = generator.emitNode(m_right.get());
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator);
     return generator.emitPutById(base.get(), m_ident, result);
 }
@@ -878,6 +915,7 @@ RegisterID* AssignResolveNode::emitCode(CodeGenerator& generator, RegisterID* ds
     if (dst == ignoredResult())
         dst = 0;
     RegisterID* value = generator.emitNode(dst, m_right.get());
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     return generator.emitPutById(base.get(), m_ident, value);
 }
 
@@ -888,6 +926,7 @@ RegisterID* AssignDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_rightHasAssignments, m_right->isPure(generator));
     RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
     RegisterID* result = generator.emitNode(value.get(), m_right.get());
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     generator.emitPutById(base.get(), m_ident, result);
     return generator.moveToDestinationIfNeeded(dst, result);
 }
@@ -897,9 +936,13 @@ RegisterID* AssignDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 RegisterID* ReadModifyDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_rightHasAssignments, m_right->isPure(generator));
+
+    generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
     RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
     RegisterID* change = generator.emitNode(m_right.get());
     RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator);
+
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     return generator.emitPutById(base.get(), m_ident, updatedValue);
 }
 
@@ -918,6 +961,8 @@ RegisterID* AssignBracketNode::emitCode(CodeGenerator& generator, RegisterID* ds
     RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript.get(), m_rightHasAssignments, m_right->isPure(generator));
     RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
     RegisterID* result = generator.emitNode(value.get(), m_right.get());
+
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     generator.emitPutByVal(base.get(), property.get(), result);
     return generator.moveToDestinationIfNeeded(dst, result);
 }
@@ -927,10 +972,12 @@ RegisterID* ReadModifyBracketNode::emitCode(CodeGenerator& generator, RegisterID
     RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator));
     RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript.get(), m_rightHasAssignments, m_right->isPure(generator));
 
+    generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
     RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
     RegisterID* change = generator.emitNode(m_right.get());
     RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator);
 
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
     generator.emitPutByVal(base.get(), property.get(), updatedValue);
 
     return updatedValue;
@@ -1196,16 +1243,19 @@ ForInNode::ForInNode(JSGlobalData* globalData, ExpressionNode* l, ExpressionNode
 {
 }
 
-ForInNode::ForInNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement)
+ForInNode::ForInNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement, int divot, int startOffset, int endOffset)
     : StatementNode(globalData)
     , m_ident(ident)
-    , m_lexpr(new ResolveNode(globalData, ident))
+    , m_lexpr(new ResolveNode(globalData, ident, divot - startOffset))
     , m_expr(expr)
     , m_statement(statement)
     , m_identIsVarDecl(true)
 {
-    if (in)
-        m_init = new AssignResolveNode(globalData, ident, in, true);
+    if (in) {
+        AssignResolveNode* node = new AssignResolveNode(globalData, ident, in, true);
+        node->setExceptionSourceRange(divot, divot - startOffset, endOffset - divot);
+        m_init = node;
+    }
     // for( var foo = bar in baz )
 }
 
@@ -1229,6 +1279,8 @@ RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst)
             propertyName = generator.newTemporary();
             RefPtr<RegisterID> protect = propertyName;
             RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident);
+
+            generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
             generator.emitPutById(base, ident, propertyName);
         }
     } else if (m_lexpr->isDotAccessorNode()) {
@@ -1237,6 +1289,8 @@ RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst)
         propertyName = generator.newTemporary();
         RefPtr<RegisterID> protect = propertyName;
         RegisterID* base = generator.emitNode(assignNode->base());
+
+        generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset());
         generator.emitPutById(base, ident, propertyName);
     } else {
         ASSERT(m_lexpr->isBracketAccessorNode());
@@ -1245,6 +1299,8 @@ RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst)
         RefPtr<RegisterID> protect = propertyName;
         RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
         RegisterID* subscript = generator.emitNode(assignNode->subscript());
+        
+        generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset());
         generator.emitPutByVal(base.get(), subscript, propertyName);
     }   
     
@@ -1329,6 +1385,7 @@ RegisterID* ReturnNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 RegisterID* WithNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> scope = generator.emitNode(m_expr.get()); // scope must be protected until popped
+    generator.emitExpressionInfo(m_divot, m_expressionLength, 0);
     generator.emitPushScope(scope.get());
     RegisterID* result = generator.emitNode(dst, m_statement.get());
     generator.emitPopScope();
@@ -1409,7 +1466,7 @@ RegisterID* LabelNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     if (generator.jumpContextForBreak(m_label))
         return emitThrowError(generator, SyntaxError, "Duplicated label %s found.", m_label);
-    
+
     RefPtr<LabelID> l0 = generator.newLabel();
     m_labelStack.push(m_label);
     generator.pushJumpContext(&m_labelStack, 0, l0.get(), false);
@@ -1427,7 +1484,9 @@ RegisterID* LabelNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 
 RegisterID* ThrowNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    generator.emitThrow(generator.emitNode(dst, m_expr.get()));
+    RefPtr<RegisterID> expr = generator.emitNode(dst, m_expr.get());
+    generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+    generator.emitThrow(expr.get());
     return dst;
 }
 
@@ -1506,20 +1565,22 @@ ScopeNode::ScopeNode(JSGlobalData* globalData, SourceElements* children, VarStac
 
 // ------------------------------ ProgramNode -----------------------------
 
-ProgramNode::ProgramNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
+ProgramNode::ProgramNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, SourceProvider* sourceProvider, bool usesEval, bool needsClosure)
     : ScopeNode(globalData, children, varStack, funcStack, usesEval, needsClosure)
+    , m_sourceProvider(sourceProvider)
 {
 }
 
-ProgramNode* ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
+ProgramNode* ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, SourceProvider* sourceProvider, bool usesEval, bool needsClosure)
 {
-    return new ProgramNode(globalData, children, varStack, funcStack, usesEval, needsClosure);
+    return new ProgramNode(globalData, children, varStack, funcStack, sourceProvider, usesEval, needsClosure);
 }
 
 // ------------------------------ EvalNode -----------------------------
 
-EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
+EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, SourceProvider* sourceProvider, bool usesEval, bool needsClosure)
     : ScopeNode(globalData, children, varStack, funcStack, usesEval, needsClosure)
+    , m_sourceProvider(sourceProvider)
 {
 }
 
@@ -1542,16 +1603,16 @@ void EvalNode::generateCode(ScopeChainNode* sc)
     JSGlobalObject* globalObject = scopeChain.globalObject();
 
     SymbolTable symbolTable;
-
-    m_code.set(new EvalCodeBlock(this, globalObject));
+    ASSERT(m_sourceProvider);
+    m_code.set(new EvalCodeBlock(this, globalObject, m_sourceProvider));
 
     CodeGenerator generator(this, globalObject->debugger(), scopeChain, &symbolTable, m_code.get());
     generator.generate();
 }
 
-EvalNode* EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
+EvalNode* EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, SourceProvider* sourceProvider, bool usesEval, bool needsClosure)
 {
-    return new EvalNode(globalData, children, varStack, funcStack, usesEval, needsClosure);
+    return new EvalNode(globalData, children, varStack, funcStack, sourceProvider, usesEval, needsClosure);
 }
 
 // ------------------------------ FunctionBodyNode -----------------------------
@@ -1572,12 +1633,18 @@ FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceEleme
     return new FunctionBodyNode(globalData, children, varStack, funcStack, usesEval, needsClosure);
 }
 
+FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, SourceProvider*, bool usesEval, bool needsClosure)
+{
+    return new FunctionBodyNode(globalData, children, varStack, funcStack, usesEval, needsClosure);
+}
+
 void FunctionBodyNode::generateCode(ScopeChainNode* sc)
 {
     ScopeChain scopeChain(sc);
     JSGlobalObject* globalObject = scopeChain.globalObject();
 
-    m_code.set(new CodeBlock(this, FunctionCode));
+    ASSERT(m_source.sourceProvider());
+    m_code.set(new CodeBlock(this, FunctionCode, m_source.sourceProvider(), m_source.startOffset()));
 
     CodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_symbolTable, m_code.get());
     generator.generate();
@@ -1613,7 +1680,8 @@ void ProgramNode::generateCode(ScopeChainNode* sc)
     ScopeChain scopeChain(sc);
     JSGlobalObject* globalObject = scopeChain.globalObject();
     
-    m_code.set(new ProgramCodeBlock(this, GlobalCode, globalObject));
+    ASSERT(m_sourceProvider);
+    m_code.set(new ProgramCodeBlock(this, GlobalCode, globalObject, m_sourceProvider));
     
     CodeGenerator generator(this, globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_code.get(), m_varStack, m_functionStack);
     generator.generate();
index b63f0ac..e082f1a 100644 (file)
@@ -175,7 +175,7 @@ namespace KJS {
         } // FIXME: Make this pure virtual.
 
         UString toString() const KJS_FAST_CALL;
-        int lineNo() const KJS_FAST_CALL { return m_line; }
+        int lineNo() const { return m_line; }
 
         virtual bool isReturnNode() const KJS_FAST_CALL { return false; }
 
@@ -187,9 +187,6 @@ namespace KJS {
     protected:
         Node(JSGlobalData*, JSType) KJS_FAST_CALL; // used by ExpressionNode
 
-        RegisterID* emitThrowError(CodeGenerator&, ErrorType, const char* msg);
-        RegisterID* emitThrowError(CodeGenerator&, ErrorType, const char* msg, const Identifier&);
-
         int m_line : 28;
         unsigned m_expectedReturnType : 3; // JSType
     };
@@ -318,8 +315,101 @@ namespace KJS {
     private:
         UString m_value;
     };
+    
+    class ThrowableExpressionData {
+    public:
+        ThrowableExpressionData()
+            : m_divot(-1)
+            , m_startOffset(-1)
+            , m_endOffset(-1)
+        {
+        }
+        
+        ThrowableExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset)
+            : m_divot(divot)
+            , m_startOffset(startOffset)
+            , m_endOffset(endOffset)
+        {
+        }
+        
+        void setExceptionSourceRange(unsigned divot, unsigned startOffset, unsigned endOffset)
+        {
+            m_divot = divot;
+            m_startOffset = startOffset;
+            m_endOffset = endOffset;
+        }
+
+        uint32_t divot() const { return m_divot; }
+        uint16_t startOffset() const { return m_startOffset; }
+        uint16_t endOffset() const { return m_endOffset; }
+
+    protected:
+        RegisterID* emitThrowError(CodeGenerator&, ErrorType, const char* msg);
+        RegisterID* emitThrowError(CodeGenerator&, ErrorType, const char* msg, const Identifier&);
+        uint32_t m_divot;
+        uint16_t m_startOffset;
+        uint16_t m_endOffset;
+    };
+
+    class ThrowableSubExpressionData : public ThrowableExpressionData {
+    public:
+        ThrowableSubExpressionData()
+            : ThrowableExpressionData()
+            , m_subexpressionDivotOffset(0)
+            , m_subexpressionEndOffset(0)
+        {
+        }
+
+        ThrowableSubExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset)
+            : ThrowableExpressionData(divot, startOffset, endOffset)
+            , m_subexpressionDivotOffset(0)
+            , m_subexpressionEndOffset(0)
+        {
+        }
+
+        void setSubexpressionInfo(uint32_t subexpressionDivot, uint16_t subexpressionOffset) {
+            ASSERT(subexpressionDivot <= m_divot);
+            if ((m_divot - subexpressionDivot) & ~0xFFFF) // Overflow means we can't do this safely, so just point at the primary divot
+                return;
+            m_subexpressionDivotOffset = m_divot - subexpressionDivot;
+            m_subexpressionEndOffset = subexpressionOffset;
+        }
+
+    protected:
+        uint16_t m_subexpressionDivotOffset;
+        uint16_t m_subexpressionEndOffset;
+    };
+    
+    class ThrowablePrefixedSubExpressionData : public ThrowableExpressionData {
+    public:
+        ThrowablePrefixedSubExpressionData()
+            : ThrowableExpressionData()
+            , m_subexpressionDivotOffset(0)
+            , m_subexpressionStartOffset(0)
+        {
+        }
+
+        ThrowablePrefixedSubExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset)
+            : ThrowableExpressionData(divot, startOffset, endOffset)
+            , m_subexpressionDivotOffset(0)
+            , m_subexpressionStartOffset(0)
+        {
+        }
+
+        void setSubexpressionInfo(uint32_t subexpressionDivot, uint16_t subexpressionOffset) {
+            ASSERT(subexpressionDivot >= m_divot);
+            if ((subexpressionDivot - m_divot) & ~0xFFFF) // Overflow means we can't do this safely, so just point at the primary divot
+                return;
+            m_subexpressionDivotOffset = subexpressionDivot - m_divot;
+            m_subexpressionStartOffset = subexpressionOffset;
+        }
+
+    protected:
+        uint16_t m_subexpressionDivotOffset;
+        uint16_t m_subexpressionStartOffset;
+    };
 
-    class RegExpNode : public ExpressionNode {
+    class RegExpNode : public ExpressionNode, public ThrowableExpressionData {
     public:
         RegExpNode(JSGlobalData* globalData, const UString& pattern, const UString& flags) KJS_FAST_CALL
             : ExpressionNode(globalData)
@@ -351,9 +441,10 @@ namespace KJS {
 
     class ResolveNode : public ExpressionNode {
     public:
-        ResolveNode(JSGlobalData* globalData, const Identifier& ident) KJS_FAST_CALL
+        ResolveNode(JSGlobalData* globalData, const Identifier& ident, int startOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
             , m_ident(ident)
+            , m_startOffset(startOffset)
         {
         }
 
@@ -369,8 +460,8 @@ namespace KJS {
 
     protected:
         Identifier m_ident;
-        int m_index; // Used by LocalVarAccessNode and ScopedVarAccessNode.
-        size_t m_scopeDepth; // Used by ScopedVarAccessNode
+        int32_t m_startOffset;
+        
     };
 
     class ElementNode : public Node {
@@ -513,8 +604,8 @@ namespace KJS {
     private:
         RefPtr<PropertyListNode> m_list;
     };
-
-    class BracketAccessorNode : public ExpressionNode {
+    
+    class BracketAccessorNode : public ExpressionNode, public ThrowableExpressionData {
     public:
         BracketAccessorNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments) KJS_FAST_CALL
             : ExpressionNode(globalData)
@@ -540,7 +631,7 @@ namespace KJS {
         bool m_subscriptHasAssignments;
     };
 
-    class DotAccessorNode : public ExpressionNode {
+    class DotAccessorNode : public ExpressionNode, public ThrowableExpressionData {
     public:
         DotAccessorNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
             : ExpressionNode(globalData)
@@ -607,7 +698,7 @@ namespace KJS {
         RefPtr<ArgumentListNode> m_listNode;
     };
 
-    class NewExprNode : public ExpressionNode {
+    class NewExprNode : public ExpressionNode, public ThrowableExpressionData {
     public:
         NewExprNode(JSGlobalData* globalData, ExpressionNode* expr) KJS_FAST_CALL
             : ExpressionNode(globalData)
@@ -632,10 +723,11 @@ namespace KJS {
         RefPtr<ArgumentsNode> m_args;
     };
 
-    class EvalFunctionCallNode : public ExpressionNode {
+    class EvalFunctionCallNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        EvalFunctionCallNode(JSGlobalData* globalData, ArgumentsNode* args) KJS_FAST_CALL
+        EvalFunctionCallNode(JSGlobalData* globalData, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_args(args)
         {
         }
@@ -648,10 +740,11 @@ namespace KJS {
         RefPtr<ArgumentsNode> m_args;
     };
 
-    class FunctionCallValueNode : public ExpressionNode {
+    class FunctionCallValueNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        FunctionCallValueNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args) KJS_FAST_CALL
+        FunctionCallValueNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_expr(expr)
             , m_args(args)
         {
@@ -666,10 +759,11 @@ namespace KJS {
         RefPtr<ArgumentsNode> m_args;
     };
 
-    class FunctionCallResolveNode : public ExpressionNode {
+    class FunctionCallResolveNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        FunctionCallResolveNode(JSGlobalData* globalData, const Identifier& ident, ArgumentsNode* args) KJS_FAST_CALL
+        FunctionCallResolveNode(JSGlobalData* globalData, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_ident(ident)
             , m_args(args)
         {
@@ -687,10 +781,11 @@ namespace KJS {
         size_t m_scopeDepth; // Used by ScopedVarFunctionCallNode and NonLocalVarFunctionCallNode
     };
     
-    class FunctionCallBracketNode : public ExpressionNode {
+    class FunctionCallBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
     public:
-        FunctionCallBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode* args) KJS_FAST_CALL
+        FunctionCallBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableSubExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_subscript(subscript)
             , m_args(args)
@@ -707,10 +802,11 @@ namespace KJS {
         RefPtr<ArgumentsNode> m_args;
     };
 
-    class FunctionCallDotNode : public ExpressionNode {
+    class FunctionCallDotNode : public ExpressionNode, public ThrowableSubExpressionData {
     public:
-        FunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args) KJS_FAST_CALL
+        FunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableSubExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_ident(ident)
             , m_args(args)
@@ -727,23 +823,23 @@ namespace KJS {
         RefPtr<ArgumentsNode> m_args;
     };
 
-    class PrePostResolveNode : public ExpressionNode {
+    class PrePostResolveNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        PrePostResolveNode(JSGlobalData* globalData, const Identifier& ident) KJS_FAST_CALL
+        PrePostResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData, NumberType)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_ident(ident)
         {
         }
 
     protected:
         Identifier m_ident;
-        size_t m_index; // Used by LocalVarPostfixNode.
     };
 
     class PostfixResolveNode : public PrePostResolveNode {
     public:
-        PostfixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper) KJS_FAST_CALL
-            : PrePostResolveNode(globalData, ident)
+        PostfixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
+            : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset)
             , m_operator(oper)
         {
         }
@@ -756,10 +852,11 @@ namespace KJS {
         Operator m_operator;
     };
 
-    class PostfixBracketNode : public ExpressionNode {
+    class PostfixBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
     public:
-        PostfixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper) KJS_FAST_CALL
+        PostfixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableSubExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_subscript(subscript)
             , m_operator(oper)
@@ -776,10 +873,11 @@ namespace KJS {
         Operator m_operator;
     };
 
-    class PostfixDotNode : public ExpressionNode {
+    class PostfixDotNode : public ExpressionNode, public ThrowableSubExpressionData {
     public:
-        PostfixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper) KJS_FAST_CALL
+        PostfixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableSubExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_ident(ident)
             , m_operator(oper)
@@ -796,10 +894,11 @@ namespace KJS {
         Operator m_operator;
     };
 
-    class PostfixErrorNode : public ExpressionNode {
+    class PostfixErrorNode : public ExpressionNode, public ThrowableSubExpressionData {
     public:
-        PostfixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper) KJS_FAST_CALL
+        PostfixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableSubExpressionData(divot, startOffset, endOffset)
             , m_expr(expr)
             , m_operator(oper)
         {
@@ -814,10 +913,11 @@ namespace KJS {
         Operator m_operator;
     };
 
-    class DeleteResolveNode : public ExpressionNode {
+    class DeleteResolveNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        DeleteResolveNode(JSGlobalData* globalData, const Identifier& ident) KJS_FAST_CALL
+        DeleteResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_ident(ident)
         {
         }
@@ -831,10 +931,11 @@ namespace KJS {
         Identifier m_ident;
     };
 
-    class DeleteBracketNode : public ExpressionNode {
+    class DeleteBracketNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        DeleteBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
+        DeleteBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_subscript(subscript)
         {
@@ -850,10 +951,11 @@ namespace KJS {
         RefPtr<ExpressionNode> m_subscript;
     };
 
-    class DeleteDotNode : public ExpressionNode {
+    class DeleteDotNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        DeleteDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
+        DeleteDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_ident(ident)
         {
@@ -942,8 +1044,8 @@ namespace KJS {
 
     class PrefixResolveNode : public PrePostResolveNode {
     public:
-        PrefixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper) KJS_FAST_CALL
-            : PrePostResolveNode(globalData, ident)
+        PrefixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
+            : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset)
             , m_operator(oper)
         {
         }
@@ -957,10 +1059,11 @@ namespace KJS {
         Operator m_operator;
     };
 
-    class PrefixBracketNode : public ExpressionNode {
+    class PrefixBracketNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData {
     public:
-        PrefixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper) KJS_FAST_CALL
+        PrefixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_subscript(subscript)
             , m_operator(oper)
@@ -977,10 +1080,11 @@ namespace KJS {
         Operator m_operator;
     };
 
-    class PrefixDotNode : public ExpressionNode {
+    class PrefixDotNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData {
     public:
-        PrefixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper) KJS_FAST_CALL
+        PrefixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_ident(ident)
             , m_operator(oper)
@@ -997,10 +1101,11 @@ namespace KJS {
         Operator m_operator;
     };
 
-    class PrefixErrorNode : public ExpressionNode {
+    class PrefixErrorNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        PrefixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper) KJS_FAST_CALL
+        PrefixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_expr(expr)
             , m_operator(oper)
         {
@@ -1282,10 +1387,23 @@ namespace KJS {
         virtual Precedence precedence() const { return PrecRelational; }
     };
 
-    class InstanceOfNode : public BinaryOpNode {
+    class ThrowableBinaryOpNode : public BinaryOpNode, public ThrowableExpressionData {
+    public:
+        ThrowableBinaryOpNode(JSGlobalData* globalData, JSType type, ExpressionNode* term1, ExpressionNode* term2, bool rightHasAssignments) KJS_FAST_CALL
+            : BinaryOpNode(globalData, type, term1, term2, rightHasAssignments)
+        {
+        }
+        ThrowableBinaryOpNode(JSGlobalData* globalData, ExpressionNode* term1, ExpressionNode* term2, bool rightHasAssignments) KJS_FAST_CALL
+            : BinaryOpNode(globalData, term1, term2, rightHasAssignments)
+        {
+        }
+        virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) KJS_FAST_CALL;
+    };
+    
+    class InstanceOfNode : public ThrowableBinaryOpNode {
     public:
         InstanceOfNode(JSGlobalData* globalData, ExpressionNode* term1, ExpressionNode* term2, bool rightHasAssignments) KJS_FAST_CALL
-            : BinaryOpNode(globalData, BooleanType, term1, term2, rightHasAssignments)
+            : ThrowableBinaryOpNode(globalData, BooleanType, term1, term2, rightHasAssignments)
         {
         }
 
@@ -1294,10 +1412,10 @@ namespace KJS {
         virtual Precedence precedence() const { return PrecRelational; }
     };
 
-    class InNode : public BinaryOpNode {
+    class InNode : public ThrowableBinaryOpNode {
     public:
         InNode(JSGlobalData* globalData, ExpressionNode* term1, ExpressionNode* term2, bool rightHasAssignments) KJS_FAST_CALL
-            : BinaryOpNode(globalData, term1, term2, rightHasAssignments)
+            : ThrowableBinaryOpNode(globalData, term1, term2, rightHasAssignments)
         {
         }
 
@@ -1436,10 +1554,11 @@ namespace KJS {
         RefPtr<ExpressionNode> m_expr2;
     };
 
-    class ReadModifyResolveNode : public ExpressionNode {
+    class ReadModifyResolveNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        ReadModifyResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, ExpressionNode*  right, bool rightHasAssignments) KJS_FAST_CALL
+        ReadModifyResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, ExpressionNode*  right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_ident(ident)
             , m_right(right)
             , m_operator(oper)
@@ -1460,7 +1579,7 @@ namespace KJS {
         bool m_rightHasAssignments : 1;
     };
 
-    class AssignResolveNode : public ExpressionNode {
+    class AssignResolveNode : public ExpressionNode, public ThrowableExpressionData {
     public:
         AssignResolveNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments) KJS_FAST_CALL
             : ExpressionNode(globalData)
@@ -1482,10 +1601,11 @@ namespace KJS {
         bool m_rightHasAssignments;
     };
 
-    class ReadModifyBracketNode : public ExpressionNode {
+    class ReadModifyBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
     public:
-        ReadModifyBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments) KJS_FAST_CALL
+        ReadModifyBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableSubExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_subscript(subscript)
             , m_right(right)
@@ -1509,10 +1629,11 @@ namespace KJS {
         bool m_rightHasAssignments : 1;
     };
 
-    class AssignBracketNode : public ExpressionNode {
+    class AssignBracketNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        AssignBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments) KJS_FAST_CALL
+        AssignBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_subscript(subscript)
             , m_right(right)
@@ -1534,10 +1655,11 @@ namespace KJS {
         bool m_rightHasAssignments : 1;
     };
 
-    class AssignDotNode : public ExpressionNode {
+    class AssignDotNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        AssignDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments) KJS_FAST_CALL
+        AssignDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_ident(ident)
             , m_right(right)
@@ -1556,10 +1678,11 @@ namespace KJS {
         bool m_rightHasAssignments;
     };
 
-    class ReadModifyDotNode : public ExpressionNode {
+    class ReadModifyDotNode : public ExpressionNode, public ThrowableSubExpressionData {
     public:
-        ReadModifyDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments) KJS_FAST_CALL
+        ReadModifyDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableSubExpressionData(divot, startOffset, endOffset)
             , m_base(base)
             , m_ident(ident)
             , m_right(right)
@@ -1581,10 +1704,11 @@ namespace KJS {
         bool m_rightHasAssignments : 1;
     };
 
-    class AssignErrorNode : public ExpressionNode {
+    class AssignErrorNode : public ExpressionNode, public ThrowableExpressionData {
     public:
-        AssignErrorNode(JSGlobalData* globalData, ExpressionNode* left, Operator oper, ExpressionNode* right) KJS_FAST_CALL
+        AssignErrorNode(JSGlobalData* globalData, ExpressionNode* left, Operator oper, ExpressionNode* right, unsigned divot, unsigned startOffset, unsigned endOffset) KJS_FAST_CALL
             : ExpressionNode(globalData)
+            , ThrowableExpressionData(divot, startOffset, endOffset)
             , m_left(left)
             , m_operator(oper)
             , m_right(right)
@@ -1836,10 +1960,10 @@ namespace KJS {
         bool m_expr1WasVarDecl;
     };
 
-    class ForInNode : public StatementNode {
+    class ForInNode : public StatementNode, public ThrowableExpressionData {
     public:
         ForInNode(JSGlobalData*, ExpressionNode*, ExpressionNode*, StatementNode*) KJS_FAST_CALL;
-        ForInNode(JSGlobalData*, const Identifier&, ExpressionNode*, ExpressionNode*, StatementNode*) KJS_FAST_CALL;
+        ForInNode(JSGlobalData*, const Identifier&, ExpressionNode*, ExpressionNode*, StatementNode*, int divot, int startOffset, int endOffset) KJS_FAST_CALL;
         
         virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) KJS_FAST_CALL;
         virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
@@ -1853,7 +1977,7 @@ namespace KJS {
         bool m_identIsVarDecl;
     };
 
-    class ContinueNode : public StatementNode {
+    class ContinueNode : public StatementNode, public ThrowableExpressionData {
     public:
         ContinueNode(JSGlobalData* globalData) KJS_FAST_CALL
             : StatementNode(globalData)
@@ -1873,7 +1997,7 @@ namespace KJS {
         Identifier m_ident;
     };
 
-    class BreakNode : public StatementNode {
+    class BreakNode : public StatementNode, public ThrowableExpressionData {
     public:
         BreakNode(JSGlobalData* globalData) KJS_FAST_CALL
             : StatementNode(globalData)
@@ -1893,7 +2017,7 @@ namespace KJS {
         Identifier m_ident;
     };
 
-    class ReturnNode : public StatementNode {
+    class ReturnNode : public StatementNode, public ThrowableExpressionData {
     public:
         ReturnNode(JSGlobalData* globalData, ExpressionNode* value) KJS_FAST_CALL
             : StatementNode(globalData)
@@ -1911,10 +2035,12 @@ namespace KJS {
 
     class WithNode : public StatementNode {
     public:
-        WithNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement) KJS_FAST_CALL
+        WithNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement, uint32_t divot, uint32_t expressionLength) KJS_FAST_CALL
             : StatementNode(globalData)
             , m_expr(expr)
             , m_statement(statement)
+            , m_divot(divot)
+            , m_expressionLength(expressionLength)
         {
         }
 
@@ -1924,9 +2050,11 @@ namespace KJS {
     private:
         RefPtr<ExpressionNode> m_expr;
         RefPtr<StatementNode> m_statement;
+        uint32_t m_divot;
+        uint32_t m_expressionLength;
     };
 
-    class LabelNode : public StatementNode {
+    class LabelNode : public StatementNode, public ThrowableExpressionData {
     public:
         LabelNode(JSGlobalData* globalData, const Identifier& label, StatementNode* statement) KJS_FAST_CALL
             : StatementNode(globalData)
@@ -1944,7 +2072,7 @@ namespace KJS {
         RefPtr<StatementNode> m_statement;
     };
 
-    class ThrowNode : public StatementNode {
+    class ThrowNode : public StatementNode, public ThrowableExpressionData {
     public:
         ThrowNode(JSGlobalData* globalData, ExpressionNode* expr) KJS_FAST_CALL
             : StatementNode(globalData)
@@ -2022,7 +2150,7 @@ namespace KJS {
         
         VarStack& varStack() { return m_varStack; }
         FunctionStack& functionStack() { return m_functionStack; }
-        
+
     protected:
         VarStack m_varStack;
         FunctionStack m_functionStack;
@@ -2036,7 +2164,7 @@ namespace KJS {
 
     class ProgramNode : public ScopeNode {
     public:
-        static ProgramNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
+        static ProgramNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, SourceProvider*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
 
         ProgramCodeBlock& byteCode(ScopeChainNode* scopeChain) KJS_FAST_CALL
         {
@@ -2046,7 +2174,7 @@ namespace KJS {
         }
 
     private:
-        ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
+        ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, SourceProvider*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
 
         void generateCode(ScopeChainNode*) KJS_FAST_CALL;
         virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) KJS_FAST_CALL;
@@ -2054,12 +2182,14 @@ namespace KJS {
         Vector<size_t> m_varIndexes; // Storage indexes belonging to the nodes in m_varStack. (Recorded to avoid double lookup.)
         Vector<size_t> m_functionIndexes; // Storage indexes belonging to the nodes in m_functionStack. (Recorded to avoid double lookup.)
 
+        RefPtr<SourceProvider> m_sourceProvider;
+
         OwnPtr<ProgramCodeBlock> m_code;
     };
 
     class EvalNode : public ScopeNode {
     public:
-        static EvalNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
+        static EvalNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, SourceProvider*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
 
         EvalCodeBlock& byteCode(ScopeChainNode* scopeChain) KJS_FAST_CALL
         {
@@ -2069,16 +2199,19 @@ namespace KJS {
         }
 
     private:
-        EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
+        EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, SourceProvider*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
 
         void generateCode(ScopeChainNode*) KJS_FAST_CALL;
         virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) KJS_FAST_CALL;
+        
+        RefPtr<SourceProvider> m_sourceProvider;
 
         OwnPtr<EvalCodeBlock> m_code;
     };
 
     class FunctionBodyNode : public ScopeNode {
     public:
+        static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, SourceProvider*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
         static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
 
         Vector<Identifier>& parameters() KJS_FAST_CALL { return m_parameters; }
@@ -2106,7 +2239,6 @@ namespace KJS {
 
         void setSource(const SourceRange& source) { m_source = source; } 
         UString toSourceString() const KJS_FAST_CALL { return UString("{") + m_source.toString() + UString("}"); }
-
     protected:
         FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, bool usesEval, bool needsClosure) KJS_FAST_CALL;
 
index f54bba2..654d7f2 100644 (file)
@@ -1,3 +1,26 @@
+2008-07-18  Oliver Hunt  <oliver@apple.com>
+
+        Reviewed by Cameron Zwarich.
+
+        Update layout tests for new exception text, and add additional test covering the
+        expression ranges provided.
+
+        * fast/css/resources/font-face-descriptor-multiple-values-parsing.js:
+        * fast/dom/SelectorAPI/dumpNodeList-expected.txt:
+        * fast/forms/select-namedItem-expected.txt:
+        * fast/js/exception-expression-offset.html: Added.
+        * fast/js/resources/exception-expression-offset.js: Added.
+          New test covering the offset positions given for exceptions
+        * fast/xsl/transform-xhr-doc-expected.txt:
+        * http/tests/security/aboutBlank/xss-DENIED-navigate-opener-document-write-expected.txt:
+        * http/tests/security/aboutBlank/xss-DENIED-navigate-opener-javascript-url-expected.txt:
+        * http/tests/security/aboutBlank/xss-DENIED-set-opener-expected.txt:
+        * http/tests/security/cross-frame-access-call.html:
+        * platform/mac/fast/events/updateLayoutForHitTest-expected.txt:
+        * platform/mac/svg/custom/createelement-expected.txt:
+        * platform/mac/tables/mozilla/bugs/bug53690-1-expected.txt:
+        * platform/mac/tables/mozilla_expected_failures/bugs/bug92868_1-expected.txt:
+
 2008-07-18  Adele Peterson & Maxime Britto  <britto@apple.com>
 
         Reviewed by Adele.
index bcb7eca..c5acda6 100644 (file)
@@ -16,24 +16,24 @@ shouldBe('test("font-weight", "all")', '"all"');
 shouldBe('test("font-weight", "100, 200")', '"100, 200"');
 shouldBe('test("font-weight", "bold, normal")', '"bold, normal"');
 shouldBe('test("font-weight", "100, 200, 300, 400, 500, 600, 700, 100")', '"100, 200, 300, 400, 500, 600, 700, 100"');
-shouldThrow('test("font-weight", "all, 100")', '"TypeError: Null value"');
-shouldThrow('test("font-weight", "bold, normal, all")', '"TypeError: Null value"');
-shouldThrow('test("font-weight", "")', '"TypeError: Null value"');
+shouldThrow('test("font-weight", "all, 100")', '"TypeError: Result of expression \'style.sheet.rules[0].style.getPropertyCSSValue(property)\' [null] is not an object."');
+shouldThrow('test("font-weight", "bold, normal, all")', '"TypeError: Result of expression \'style.sheet.rules[0].style.getPropertyCSSValue(property)\' [null] is not an object."');
+shouldThrow('test("font-weight", "")', '"TypeError: Result of expression \'style.sheet.rules[0].style.getPropertyCSSValue(property)\' [null] is not an object."');
 
 shouldBe('test("font-style", "normal")', '"normal"');
 shouldBe('test("font-style", "italic")', '"italic"');
 shouldBe('test("font-style", "normal, oblique")', '"normal, oblique"');
 shouldBe('test("font-style", "all")', '"all"');
-shouldThrow('test("font-style", "all, normal")', '"TypeError: Null value"');
-shouldThrow('test("font-style", "italic, all")', '"TypeError: Null value"');
-shouldThrow('test("font-style", "")', '"TypeError: Null value"');
+shouldThrow('test("font-style", "all, normal")', '"TypeError: Result of expression \'style.sheet.rules[0].style.getPropertyCSSValue(property)\' [null] is not an object."');
+shouldThrow('test("font-style", "italic, all")', '"TypeError: Result of expression \'style.sheet.rules[0].style.getPropertyCSSValue(property)\' [null] is not an object."');
+shouldThrow('test("font-style", "")', '"TypeError: Result of expression \'style.sheet.rules[0].style.getPropertyCSSValue(property)\' [null] is not an object."');
 
 shouldBe('test("font-variant", "normal")', '"normal"');
 shouldBe('test("font-variant", "small-caps")', '"small-caps"');
 shouldBe('test("font-variant", "normal, small-caps")', '"normal, small-caps"');
 shouldBe('test("font-variant", "all")', '"all"');
-shouldThrow('test("font-variant", "all, normal")', '"TypeError: Null value"');
-shouldThrow('test("font-variant", "small-caps, all")', '"TypeError: Null value"');
-shouldThrow('test("font-variant", "")', '"TypeError: Null value"');
+shouldThrow('test("font-variant", "all, normal")', '"TypeError: Result of expression \'style.sheet.rules[0].style.getPropertyCSSValue(property)\' [null] is not an object."');
+shouldThrow('test("font-variant", "small-caps, all")', '"TypeError: Result of expression \'style.sheet.rules[0].style.getPropertyCSSValue(property)\' [null] is not an object."');
+shouldThrow('test("font-variant", "")', '"TypeError: Result of expression \'style.sheet.rules[0].style.getPropertyCSSValue(property)\' [null] is not an object."');
 
 var successfullyParsed = true;
index b629ec8..d8117f7 100644 (file)
@@ -46,8 +46,8 @@ Error: SYNTAX_ERR: DOM Exception 12
 
 Document.querySelector
 
-TypeError: Null value
-TypeError: Null value
+TypeError: Result of expression 'node.querySelector(selectorString)' [null] is not an object.
+TypeError: Result of expression 'node.querySelector(selectorString)' [null] is not an object.
 [object HTMLDivElement]
 [object HTMLDivElement]
 [object HTMLDivElement]
@@ -58,9 +58,9 @@ Error: SYNTAX_ERR: DOM Exception 12
 
 Element.querySelector
 
-TypeError: Null value
-TypeError: Null value
-TypeError: Null value
+TypeError: Result of expression 'node.querySelector(selectorString)' [null] is not an object.
+TypeError: Result of expression 'node.querySelector(selectorString)' [null] is not an object.
+TypeError: Result of expression 'node.querySelector(selectorString)' [null] is not an object.
 [object HTMLDivElement]
 [object HTMLDivElement]
 [object HTMLDivElement]
@@ -71,9 +71,9 @@ Error: SYNTAX_ERR: DOM Exception 12
 
 DocumentFragment.querySelector
 
-TypeError: Null value
-TypeError: Null value
-TypeError: Null value
+TypeError: Result of expression 'node.querySelector(selectorString)' [null] is not an object.
+TypeError: Result of expression 'node.querySelector(selectorString)' [null] is not an object.
+TypeError: Result of expression 'node.querySelector(selectorString)' [null] is not an object.
 [object HTMLDivElement]
 [object HTMLDivElement]
 [object HTMLDivElement]
index caef5ea..9a59c87 100644 (file)
@@ -4,5 +4,5 @@ FOUND ITEM: 2
 FOUND ITEM: 1
 FOUND ITEM: 1
 FOUND ITEM: 1
-ERROR: Null value
+ERROR: Result of expression 'item' [null] is not an object.
 
diff --git a/LayoutTests/fast/js/exception-expression-offset.html b/LayoutTests/fast/js/exception-expression-offset.html
new file mode 100644 (file)
index 0000000..3b18ed6
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="resources/js-test-style.css">
+<script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="resources/exception-expression-offset.js"></script>
+<script src="resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/fast/js/resources/exception-expression-offset.js b/LayoutTests/fast/js/resources/exception-expression-offset.js
new file mode 100644 (file)
index 0000000..5f45167
--- /dev/null
@@ -0,0 +1,38 @@
+description('This test exercises the source expression offset information that is attached to exception objects for the inspector.');
+var ex;
+
+function testException(code, errorStart, errorCaret, errorEnd, message) {
+    try {
+        debug("");
+        debug("Testing '"+code+"'");
+        eval(code);
+    } catch (e) {
+        ex = e;
+        shouldBeTrue('ex.expressionBeginOffset == ' + errorStart);
+        shouldBeTrue('ex.expressionCaretOffset == ' + errorCaret);
+        shouldBeTrue('ex.expressionEndOffset == ' + errorEnd);
+        shouldBeTrue('ex.message == "' + message +'"');
+    }
+}
+
+testException("undefined.a++", 0, 9, 11, "Result of expression 'undefined' [undefined] is not an object.");
+testException("++undefined.a", 2, 11, 13, "Result of expression 'undefined' [undefined] is not an object.");
+testException("undefined[0]++", 0, 9, 12, "Result of expression 'undefined' [undefined] is not an object.");
+testException("++undefined[1]", 2, 11, 14, "Result of expression 'undefined' [undefined] is not an object.");
+testException("undefined.b", 0, 9, 11, "Result of expression 'undefined' [undefined] is not an object.");
+testException("undefined[0]", 0, 9, 12, "Result of expression 'undefined' [undefined] is not an object.");
+testException("undefined.b += 1", 0, 9, 11, "Result of expression 'undefined' [undefined] is not an object.");
+testException("undefined[0] += 1", 0, 9, 12, "Result of expression 'undefined' [undefined] is not an object.");
+testException("undefined()", 0, 9, 11, "Result of expression 'undefined' [undefined] is not a function.");
+testException("new undefined()", 0, 13, 15, "Result of expression 'undefined' [undefined] is not a constructor.");
+testException("({}).b()", 0, 6, 8, "Result of expression '({}).b' [undefined] is not a function.");
+testException("new {}.b()", 0, 8, 10, "Result of expression '{}.b' [undefined] is not a constructor.");
+testException("1()", 0, 1, 3, "Result of expression '1' [1] is not a function.");
+testException("new 1()", 0, 5, 7, "Result of expression '1' [1] is not a constructor.");
+testException("throw { message : 'thrown object' }", 0, undefined, 35, "thrown object");
+testException("1 in undefined", 0, 5, 14, "Result of expression 'undefined' [undefined] is not a valid argument for 'in'.");
+testException("1 instanceof undefined", 0, 13, 22, "Result of expression 'undefined' [undefined] is not a valid argument for 'instanceof'.");
+testException("for (undefined.b in [1]) {}", 5, 14, 16, "Result of expression 'undefined' [undefined] is not an object.");
+testException("for (undefined[0] in [1]) {}", 5, 14, 17, "Result of expression 'undefined' [undefined] is not an object.");
+
+var successfullyParsed = true;
index 5e08d1f..d2bb492 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 20: Undefined value
+CONSOLE MESSAGE: line 20: Result of expression 'doc' [undefined] is not an object.
 Test for bug 10313: xsl:import doesn't work in stylesheets loaded via XMLHttpRequest.
 
 It's nice that this hasn't crashed, but the XSL transformation has failed.
index 623e786..126cef4 100644 (file)
@@ -1,6 +1,6 @@
 CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/innocent-victim-with-notify.html from frame with URL about:blank. Domains, protocols and ports must match.
 
-CONSOLE MESSAGE: line 1: Undefined value
+CONSOLE MESSAGE: line 1: Result of expression 'target.document' [undefined] is not an object.
 This page opens a window to "", injects malicious code, and then navigates its opener to the victim. The opened window then tries to scripts its opener after document.writeing a new document.
 Code injected into window:
 <script>document.write('<script>function write(target, message) { target.document.body.innerHTML = message; }setTimeout(function() {write(window.opener, \'FAIL: XSS was allowed.\');}, 100);setTimeout(function() {write(window.opener.top.frames[1], \'SUCCESS: Window remained in original SecurityOrigin.\');}, 200);setTimeout(function() { if (window.layoutTestController) layoutTestController.globalFlag = true; }, 300);<\/script>');</script>
index a57b56e..8218e30 100644 (file)
@@ -1,6 +1,6 @@
 CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/innocent-victim-with-notify.html from frame with URL http://127.0.0.1:8000/security/aboutBlank/xss-DENIED-navigate-opener-javascript-url.html. Domains, protocols and ports must match.
 
-CONSOLE MESSAGE: line 1: Undefined value
+CONSOLE MESSAGE: line 1: Result of expression 'target.document' [undefined] is not an object.
 This page opens a window to "", injects malicious code, and then navigates its opener to the victim. The opened window then tries to scripts its opener after reloading itself as a javascript URL.
 Code injected into window:
 <script>window.location = 'javascript:\'<script>function write(target, message) { target.document.body.innerHTML = message; }setTimeout(function() {write(window.opener, \\\'FAIL: XSS was allowed.\\\');}, 100);setTimeout(function() {write(window.opener.top.frames[1], \\\'SUCCESS: Window remained in original SecurityOrigin.\\\');}, 200);setTimeout(function() { if (window.layoutTestController) layoutTestController.globalFlag = true; }, 300);<\\\/script>\''</script>
index 0542488..a658c75 100644 (file)
@@ -2,7 +2,7 @@ CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http
 
 CONSOLE MESSAGE: line 1: Unsafe JavaScript attempt to access frame with URL http://localhost:8000/security/resources/innocent-victim.html from frame with URL about:blank. Domains, protocols and ports must match.
 
-CONSOLE MESSAGE: line 1: Undefined value
+CONSOLE MESSAGE: line 1: Result of expression 'target.document' [undefined] is not an object.
 This page opens a window to "", injects malicious code, and then uses window.open.call to set its opener to the victim. The opened window then tries to scripts its opener.
 Code injected into window:
 <script>function write(target, message) { target.document.body.innerHTML = message; }
index 90523a5..d768858 100644 (file)
@@ -56,7 +56,7 @@ window.onload = function()
     shouldBe("window.resizeTo.call(targetWindow, 0, 0);", "undefined");
 
     // Throws a TypeError and logs to the error console
-    shouldBe("window.showModalDialog.call(targetWindow);", "'TypeError: Undefined value'");
+    shouldBe("window.showModalDialog.call(targetWindow);", "'Result of expression 'window.showModalDialog' [undefined] is not an object.'");
 
     // - Tests for the Location object -
     // undefined value indicates failure
index e489abc..3801ee3 100644 (file)
@@ -1,7 +1,7 @@
-CONSOLE MESSAGE: line 36: Null value
-CONSOLE MESSAGE: line 40: Null value
-CONSOLE MESSAGE: line 36: Null value
-CONSOLE MESSAGE: line 40: Null value
+CONSOLE MESSAGE: line 36: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
+CONSOLE MESSAGE: line 40: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
+CONSOLE MESSAGE: line 36: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
+CONSOLE MESSAGE: line 40: Result of expression 'triangleSpan.nextSibling.nextSibling.nextSibling.nextSibling' [null] is not an object.
 layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
 layer at (0,0) size 800x600
index fbbc261..07c364a 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 13: TypeError: Null value
+CONSOLE MESSAGE: line 13: TypeError: Result of expression 'green' [null] is not an object.
 layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
 layer at (0,0) size 800x600
index b4dcf10..fa5a7a8 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 4: TypeError: Undefined value
+CONSOLE MESSAGE: line 4: TypeError: Result of expression 'document.forms[1]' [undefined] is not an object.
 layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
 layer at (0,0) size 800x600
index 6518515..087a892 100644 (file)
@@ -1,4 +1,4 @@
-CONSOLE MESSAGE: line 14: Undefined value
+CONSOLE MESSAGE: line 14: Result of expression 'document.styleSheets[1].disabled =' [undefined] is not an object.
 layer at (0,0) size 800x600
   RenderView at (0,0) size 800x600
 layer at (0,0) size 800x76