mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
Fix issues with (and hasOwnProperty)
This commit is contained in:
parent
0b44b41e3d
commit
df71b0c049
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
25
src/jsvar.c
25
src/jsvar.c
@ -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;
|
||||
|
||||
19
src/jsvar.h
19
src/jsvar.h
@ -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);
|
||||
|
||||
|
||||
@ -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, ':') ||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
45
tests/test_object_hasOwnProperty.js
Normal file
45
tests/test_object_hasOwnProperty.js
Normal 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;
|
||||
Loading…
x
Reference in New Issue
Block a user