#include "Escargot.h" #include "GlobalObject.h" #include "Context.h" #include "ErrorObject.h" #include "StringObject.h" #include "NumberObject.h" #include "parser/ScriptParser.h" #include "parser/esprima_cpp/esprima.h" #include "heap/HeapProfiler.h" namespace Escargot { #ifdef ESCARGOT_SHELL static Value builtinPrint(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { puts(argv[0].toString(state)->toUTF8StringData().data()); return Value(); } static Value builtinLoad(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { auto f = argv[0].toString(state)->toUTF8StringData(); const char* fileName = f.data(); FILE* fp = fopen(fileName, "r"); String* src = String::emptyString; if (fp) { std::string str; char buf[512]; while (fgets(buf, sizeof buf, fp) != NULL) { str += buf; } fclose(fp); src = new UTF16String(std::move(utf8StringToUTF16String(str.data(), str.length()))); } Context* context = state.context(); auto result = context->scriptParser().parse(src, argv[0].toString(state)); if (!result.m_error) { result.m_script->execute(context); } return Value(); } #endif static Value builtinGc(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { GC_gcollect_and_unmap(); return Value(); } static Value builtinEval(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { return state.context()->globalObject()->eval(state, argv[0], nullptr); } Value GlobalObject::eval(ExecutionState& state, const Value& arg, CodeBlock* parentCodeBlock) { if (arg.isString()) { ScriptParser parser(state.context()); const char* s = "eval input"; ScriptParser::ScriptParserResult parserResult = parser.parse(StringView(arg.asString(), 0, arg.asString()->length()), String::fromUTF8(s, strlen(s)), parentCodeBlock); if (parserResult.m_error) { TypeErrorObject* err = new TypeErrorObject(state, parserResult.m_error->message); state.throwException(err); } if (!parentCodeBlock) { return parserResult.m_script->execute(state.context()); } else { return parserResult.m_script->executeLocal(state); } } return arg; } static int parseDigit(char16_t c, int radix) { int digit = -1; if (c >= '0' && c <= '9') digit = c - '0'; else if (c >= 'A' && c <= 'Z') digit = c - 'A' + 10; else if (c >= 'a' && c <= 'z') digit = c - 'a' + 10; if (digit >= radix) return -1; return digit; } static Value builtinParseInt(ExecutionState& state, Value thisValue, size_t argc, Value* argv, bool isNewExpression) { Value ret; // 1. Let inputString be ToString(string). Value input = argv[0]; String* s = input.toString(state); // 2. Let S be a newly created substring of inputString consisting of the first character that is not a StrWhiteSpaceChar // and all characters following that character. (In other words, remove leading white space.) unsigned p = 0; unsigned strLen = s->length(); for (; p < strLen; p++) { char16_t c = s->charAt(p); if (!(esprima::isWhiteSpace(c) || esprima::isLineTerminator(c))) break; } // 3. Let sign be 1. // 4. If S is not empty and the first character of S is a minus sign -, let sign be −1. // 5. If S is not empty and the first character of S is a plus sign + or a minus sign -, then remove the first character from S. double sign = 1; if (p < strLen) { if (s->charAt(p) == '+') p++; else if (s->charAt(p) == '-') { sign = -1; p++; } } // 6. Let R = ToInt32(radix). // 7. Let stripPrefix be true. // 8. If R ≠ 0, then // b. If R 16, let stripPrefix be false. // 9. Else, R = 0 // a. Let R = 10. // 10. If stripPrefix is true, then // a. If the length of S is at least 2 and the first two characters of S are either “0x” or “0X”, then remove the first two characters from S and let R = 16. // 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S consisting of all characters // before the first such character; otherwise, let Z be S. int radix = 0; if (argc >= 2) { radix = argv[1].toInt32(state); } if ((radix == 0 || radix == 16) && strLen - p >= 2 && s->charAt(p) == '0' && (s->charAt(p + 1) == 'x' || s->charAt(p + 1) == 'X')) { radix = 16; p += 2; } if (radix == 0) radix = 10; // 8.a If R < 2 or R > 36, then return NaN. if (radix < 2 || radix > 36) return Value(std::numeric_limits::quiet_NaN()); // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, // using the letters AZ and az for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant digits, // every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation; // and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the mathematical integer value // that is represented by Z in radix-R notation.) // 14. Let number be the Number value for mathInt. bool sawDigit = false; double number = 0.0; while (p < strLen) { int digit = parseDigit(s->charAt(p), radix); if (digit == -1) break; sawDigit = true; number *= radix; number += digit; p++; } // 12. If Z is empty, return NaN. if (!sawDigit) return Value(std::numeric_limits::quiet_NaN()); // 15. Return sign × number. return Value(sign * number); } void GlobalObject::installOthers(ExecutionState& state) { defineOwnProperty(state, state.context()->staticStrings().Infinity, ObjectPropertyDescriptor(Value(std::numeric_limits::infinity()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NotPresent))); defineOwnProperty(state, state.context()->staticStrings().NaN, ObjectPropertyDescriptor(Value(std::numeric_limits::quiet_NaN()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NotPresent))); defineOwnProperty(state, state.context()->staticStrings().undefined, ObjectPropertyDescriptor(Value(), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::NotPresent))); m_eval = new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().eval, builtinEval, 1, nullptr, NativeFunctionInfo::Strict), false); defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().eval), ObjectPropertyDescriptor(m_eval, (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().parseInt), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().parseInt, builtinParseInt, 2, nullptr, NativeFunctionInfo::Strict), false), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::WritablePresent | ObjectPropertyDescriptor::ConfigurablePresent))); #ifdef ESCARGOT_SHELL defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().print), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().print, builtinPrint, 1, nullptr, NativeFunctionInfo::Strict), false), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent))); defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().load), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().load, builtinLoad, 1, nullptr, NativeFunctionInfo::Strict), false), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent))); #endif defineOwnProperty(state, ObjectPropertyName(state.context()->staticStrings().gc), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(state.context()->staticStrings().gc, builtinGc, 0, nullptr, NativeFunctionInfo::Strict), false), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent))); #ifdef PROFILE_BDWGC AtomicString dumpBackTrace(state, "dumpBackTrace"); defineOwnProperty(state, ObjectPropertyName(dumpBackTrace), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(dumpBackTrace, builtinDumpBackTrace, 1, nullptr, NativeFunctionInfo::Strict), false), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent))); AtomicString registerLeakCheck(state, "registerLeakCheck"); defineOwnProperty(state, ObjectPropertyName(registerLeakCheck), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(registerLeakCheck, builtinRegisterLeakCheck, 2, nullptr, NativeFunctionInfo::Strict), false), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent))); AtomicString setPhaseName(state, "setPhaseName"); defineOwnProperty(state, ObjectPropertyName(setPhaseName), ObjectPropertyDescriptor(new FunctionObject(state, NativeFunctionInfo(setPhaseName, builtinSetGCPhaseName, 1, nullptr, NativeFunctionInfo::Strict), false), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::AllPresent))); #endif m_stringProxyObject = new StringObject(state); m_numberProxyObject = new NumberObject(state); } }