UString FunctionExecutable::paramString() const { FunctionParameters& parameters = *m_parameters; UStringBuilder builder; for (size_t pos = 0; pos < parameters.size(); ++pos) { if (!builder.isEmpty()) builder.append(", "); builder.append(parameters[pos].ustring()); } return builder.toUString(); }
JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize) { ExecState* exec = toJS(ctx); JSLock lock(exec); unsigned count = 0; UStringBuilder builder; CallFrame* callFrame = exec; UString functionName; if (exec->callee()) { if (asObject(exec->callee())->inherits(&InternalFunction::s_info)) { functionName = asInternalFunction(exec->callee())->name(exec); builder.append("#0 "); builder.append(functionName); builder.append("() "); count++; } } while (true) { ASSERT(callFrame); int signedLineNumber; intptr_t sourceID; UString urlString; JSValue function; UString levelStr = UString::number(count); exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function); if (function) functionName = asFunction(function)->name(exec); else { // Caller is unknown, but if frame is empty we should still add the frame, because // something called us, and gave us arguments. if (count) break; } unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0; if (!builder.isEmpty()) builder.append("\n"); builder.append("#"); builder.append(levelStr); builder.append(" "); builder.append(functionName); builder.append("() at "); builder.append(urlString); builder.append(":"); builder.append(UString::number(lineNumber)); if (!function || ++count == maxStackSize) break; callFrame = callFrame->callerFrame(); } return OpaqueJSString::create(builder.toUString()).leakRef(); }
static RegExp* parseRegExpLine(JSGlobalData& globalData, char* line, int lineLength) { UStringBuilder pattern; if (line[0] != '/') return 0; int i = scanString(line + 1, lineLength - 1, pattern, '/') + 1; if ((i >= lineLength) || (line[i] != '/')) return 0; ++i; return RegExp::create(globalData, pattern.toUString(), regExpFlags(line + i)); }
Local<Unknown> Stringifier::stringify(Handle<Unknown> value) { JSObject* object = constructEmptyObject(m_exec); if (m_exec->hadException()) return Local<Unknown>(m_exec->globalData(), jsNull()); PropertyNameForFunctionCall emptyPropertyName(m_exec->globalData().propertyNames->emptyIdentifier); object->putDirect(m_exec->globalData(), m_exec->globalData().propertyNames->emptyIdentifier, value.get()); UStringBuilder result; if (appendStringifiedValue(result, value.get(), object, emptyPropertyName) != StringifySucceeded) return Local<Unknown>(m_exec->globalData(), jsUndefined()); if (m_exec->hadException()) return Local<Unknown>(m_exec->globalData(), jsNull()); return Local<Unknown>(m_exec->globalData(), jsString(m_exec, result.toUString())); }
JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&) { UString pattern = asRegExpObject(slotBase)->regExp()->pattern(); size_t forwardSlashPosition = pattern.find('/'); if (forwardSlashPosition == notFound) return jsString(exec, pattern); // 'completed' tracks the length of original pattern already copied // into the result buffer. size_t completed = 0; UStringBuilder result; do { // 'slashesPosition' points to the first (of possibly zero) backslash // prior to the forwards slash. size_t slashesPosition = forwardSlashPosition; while (slashesPosition && pattern[slashesPosition - 1] == '\\') --slashesPosition; // Check whether the number of backslashes is odd or even - // if odd, the forwards slash is already escaped, so we mustn't // double escape it. if ((forwardSlashPosition - slashesPosition) & 1) result.append(pattern.substringSharingImpl(completed, forwardSlashPosition - completed + 1)); else { result.append(pattern.substringSharingImpl(completed, forwardSlashPosition - completed)); result.append("\\/"); } completed = forwardSlashPosition + 1; forwardSlashPosition = pattern.find('/', completed); } while (forwardSlashPosition != notFound); // Copy in the remainder of the pattern to the buffer. result.append(pattern.substringSharingImpl(completed)); return jsString(exec, result.toUString()); }
// ECMA 15.3.2 The Function Constructor JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber) { // Functions need to have a space following the opening { due to for web compatibility // see https://bugs.webkit.org/show_bug.cgi?id=24350 // We also need \n before the closing } to handle // comments at the end of the last line UString program; if (args.isEmpty()) program = "(function() { \n})"; else if (args.size() == 1) program = makeUString("(function() { ", args.at(0).toString(exec), "\n})"); else { UStringBuilder builder; builder.append("(function("); builder.append(args.at(0).toString(exec)); for (size_t i = 1; i < args.size() - 1; i++) { builder.append(","); builder.append(args.at(i).toString(exec)); } builder.append(") { "); builder.append(args.at(args.size() - 1).toString(exec)); builder.append("\n})"); program = builder.toUString(); } JSGlobalObject* globalObject = exec->lexicalGlobalObject(); JSGlobalData& globalData = globalObject->globalData(); SourceCode source = makeSource(program, sourceURL, lineNumber); JSObject* exception = 0; RefPtr<FunctionExecutable> function = FunctionExecutable::fromGlobalCode(functionName, exec, exec->dynamicGlobalObject()->debugger(), source, &exception); if (!function) { ASSERT(exception); return throwError(exec, exception); } ScopeChain scopeChain(globalObject, &globalData, globalObject, exec->globalThisValue()); return new (exec) JSFunction(exec, function, scopeChain.node()); }
static RegExpTest* parseTestLine(char* line, int lineLength) { UStringBuilder subjectString; if ((line[0] != ' ') || (line[1] != '"')) return 0; int i = scanString(line + 2, lineLength - 2, subjectString, '"') + 2; if ((i >= (lineLength - 2)) || (line[i] != '"') || (line[i+1] != ',') || (line[i+2] != ' ')) return 0; i += 3; int offset; if (sscanf(line + i, "%d, ", &offset) != 1) return 0; while (line[i] && line[i] != ' ') ++i; ++i; int matchResult; if (sscanf(line + i, "%d, ", &matchResult) != 1) return 0; while (line[i] && line[i] != ' ') ++i; ++i; if (line[i++] != '(') return 0; int start, end; RegExpTest* result = new RegExpTest(); result->subject = subjectString.toUString(); result->offset = offset; result->result = matchResult; while (line[i] && line[i] != ')') { if (sscanf(line + i, "%d, %d", &start, &end) != 2) { delete result; return 0; } result->expectVector.append(start); result->expectVector.append(end); while (line[i] && (line[i] != ',') && (line[i] != ')')) i++; i++; while (line[i] && (line[i] != ',') && (line[i] != ')')) i++; if (line[i] == ')') break; if (!line[i] || (line[i] != ',')) { delete result; return 0; } i++; } return result; }
// "inline" is required here to help WINSCW compiler resolve specialized argument in templated functions. template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType LiteralParser::Lexer::lexString(LiteralParserToken& token) { ++m_ptr; const UChar* runStart; UStringBuilder builder; do { runStart = m_ptr; while (m_ptr < m_end && isSafeStringCharacter<mode>(*m_ptr)) ++m_ptr; if (runStart < m_ptr) builder.append(runStart, m_ptr - runStart); if ((mode == StrictJSON) && m_ptr < m_end && *m_ptr == '\\') { ++m_ptr; if (m_ptr >= m_end) return TokError; switch (*m_ptr) { case '"': builder.append('"'); m_ptr++; break; case '\\': builder.append('\\'); m_ptr++; break; case '/': builder.append('/'); m_ptr++; break; case 'b': builder.append('\b'); m_ptr++; break; case 'f': builder.append('\f'); m_ptr++; break; case 'n': builder.append('\n'); m_ptr++; break; case 'r': builder.append('\r'); m_ptr++; break; case 't': builder.append('\t'); m_ptr++; break; case 'u': if ((m_end - m_ptr) < 5) // uNNNN == 5 characters return TokError; for (int i = 1; i < 5; i++) { if (!isASCIIHexDigit(m_ptr[i])) return TokError; } builder.append(JSC::Lexer::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4])); m_ptr += 5; break; default: return TokError; } } } while ((mode == StrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != '"'); if (m_ptr >= m_end || *m_ptr != '"') return TokError; token.stringToken = builder.toUString(); token.type = TokString; token.end = ++m_ptr; return TokString; }
JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&) { UString pattern = asRegExpObject(slotBase)->regExp()->pattern(); unsigned length = pattern.length(); const UChar* characters = pattern.characters(); bool previousCharacterWasBackslash = false; bool inBrackets = false; bool shouldEscape = false; // 15.10.6.4 specifies that RegExp.prototype.toString must return '/' + source + '/', // and also states that the result must be a valid RegularExpressionLiteral. '//' is // not a valid RegularExpressionLiteral (since it is a single line comment), and hence // source cannot ever validly be "". If the source is empty, return a different Pattern // that would match the same thing. if (!length) return jsString(exec, "(?:)"); // early return for strings that don't contain a forwards slash and LineTerminator for (unsigned i = 0; i < length; ++i) { UChar ch = characters[i]; if (!previousCharacterWasBackslash) { if (inBrackets) { if (ch == ']') inBrackets = false; } else { if (ch == '/') { shouldEscape = true; break; } if (ch == '[') inBrackets = true; } } if (Lexer<UChar>::isLineTerminator(ch)) { shouldEscape = true; break; } if (previousCharacterWasBackslash) previousCharacterWasBackslash = false; else previousCharacterWasBackslash = ch == '\\'; } if (!shouldEscape) return jsString(exec, pattern); previousCharacterWasBackslash = false; inBrackets = false; UStringBuilder result; for (unsigned i = 0; i < length; ++i) { UChar ch = characters[i]; if (!previousCharacterWasBackslash) { if (inBrackets) { if (ch == ']') inBrackets = false; } else { if (ch == '/') result.append('\\'); else if (ch == '[') inBrackets = true; } } // escape LineTerminator if (Lexer<UChar>::isLineTerminator(ch)) { if (!previousCharacterWasBackslash) result.append('\\'); if (ch == '\n') result.append('n'); else if (ch == '\r') result.append('r'); else if (ch == 0x2028) result.append("u2028"); else result.append("u2029"); } else result.append(ch); if (previousCharacterWasBackslash) previousCharacterWasBackslash = false; else previousCharacterWasBackslash = ch == '\\'; } return jsString(exec, result.toUString()); }
JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source) { JSGlobalData* globalData = &exec->globalData(); addErrorInfo(globalData, error, line, source); UStringBuilder stackString; JSArray* stackArray = constructEmptyArray(exec); CallFrame* frame = exec; stackString.append(error->toString(exec)); bool functionKnown; ReturnAddressPtr pc; while (!frame->hasHostCallFrameFlag()) { CodeBlock* codeBlock = frame->codeBlock(); JSObject* arrayItem = constructEmptyObject(exec); stackString.append("\n at "); JSObject* callee = frame->callee(); UString functionName; if (callee && callee->inherits(&JSFunction::s_info)) { functionName = asFunction(callee)->calculatedDisplayName(exec); functionKnown = !functionName.isEmpty(); } else { functionKnown = false; } if (functionKnown) { stackString.append(functionName); stackString.append(" ("); arrayItem->putWithAttributes( globalData, Identifier(globalData, functionPropertyName), jsString(globalData, functionName), ReadOnly | DontDelete ); } UString sourceURL = codeBlock->ownerExecutable()->sourceURL(); arrayItem->putWithAttributes( globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete ); stackString.append(sourceURL); stackString.append(":"); if (frame != exec) { line = codeBlock->lineNumberForBytecodeOffset(codeBlock->bytecodeOffset(pc)); } arrayItem->putWithAttributes( globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete ); stackString.append(UString::number(line)); if (functionKnown) { stackString.append(")"); } stackArray->push(exec, JSValue(arrayItem)); pc = frame->returnPC(); frame = frame->callerFrame(); } error->putWithAttributes( globalData, Identifier(globalData, stackPropertyName), jsString(globalData, stackString.toUString()), ReadOnly | DontDelete ); error->putWithAttributes( globalData, Identifier(globalData, "stackArray"), stackArray, ReadOnly | DontDelete ); return error; }