27 #include "function_object.h"
30 #include "operations.h"
49 char hexdigits[] =
"0123456789ABCDEF";
54 for (
int k = 0; k <
string.size(); k++) {
57 if (unescapedSet.
find(C) >= 0) {
58 if (encbufLen+1 >= encbufAlloc)
59 encbuf = (
UChar*)realloc(encbuf,(encbufAlloc *= 2)*
sizeof(
UChar));
60 encbuf[encbufLen++] = C;
63 unsigned char octets[4];
66 unsigned short zzzzzzz = C.uc;
70 else if (C.uc <= 0x07FF) {
71 unsigned short zzzzzz = C.uc & 0x3F;
72 unsigned short yyyyy = (C.uc >> 6) & 0x1F;
73 octets[0] = 0xC0 | yyyyy;
74 octets[1] = 0x80 | zzzzzz;
77 else if (C.uc >= 0xD800 && C.uc <= 0xDBFF) {
80 if (k + 1 >=
string.size()) {
82 exec->setException(err);
87 unsigned short Cnext =
UChar(
string[++k]).uc;
89 if (Cnext < 0xDC00 || Cnext > 0xDFFF) {
91 exec->setException(err);
96 unsigned short zzzzzz = Cnext & 0x3F;
97 unsigned short yyyy = (Cnext >> 6) & 0x0F;
98 unsigned short xx = C.uc & 0x03;
99 unsigned short wwww = (C.uc >> 2) & 0x0F;
100 unsigned short vvvv = (C.uc >> 6) & 0x0F;
101 unsigned short uuuuu = vvvv+1;
102 octets[0] = 0xF0 | (uuuuu >> 2);
103 octets[1] = 0x80 | ((uuuuu & 0x03) << 4) | wwww;
104 octets[2] = 0x80 | (xx << 4) | yyyy;
105 octets[3] = 0x80 | zzzzzz;
108 else if (C.uc >= 0xDC00 && C.uc <= 0xDFFF) {
110 exec->setException(err);
116 unsigned short zzzzzz = C.uc & 0x3F;
117 unsigned short yyyyyy = (C.uc >> 6) & 0x3F;
118 unsigned short xxxx = (C.uc >> 12) & 0x0F;
119 octets[0] = 0xE0 | xxxx;
120 octets[1] = 0x80 | yyyyyy;
121 octets[2] = 0x80 | zzzzzz;
125 while (encbufLen+3*octets_len >= encbufAlloc)
126 encbuf = (
UChar*)realloc(encbuf,(encbufAlloc *= 2)*
sizeof(
UChar));
128 for (
int j = 0; j < octets_len; j++) {
129 encbuf[encbufLen++] =
'%';
130 encbuf[encbufLen++] = hexdigits[octets[j] >> 4];
131 encbuf[encbufLen++] = hexdigits[octets[j] & 0x0F];
136 UString encoded(encbuf,encbufLen);
141 static bool decodeHex(
UChar hi,
UChar lo,
unsigned short *val)
144 if (hi.uc >=
'0' && hi.uc <=
'9')
145 *val = (hi.uc-
'0') << 4;
146 else if (hi.uc >=
'a' && hi.uc <=
'f')
147 *val = 10+(hi.uc-
'a') << 4;
148 else if (hi.uc >=
'A' && hi.uc <=
'F')
149 *val = 10+(hi.uc-
'A') << 4;
153 if (lo.uc >=
'0' && lo.uc <=
'9')
155 else if (lo.uc >=
'a' && lo.uc <=
'f')
156 *val |= 10+(lo.uc-
'a');
157 else if (lo.uc >=
'A' && lo.uc <=
'F')
158 *val |= 10+(lo.uc-
'A');
171 for (
int k = 0; k <
string.size(); k++) {
174 if (C !=
UChar(
'%')) {
176 if (decbufLen+1 >= decbufAlloc)
177 decbuf = (
UChar*)realloc(decbuf,(decbufAlloc *= 2)*
sizeof(
UChar));
178 decbuf[decbufLen++] = C;
184 if (k+2 >=
string.size()) {
186 exec->setException(err);
192 if (!decodeHex(
string[k+1],
string[k+2],&B)) {
194 exec->setException(err);
201 if (decbufLen+2 >= decbufAlloc)
202 decbuf = (
UChar*)realloc(decbuf,(decbufAlloc *= 2)*
sizeof(
UChar));
204 if ((B & 0x80) == 0) {
211 while (((B << n) & 0x80) != 0)
214 if (n < 2 || n > 4) {
216 exec->setException(err);
221 if (k+3*(n-1) >=
string.size()) {
223 exec->setException(err);
228 unsigned short octets[4];
230 for (
int j = 1; j < n; j++) {
233 !decodeHex(
string[k+1],
string[k+2],&B) ||
234 ((B & 0xC0) != 0x80)) {
236 exec->setException(err);
246 const unsigned long replacementChar = 0xFFFD;
249 unsigned long yyyyy = octets[0] & 0x1F;
250 unsigned long zzzzzz = octets[1] & 0x3F;
251 V = (yyyyy << 6) | zzzzzz;
255 C =
UChar((
unsigned short)V);
258 unsigned long xxxx = octets[0] & 0x0F;
259 unsigned long yyyyyy = octets[1] & 0x3F;
260 unsigned long zzzzzz = octets[2] & 0x3F;
261 V = (xxxx << 12) | (yyyyyy << 6) | zzzzzz;
264 if (V < 0x800 || V == 0xFFFE || V == 0xFFFF ||
265 (V >= 0xD800 && V <= 0xDFFF))
267 C =
UChar((
unsigned short)V);
271 unsigned long uuuuu = ((octets[0] & 0x07) << 2) | ((octets[1] >> 4) & 0x03);
272 unsigned long vvvv = uuuuu-1;
275 exec->setException(err);
279 unsigned long wwww = octets[1] & 0x0F;
280 unsigned long xx = (octets[2] >> 4) & 0x03;
281 unsigned long yyyy = octets[2] & 0x0F;
282 unsigned long zzzzzz = octets[3] & 0x3F;
283 unsigned short H = 0xD800 | (vvvv << 6) | (wwww << 2) | xx;
284 unsigned short L = 0xDC00 | (yyyy << 6) | zzzzzz;
285 decbuf[decbufLen++] =
UChar(H);
286 decbuf[decbufLen++] =
UChar(L);
291 if (reservedSet.
find(C) < 0) {
292 decbuf[decbufLen++] = C;
296 while (decbufLen+k-start+1 >= decbufAlloc)
297 decbuf = (
UChar*)realloc(decbuf,(decbufAlloc *= 2)*
sizeof(
UChar));
298 for (
int p = start; p <= k; p++)
299 decbuf[decbufLen++] =
string[p];
303 UString decoded(decbuf,decbufLen);
308 static UString uriReserved =
";/?:@&=+$,";
309 static UString uriAlpha =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
310 static UString DecimalDigit =
"0123456789";
311 static UString uriMark =
"-_.!~*'()";
312 static UString uriUnescaped = uriAlpha+DecimalDigit+uriMark;
316 const ClassInfo FunctionImp::info = {
"Function", &InternalFunctionImp::info, 0, 0};
322 ~Parameter() {
delete next; }
330 static_cast<
FunctionPrototypeImp*>(exec->lexicalInterpreter()->builtinFunctionPrototype().imp())
331 ), param(0L), line0(-1), line1(-1), sid(-1)
337 FunctionImp::~FunctionImp()
342 bool FunctionImp::implementsCall()
const
353 exec->
context().imp(),
this, &args);
355 newExec.setException(exec->exception());
358 processParameters(&newExec, args);
360 processVarDecls(&newExec);
362 ctx.setLines(line0,line0);
363 Debugger *dbg = exec->interpreter()->imp()->debugger();
365 if (!dbg->enterContext(&newExec)) {
374 ctx.setLines(line1,line1);
379 if (!dbg->exitContext(&newExec,comp)) {
387 if (newExec.hadException())
388 exec->setException(newExec.exception());
392 if (comp.complType() == Throw) {
394 printInfo(exec, n.c_str(), comp.value());
395 }
else if (comp.complType() == ReturnValue) {
397 printInfo(exec, n.c_str(), comp.value());
399 fprintf(stderr,
"%s returns: undefined\n", n.c_str());
402 if (comp.complType() == Throw) {
403 exec->setException(comp.value());
406 else if (comp.complType() == ReturnValue)
412 void FunctionImp::addParameter(
const Identifier &n)
414 Parameter **p = ¶m;
418 *p =
new Parameter(n);
421 Identifier FunctionImp::parameterProperty(
int index)
const
426 for (p = param; p && pos < index; p = p->next)
434 for (p = p->next; p; p = p->next)
441 UString FunctionImp::parameterString()
const
444 const Parameter *p = param;
448 s += p->name.ustring();
457 void FunctionImp::processParameters(
ExecState *exec,
const List &args)
462 fprintf(stderr,
"---------------------------------------------------\n"
463 "processing parameters for %s call\n",
464 name().isEmpty() ?
"(internal)" :
name().ascii());
469 Parameter *p = param;
471 if (it != args.
end()) {
473 fprintf(stderr,
"setting parameter %s ", p->name.ascii());
474 printInfo(exec,
"to", *it);
476 variable.
put(exec, p->name, *it);
485 for (
int i = 0; i < args.
size(); i++)
486 printInfo(exec,
"setting argument", args[i]);
491 void FunctionImp::processVarDecls(
ExecState * )
498 if (propertyName == argumentsPropertyName) {
504 if (context->function() ==
this)
505 return static_cast<ActivationImp *
>
506 (context->activationObject())->get(exec, propertyName);
507 context = context->callingContext();
513 if (propertyName == lengthPropertyName) {
514 const Parameter * p = param;
523 if (propertyName == callerPropertyName) {
526 if (context->function() ==
this) {
528 if (cc && cc->function())
529 return Value(cc->function());
533 context = context->callingContext();
538 return InternalFunctionImp::get(exec, propertyName);
543 if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
545 InternalFunctionImp::put(exec, propertyName, value, attr);
550 if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
552 return InternalFunctionImp::hasProperty(exec, propertyName);
557 if (propertyName == argumentsPropertyName || propertyName == lengthPropertyName)
559 return InternalFunctionImp::deleteProperty(exec, propertyName);
565 const ClassInfo DeclaredFunctionImp::info = {
"Function", &FunctionImp::info, 0, 0};
574 line0 = body->firstLine();
575 line1 = body->lastLine();
576 sid = body->sourceId();
579 DeclaredFunctionImp::~DeclaredFunctionImp()
585 bool DeclaredFunctionImp::implementsConstruct()
const
594 Value p = get(exec,prototypePropertyName);
595 if (p.
type() == ObjectType)
596 proto =
Object(
static_cast<ObjectImp*
>(p.imp()));
600 Object obj(
new ObjectImp(proto));
602 Value res = call(exec,obj,args);
604 if (res.
type() == ObjectType)
605 return Object::dynamicCast(res);
614 if (result.complType() == Throw || result.complType() == ReturnValue)
619 void DeclaredFunctionImp::processVarDecls(
ExecState *exec)
621 body->processVarDecls(exec);
630 class ShadowImp :
public ObjectImp {
632 ShadowImp(ObjectImp *_obj,
Identifier _prop) : obj(_obj), prop(_prop) {}
635 virtual const ClassInfo *classInfo()
const {
return &info; }
642 const ClassInfo ShadowImp::info = {
"Shadow", 0, 0, 0};
644 void ShadowImp::mark()
655 const ClassInfo ArgumentsImp::info = {
"Arguments", 0, 0, 0};
660 : ObjectImp(exec->lexicalInterpreter()->builtinObjectPrototype()), activation(act)
663 putDirect(calleePropertyName, func, DontEnum);
664 putDirect(lengthPropertyName, args.
size(), DontEnum);
667 for (
int i = 0; arg != args.
end(); arg++, i++) {
670 Object shadow(
new ShadowImp(act,prop));
671 ObjectImp::put(exec,Identifier::from(i), shadow, DontEnum);
674 ObjectImp::put(exec,Identifier::from(i), *arg, DontEnum);
680 void ArgumentsImp::mark()
683 if (!activation->marked())
689 Value val = ObjectImp::get(exec,propertyName);
690 assert(SimpleNumber::is(val.imp()) || !val.imp()->isDestroyed());
691 Object obj = Object::dynamicCast(val);
692 if (obj.
isValid() && obj.inherits(&ShadowImp::info)) {
693 ShadowImp *shadow =
static_cast<ShadowImp*
>(val.imp());
694 return activation->get(exec,shadow->prop);
702 const Value &value,
int attr)
704 Value val = ObjectImp::get(exec,propertyName);
705 Object obj = Object::dynamicCast(val);
706 if (obj.
isValid() && obj.inherits(&ShadowImp::info)) {
707 ShadowImp *shadow =
static_cast<ShadowImp*
>(val.imp());
708 activation->put(exec,shadow->prop,value,attr);
711 ObjectImp::put(exec,propertyName,value,attr);
717 const ClassInfo ActivationImp::info = {
"Activation", 0, 0, 0};
720 ActivationImp::ActivationImp(
FunctionImp *
function,
const List &arguments)
721 : _function(function), _arguments(true), _argumentsObject(0)
723 _arguments = arguments.
copy();
729 if (propertyName == argumentsPropertyName) {
731 ValueImp *v = getDirect(propertyName);
736 if (!_argumentsObject)
737 _argumentsObject =
new ArgumentsImp(exec, _function, _arguments,
const_cast<ActivationImp*
>(
this));
738 return Value(_argumentsObject);
740 return ObjectImp::get(exec, propertyName);
745 if (propertyName == argumentsPropertyName)
747 return ObjectImp::hasProperty(exec, propertyName);
752 if (propertyName == argumentsPropertyName)
754 return ObjectImp::deleteProperty(exec, propertyName);
757 void ActivationImp::mark()
760 if (_function && !_function->marked())
763 if (_argumentsObject && !_argumentsObject->marked())
764 _argumentsObject->mark();
775 putDirect(lengthPropertyName, len, DontDelete|ReadOnly|DontEnum);
779 CodeType GlobalFuncImp::codeType()
const
781 return id == Eval ? EvalCode : codeType();
784 bool GlobalFuncImp::implementsCall()
const
793 static const char do_not_escape[] =
794 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
795 "abcdefghijklmnopqrstuvwxyz"
802 if (x.
type() != StringType)
810 fprintf(stderr,
"eval(): %s\n", s.
ascii());
813 FunctionBodyNode *progNode = Parser::parse(s.
data(),s.
size(),&source,&errLine,&errMsg);
816 Debugger *dbg = exec->interpreter()->imp()->debugger();
818 bool cont = dbg->sourceParsed(exec,source->sid,s,errLine);
828 exec->interpreter()->imp()->addSourceCode(source);
832 Object err = Error::create(exec,SyntaxError,errMsg.
ascii(),errLine);
834 exec->setException(err);
851 newExec.setException(exec->exception());
853 ctx.setLines(progNode->firstLine(),progNode->firstLine());
855 if (!dbg->enterContext(&newExec)) {
859 if (progNode->deref())
866 progNode->processVarDecls(&newExec);
871 ctx.setLines(progNode->lastLine(),progNode->lastLine());
872 if (dbg && !dbg->exitContext(&newExec,c))
875 else if (newExec.hadException())
876 exec->setException(newExec.exception());
877 else if (c.complType() == Throw)
878 exec->setException(c.value());
879 else if (c.isValueCompletion())
882 if (progNode->deref())
890 CString cstr = args[0].toString(exec).cstring();
891 const char* startptr = cstr.c_str();
892 while ( *startptr && isspace( *startptr ) )
897 base = args[1].toInt32(exec);
900 if (*startptr ==
'-') {
904 else if (*startptr ==
'+') {
909 bool leading0 =
false;
910 if ((base == 0 || base == 16) &&
911 (*startptr ==
'0' && (startptr[1] ==
'x' || startptr[1] ==
'X'))) {
915 else if (base == 0 && *startptr ==
'0') {
920 else if (base == 0) {
924 if (base < 2 || base > 36) {
930 for (; *startptr; startptr++) {
932 if (*startptr >=
'0' && *startptr <=
'9')
933 thisval = *startptr -
'0';
934 else if (*startptr >=
'a' && *startptr <=
'z')
935 thisval = 10 + *startptr -
'a';
936 else if (*startptr >=
'A' && *startptr <=
'Z')
937 thisval = 10 + *startptr -
'A';
939 if (thisval < 0 || thisval >= base)
947 if (index == 0 && !leading0)
950 res =
Number(
double(val)*sign);
955 UString str = args[0].toString(exec);
959 const char *c = str.
ascii();
962 isHex = (c[0] ==
'0' && (c[1] ==
'x' || c[1] ==
'X'));
971 res =
Boolean(isNaN(args[0].toNumber(exec)));
974 double n = args[0].toNumber(exec);
975 res =
Boolean(!isNaN(n) && !isInf(n));
979 res =
String(decodeURI(exec,args[0].toString(exec),uriReserved+
"#"));
981 case DecodeURIComponent:
982 res =
String(decodeURI(exec,args[0].toString(exec),
""));
985 res =
String(encodeURI(exec,args[0].toString(exec),uriReserved+uriUnescaped+
"#"));
987 case EncodeURIComponent:
988 res =
String(encodeURI(exec,args[0].toString(exec),uriUnescaped));
991 UString r =
"", s, str = args[0].toString(exec);
992 const UChar *c = str.data();
993 for (
int k = 0; k < str.size(); k++, c++) {
997 sprintf(tmp,
"%%u%04X", u);
999 }
else if (u != 0 && strchr(do_not_escape, (
char)u)) {
1003 sprintf(tmp,
"%%%02X", u);
1012 UString s =
"", str = args[0].toString(exec);
1013 int k = 0, len = str.
size();
1015 const UChar *c = str.data() + k;
1017 if (*c ==
UChar(
'%') && k <= len - 6 && *(c+1) ==
UChar(
'u')) {
1018 if (Lexer::isHexDigit((c+2)->uc) && Lexer::isHexDigit((c+3)->uc) &&
1019 Lexer::isHexDigit((c+4)->uc) && Lexer::isHexDigit((c+5)->uc)) {
1020 u = Lexer::convertUnicode((c+2)->uc, (c+3)->uc,
1021 (c+4)->uc, (c+5)->uc);
1025 }
else if (*c ==
UChar(
'%') && k <= len - 3 &&
1026 Lexer::isHexDigit((c+1)->uc) && Lexer::isHexDigit((c+2)->uc)) {
1027 u =
UChar(Lexer::convertHex((c+1)->uc, (c+2)->uc));
1039 puts(args[0].toString(exec).ascii());
Represents an primitive Boolean value.
8 bit char based string class
Completion objects are used to convey the return status and value from functions.
static Object create(ExecState *exec, ErrorType errtype=GeneralError, const char *message=0, int lineno=-1, int sourceId=-1)
Factory method for error objects.
Represents the current state of script execution.
Context context() const
Returns the execution context associated with this execution state.
Interpreter * lexicalInterpreter() const
Returns the interpreter associated with the current scope's global object.
Interpreter * dynamicInterpreter() const
Returns the interpreter associated with this execution state.
Implementation class for functions implemented in JS.
The initial value of Function.prototype (and thus all objects created with the Function constructor)
Represents an Identifier for a Javascript object.
static const Identifier & null()
Creates an empty Identifier.
bool isEmpty() const
Returns that the identifiers string is set, but is empty.
Base class for all function objects.
Object builtinObjectPrototype() const
Returns the builtin "Object.prototype" object.
Object & globalObject() const
Returns the object that is used as the global object during all script execution performed by this in...
Iterator for KJS::List objects.
ListIterator begin() const
List copy() const
Make a copy of the list.
Represents an primitive Null value.
Represents an primitive Number value.
void put(ExecState *exec, const Identifier &propertyName, const Value &value, int attr=None)
Sets the specified property.
Represents an primitive String value.
bool is8Bit() const
Use this if you want to make sure that this string is a plain ASCII string.
double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
Attempts an conversion to a number.
int find(const UString &f, int pos=0) const
char * ascii() const
Convert the Unicode string to plain ASCII chars chopping of any higher bytes.
const UChar * data() const
Represents an primitive Undefined value.
ValueImp is the base type for all primitives (Undefined, Null, Boolean, String, Number) and objects i...
Value objects are act as wrappers ("smart pointers") around ValueImp objects and their descendents.
UString toString(ExecState *exec) const
Performs the ToString type conversion operation on this value (ECMA 9.8)
bool isValid() const
Returns whether or not this is a valid value.
Type type() const
Returns the type of value.
const TDEShortcut & next()
TQString name(StdAccel id)