/* * When eval'ing code using the Duktape API (duk_eval() and friends), the * eval code is evaluated in non-strict mode by default. If the eval code * contains a "use strict" directive, then it is of course evaluated in * strict mode. * * This behavior is a change from Duktape 0.11.0 where the strictness of the * current context would be inherited into eval code. Because the Duktape * context is non-strict when no Duktape/C calls active and strict when a * Duktape/C call is active, eval() code strictness would also depend on * whether duk_eval() was called inside or outside of a Duktape/C activation. * This is quite confusing. One practical issue is that strict eval code * gets a fresh variable declaration environment and the following will * behave differently: * * var foo = 'bar'; * * In non-strict mode this establishes a 'foo' property in the global object. * In strict mode it declares a new 'foo' variable in a fresh, temporary * lexical environment and doesn't have an effect on the global object. * * The strictness behavior was changed in Duktape 0.12.0 so that duk_eval() * always compiles code in non-strict mode so that it's possible to eval * non-strict code inside a Duktape/C activation. This matches the behavior * of duk_compile() which also doesn't "inherit" strictness from the Duktape/C * context. Further, in Duktape 0.12.0 and onwards the Duktape/C context is * always considered strict to minimize confusion. */ /*=== *** test_1 (duk_safe_call) context is strict: 1 test_1 evalcode, typeof Math: object global.foo1=bar final top: 0 ==> rc=0, result='undefined' *** test_2 (duk_safe_call) context is strict: 1 context is strict: 1 test_2 evalcode, typeof Math: object global.foo2=bar final top: 0 ==> rc=0, result='undefined' ===*/ static duk_ret_t test_1(duk_context *ctx) { const char *str; /* Eval happens outside of a Duktape/C activation. The eval code was * executed in non-strict mode also in Duktape 0.11.0 and prior. */ printf("context is strict: %d\n", duk_is_strict_call(ctx)); duk_eval_string_noresult(ctx, "print('test_1 evalcode, typeof Math:', typeof Math); var foo1 = 'bar';"); duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "foo1"); str = duk_get_string(ctx, -1); printf("global.foo1=%s\n", str ? str : "NULL"); duk_pop_2(ctx); printf("final top: %ld\n", (long) duk_get_top(ctx)); return 0; } static duk_ret_t test_2_inner(duk_context *ctx) { /* Eval happens inside a Duktape/C activation, so we're currently in * in strict mode. In Duktape 0.11.0 and prior, the 'foo2' declaration * would go into a temporary lexical environment and would not be visible * in the global object. The code can still read (and write) properties * of the global object. */ printf("context is strict: %d\n", duk_is_strict_call(ctx)); duk_eval_string_noresult(ctx, "print('test_2 evalcode, typeof Math:', typeof Math); var foo2 = 'bar';"); return 0; } static duk_ret_t test_2(duk_context *ctx) { const char *str; printf("context is strict: %d\n", duk_is_strict_call(ctx)); duk_push_c_function(ctx, test_2_inner, 0); duk_call(ctx, 0); duk_pop(ctx); duk_push_global_object(ctx); duk_get_prop_string(ctx, -1, "foo2"); str = duk_get_string(ctx, -1); printf("global.foo2=%s\n", str ? str : "NULL"); duk_pop_2(ctx); printf("final top: %ld\n", (long) duk_get_top(ctx)); return 0; } void test(duk_context *ctx) { TEST_SAFE_CALL(test_1); TEST_SAFE_CALL(test_2); }