Fix issues with (and hasOwnProperty)

This commit is contained in:
Gordon Williams 2014-04-23 14:35:03 +01:00
parent 0b44b41e3d
commit df71b0c049
7 changed files with 97 additions and 19 deletions

View File

@ -10,6 +10,7 @@
Initialise Graphics flags Graphics.createCallback - could have caused all kinds of issues
Now make setInterval > 5s less accurate when setDeepSleep is on (saves ~0.5 sec of non-sleep time)
Fixed problem when accessing an array with a string in a variable
Fix issues with `"0" in {0:1}` (and hasOwnProperty)
1v61 : Fix toString crash for large numbers
Support floating-point literals without a leading 0 - eg '.5' (fix #296)

View File

@ -702,15 +702,7 @@ NO_INLINE JsVar *jspeFactorMember(JsVar *a, JsVar **parentResult) {
index = jsvSkipNameAndUnLock(jspeAssignmentExpression());
JSP_MATCH_WITH_CLEANUP_AND_RETURN(']', jsvUnLock(parent);jsvUnLock(index);, a);
if (JSP_SHOULD_EXECUTE) {
/* Index filtering (bug #19) - if we have an array index A that is:
is_string(A) && int_to_string(string_to_int(A)) = =A
then convert it to an integer. Should be too nasty for performance
as we only do this when accessing an array with a string */
if (jsvIsString(index) && jsvIsStringNumericStrict(index)) {
JsVar *v = jsvNewFromInteger(jsvGetInteger(index));
jsvUnLock(index);
index = v;
}
index = jsvAsArrayIndexAndUnLock(index);
JsVar *aVar = jsvSkipName(a);
if (aVar && (jsvIsArrayBuffer(aVar))) {
@ -720,8 +712,6 @@ NO_INLINE JsVar *jspeFactorMember(JsVar *a, JsVar **parentResult) {
if (a) // turn into an 'array buffer name'
a->flags = (a->flags & ~(JSV_NAME|JSV_VARTYPEMASK)) | JSV_ARRAYBUFFERNAME;
} else if (aVar && (jsvIsArray(aVar) || jsvIsObject(aVar) || jsvIsFunction(aVar))) {
if (!jsvIsString(index) && (jsvIsBoolean(index) || !jsvIsNumeric(index)))
index = jsvAsString(index, true);
JsVar *child = jsvFindChildFromVar(aVar, index, false);
if (!child) {
child = jsvAsName(index);
@ -881,6 +871,7 @@ NO_INLINE JsVar *jspeFactorObject() {
JsVar *valueVar;
JsVar *value = jspeAssignmentExpression(); // value can be 0 (could be undefined!)
valueVar = jsvSkipNameAndUnLock(value);
varName = jsvAsArrayIndexAndUnLock(varName);
varName = jsvMakeIntoVariableName(varName, valueVar);
jsvAddName(contents, varName);
jsvUnLock(valueVar);
@ -1202,6 +1193,7 @@ NO_INLINE JsVar *__jspeRelationalExpression(JsVar *a) {
JsVar *av = jsvSkipName(a); // needle
JsVar *bv = jsvSkipName(b); // haystack
if (jsvIsArray(bv) || jsvIsObject(bv)) { // search keys, NOT values
av = jsvAsArrayIndexAndUnLock(av);
JsVar *varFound = jsvFindChildFromVar( bv, av, false);
res = jsvNewFromBool(varFound!=0);
jsvUnLock(varFound);

View File

@ -754,6 +754,31 @@ JsVar *jsvAsString(JsVar *v, bool unlockVar) {
return str;
}
/** Given a JsVar meant to be an index to an array, convert it to
* the actual variable type we'll use to access the array. For example
* a["0"] is actually translated to a[0]
*/
JsVar *jsvAsArrayIndex(JsVar *index) {
if (jsvIsInt(index)) {
return jsvLockAgain(index); // we're ok!
} else if (jsvIsString(index)) {
/* Index filtering (bug #19) - if we have an array index A that is:
is_string(A) && int_to_string(string_to_int(A)) == A
then convert it to an integer. Shouldn't be too nasty for performance
as we only do this when accessing an array with a string */
if (jsvIsStringNumericStrict(index))
return jsvNewFromInteger(jsvGetInteger(index));
} else if (jsvIsFloat(index)) {
// if it's a float that is actually integral, return an integer...
JsVarFloat v = jsvGetFloat(index);
JsVarInt vi = jsvGetInteger(index);
if (v == vi) return jsvNewFromInteger(vi);
}
// else if it's not a simple numeric type, convert it to a string
return jsvAsString(index, false);
}
/// Returns true if the string is empty - faster than jsvGetStringLength(v)==0
bool jsvIsEmptyString(JsVar *v) {
if (!jsvHasCharacterData(v)) return true;

View File

@ -336,22 +336,33 @@ JsVar *jsvSkipOneName(JsVar *a);
* ALWAYS locks - so must unlock what it returns. */
JsVar *jsvSkipToLastName(JsVar *a);
/** Same as jsvSkipName, but ensures that 'a' is unlocked if it was
* a name, so it can be used INLINE_FUNC */
/** Same as jsvSkipName, but ensures that 'a' is unlocked */
static inline JsVar *jsvSkipNameAndUnLock(JsVar *a) {
JsVar *b = jsvSkipName(a);
jsvUnLock(a);
return b;
}
/** Same as jsvSkipOneName, but ensures that 'a' is unlocked if it was
* a name, so it can be used INLINE_FUNC */
/** Same as jsvSkipOneName, but ensures that 'a' is unlocked */
static inline JsVar *jsvSkipOneNameAndUnLock(JsVar *a) {
JsVar *b = jsvSkipOneName(a);
jsvUnLock(a);
return b;
}
/** Given a JsVar meant to be an index to an array, convert it to
* the actual variable type we'll use to access the array. For example
* a["0"] is actually translated to a[0]
*/
JsVar *jsvAsArrayIndex(JsVar *index);
/** Same as jsvAsArrayIndex, but ensures that 'index' is unlocked */
static inline JsVar *jsvAsArrayIndexAndUnLock(JsVar *a) {
JsVar *b = jsvAsArrayIndex(a);
jsvUnLock(a);
return b;
}
/** Try and turn the supplied variable into a name. If not, make a new one. This locks again. */
JsVar *jsvAsName(JsVar *var);

View File

@ -83,7 +83,7 @@ JsVar *jswrap_json_parse_internal(JsLex *lex) {
JsVar *obj = jsvNewWithFlags(JSV_OBJECT); if (!obj) return 0;
jslGetNextToken(lex); // {
while (lex->tk == LEX_STR) {
JsVar *key = jslGetTokenValueAsVar(lex);
JsVar *key = jsvAsArrayIndexAndUnLock(jslGetTokenValueAsVar(lex));
jslGetNextToken(lex);
JsVar *value = 0;
if (!jslMatch(lex, ':') ||

View File

@ -144,12 +144,12 @@ JsVar *jswrap_object_keys(JsVar *obj) {
"return" : ["bool", "True if it exists, false if it doesn't"]
}*/
bool jswrap_object_hasOwnProperty(JsVar *parent, JsVar *name) {
char str[32];
jsvGetString(name, str, sizeof(str));
JsVar *propName = jsvAsArrayIndex(name);
bool contains = false;
if (jsvHasChildren(parent)) {
JsVar *foundVar = jsvFindChildFromString(parent, str, false);
JsVar *foundVar = jsvFindChildFromVar(parent, propName, false);
if (foundVar) {
contains = true;
jsvUnLock(foundVar);
@ -157,6 +157,9 @@ bool jswrap_object_hasOwnProperty(JsVar *parent, JsVar *name) {
}
if (!contains) { // search builtins
char str[32];
jsvGetString(propName, str, sizeof(str));
JsVar *foundVar = jswFindBuiltInFunction(parent, str);
if (foundVar) {
contains = true;
@ -164,6 +167,7 @@ bool jswrap_object_hasOwnProperty(JsVar *parent, JsVar *name) {
}
}
jsvUnLock(propName);
return contains;
}

View File

@ -0,0 +1,45 @@
// http://forum.espruino.com/conversations/1194/
var a={};
a["0"]=2;
a[5.3]=2;
var b={"0":3};
var r = [
a.hasOwnProperty(0),
a.hasOwnProperty(0.0),
a.hasOwnProperty("0"),
0 in a,
0.0 in a,
"0" in a,
b.hasOwnProperty(0),
b.hasOwnProperty(0.0),
b.hasOwnProperty("0"),
0 in b,
0.0 in b,
"0" in b,
// just being sure
!a.hasOwnProperty(1),
!a.hasOwnProperty(0.1),
!a.hasOwnProperty("1"),
!(1 in a),
!(0.1 in a),
!("1" in a),
!b.hasOwnProperty(1),
!b.hasOwnProperty(0.1),
!b.hasOwnProperty("1"),
!(1 in b),
!(0.1 in b),
!("1" in b),
// floats
5.3 in a,
"5.3" in a,
a.hasOwnProperty(5.3),
a.hasOwnProperty("5.3"),
!a.hasOwnProperty(5),
];
var pass = 0;
r.forEach(function(res) { if (res) pass++; } );
result = pass == r.length;