ref: 2d28162c2fd40588cde6b2fd62517fe25e7baffb
parent: 3585abad419a5eb53ebb58d6c37bbeeff44ce65e
author: Tor Andersson <tor@ccxvii.net>
date: Mon Feb 24 07:03:59 EST 2014
typeof X when X in not declared should return undefined rather than throw.
--- a/jscompile.c
+++ b/jscompile.c
@@ -199,6 +199,15 @@
/* Expressions */
+static void ctypeof(JF, js_Ast *exp)
+{
+ if (exp->type == EXP_IDENTIFIER)
+ emitlocal(J, F, OP_GETLOCAL, OP_HASVAR, exp->string);
+ else
+ cexp(J, F, exp);
+ emit(J, F, OP_TYPEOF);
+}
+
static void cunary(JF, js_Ast *exp, int opcode)
{
cexp(J, F, exp->a);
@@ -525,7 +534,7 @@
emit(J, F, OP_UNDEF);
break;
- case EXP_TYPEOF: cunary(J, F, exp, OP_TYPEOF); break;
+ case EXP_TYPEOF: ctypeof(J, F, exp->a); break;
case EXP_POS: cunary(J, F, exp, OP_POS); break;
case EXP_NEG: cunary(J, F, exp, OP_NEG); break;
case EXP_BITNOT: cunary(J, F, exp, OP_BITNOT); break;
--- a/jscompile.h
+++ b/jscompile.h
@@ -42,6 +42,7 @@
OP_INITVAR, /* <value> -S- */
OP_DEFVAR, /* -S- */
+ OP_HASVAR, /* -S- ( <value> | undefined ) */
OP_GETVAR, /* -S- <value> */
OP_SETVAR, /* <value> -S- <value> */
OP_DELVAR, /* -S- <success> */
--- a/jsrun.c
+++ b/jsrun.c
@@ -702,7 +702,7 @@
jsR_defproperty(J, J->E->variables, name, JS_DONTENUM | JS_DONTCONF, NULL, NULL, NULL);
}
-static void js_getvar(js_State *J, const char *name)
+static int js_hasvar(js_State *J, const char *name)
{
js_Environment *E = J->E;
do {
@@ -715,11 +715,11 @@
} else {
js_pushvalue(J, ref->value);
}
- return;
+ return 1;
}
E = E->outer;
} while (E);
- js_referenceerror(J, "%s is not defined", name);
+ return 0;
}
static void js_setvar(js_State *J, const char *name)
@@ -1075,7 +1075,14 @@
break;
case OP_GETVAR:
- js_getvar(J, ST[*pc++]);
+ str = ST[*pc++];
+ if (!js_hasvar(J, str))
+ js_referenceerror(J, "%s is not defined", str);
+ break;
+
+ case OP_HASVAR:
+ if (!js_hasvar(J, ST[*pc++]))
+ js_pushundefined(J);
break;
case OP_SETVAR:
--- a/opnames.h
+++ b/opnames.h
@@ -30,6 +30,7 @@
"dellocal",
"initvar",
"defvar",
+"hasvar",
"getvar",
"setvar",
"delvar",