diff --git a/bench.ce b/bench.ce index 338cfdbd..d8dac60e 100644 --- a/bench.ce +++ b/bench.ce @@ -203,7 +203,7 @@ function calibrate_batch_size(bench_fn, is_batch) { // Find a batch size that takes at least MIN_SAMPLE_NS while (n < MAX_BATCH_SIZE) { // Ensure n is a valid number before calling - if (typeof n != 'number' || n < 1) { + if (!is_number(n) || n < 1) { n = 1 break } @@ -217,7 +217,7 @@ function calibrate_batch_size(bench_fn, is_batch) { // Double the batch size var new_n = n * 2 // Check if multiplication produced a valid number - if (typeof new_n != 'number' || new_n > MAX_BATCH_SIZE) { + if (!is_number(new_n) || new_n > MAX_BATCH_SIZE) { n = MAX_BATCH_SIZE break } @@ -225,12 +225,12 @@ function calibrate_batch_size(bench_fn, is_batch) { } // Adjust to target sample duration - if (dt > 0 && dt < TARGET_SAMPLE_NS && typeof n == 'number' && typeof dt == 'number') { + if (dt > 0 && dt < TARGET_SAMPLE_NS && is_number(n) && is_number(dt)) { var calc = n * TARGET_SAMPLE_NS / dt - if (typeof calc == 'number' && calc > 0) { + if (is_number(calc) && calc > 0) { var target_n = number.floor(calc) // Check if floor returned a valid number - if (typeof target_n == 'number' && target_n > 0) { + if (is_number(target_n) && target_n > 0) { if (target_n > MAX_BATCH_SIZE) target_n = MAX_BATCH_SIZE if (target_n < MIN_BATCH_SIZE) target_n = MIN_BATCH_SIZE n = target_n @@ -239,7 +239,7 @@ function calibrate_batch_size(bench_fn, is_batch) { } // Safety check - ensure we always return a valid batch size - if (typeof n != 'number' || n < 1) { + if (!is_number(n) || n < 1) { n = 1 } @@ -254,7 +254,7 @@ function run_single_bench(bench_fn, bench_name) { // 1. Object with { setup, run, teardown } - structured format // 2. Function that accepts (n) - batch format // 3. Function that accepts () - legacy format - var is_structured = typeof bench_fn == 'object' && bench_fn.run + var is_structured = is_object(bench_fn) && bench_fn.run var is_batch = false var batch_size = 1 var setup_fn = null @@ -285,7 +285,7 @@ function run_single_bench(bench_fn, bench_name) { batch_size = calibrate_batch_size(calibrate_fn, is_batch) // Safety check for structured benchmarks - if (typeof batch_size != 'number' || batch_size < 1) { + if (!is_number(batch_size) || batch_size < 1) { batch_size = 1 } } else { @@ -307,8 +307,9 @@ function run_single_bench(bench_fn, bench_name) { // Warmup phase for (var i = 0; i < WARMUP_BATCHES; i++) { // Ensure batch_size is valid before warmup - if (typeof batch_size != 'number' || batch_size < 1) { - log.console(`WARNING: batch_size became ${typeof batch_size} = ${batch_size}, resetting to 1`) + if (!is_number(batch_size) || batch_size < 1) { + var type_str = is_null(batch_size) ? 'null' : is_number(batch_size) ? 'number' : is_text(batch_size) ? 'text' : is_object(batch_size) ? 'object' : is_array(batch_size) ? 'array' : is_function(batch_size) ? 'function' : is_logical(batch_size) ? 'logical' : 'unknown' + log.console(`WARNING: batch_size became ${type_str} = ${batch_size}, resetting to 1`) batch_size = 1 } @@ -332,7 +333,7 @@ function run_single_bench(bench_fn, bench_name) { // Measurement phase - collect SAMPLES timing samples for (var i = 0; i < SAMPLES; i++) { // Double-check batch_size is valid (should never happen, but defensive) - if (typeof batch_size != 'number' || batch_size < 1) { + if (!is_number(batch_size) || batch_size < 1) { batch_size = 1 } @@ -439,11 +440,11 @@ function run_benchmarks(package_name, specific_bench) { bench_mod = shop.use(mod_path, use_pkg) var benches = [] - if (typeof bench_mod == 'function') { + if (is_function(bench_mod)) { benches.push({name: 'main', fn: bench_mod}) - } else if (typeof bench_mod == 'object') { + } else if (is_object(bench_mod)) { for (var k in bench_mod) { - if (typeof bench_mod[k] == 'function') { + if (is_function(bench_mod[k])) { benches.push({name: k, fn: bench_mod[k]}) } } diff --git a/cellfs.cm b/cellfs.cm index 9e2fb86d..3328481a 100644 --- a/cellfs.cm +++ b/cellfs.cm @@ -174,7 +174,7 @@ function mount(source, name) { mount_info.zip_blob = blob // keep blob alive } else { var zip = miniz.read(blob) - if (!zip || typeof zip.count != 'function') { + if (!is_object(zip) || !is_function(zip.count)) { throw new Error("Invalid archive file (not zip or qop): " + source) } diff --git a/config.ce b/config.ce index 591da507..9526e9cc 100644 --- a/config.ce +++ b/config.ce @@ -38,7 +38,7 @@ function parse_key(key) { function get_nested(obj, path) { var current = obj for (var segment of path) { - if (!current || typeof current != 'object') return null + if (is_null(current) || !is_object(current)) return null current = current[segment] } return current @@ -49,7 +49,7 @@ function set_nested(obj, path, value) { var current = obj for (var i = 0; i < path.length - 1; i++) { var segment = path[i] - if (!current[segment] || typeof current[segment] != 'object') { + if (is_null(current[segment]) || !is_object(current[segment])) { current[segment] = {} } current = current[segment] @@ -74,8 +74,8 @@ function parse_value(str) { // Format value for display function format_value(val) { - if (typeof val == 'string') return '"' + val + '"' - if (typeof val == 'number' && val >= 1000) { + if (is_text(val)) return '"' + val + '"' + if (is_number(val) && val >= 1000) { // Add underscores to large numbers return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '_') } diff --git a/internal/engine.cm b/internal/engine.cm index 38fec016..e9591c45 100644 --- a/internal/engine.cm +++ b/internal/engine.cm @@ -96,7 +96,7 @@ globalThis.isa = function(value, master) { if (master == null) return false // isa(value, function) - check if function.prototype is in chain - if (typeof master == 'function') { + if (is_function(master)) { // Special type checks if (master == stone) return is_stone(value) if (master == number) return is_number(value) @@ -119,7 +119,7 @@ globalThis.isa = function(value, master) { } // isa(object, master_object) - check prototype chain - if (typeof master == 'object') { + if (is_object(master)) { var proto = _getPrototypeOf(value) while (proto != null) { if (proto == master) return true @@ -543,7 +543,7 @@ function actor_send(actor, message) { if (!isa(actor, actor) && !isa(actor.replycc, actor)) throw new Error(`Must send to an actor object. Attempted send to ${actor}`) - if (typeof message != 'object') throw new Error('Must send an object record.') + if (!is_object(message)) throw new Error('Must send an object record.') // message to self if (actor[ACTORDATA].id == _cell.id) { @@ -611,10 +611,10 @@ var need_stop = false var replies = {} globalThis.send = function send(actor, message, reply) { - if (typeof actor != 'object') + if (!is_object(actor)) throw new Error(`Must send to an actor object. Provided: ${actor}`); - if (typeof message != 'object') + if (!is_object(message)) throw new Error('Message must be an object') var send = {type:"user", data: message} diff --git a/parseq.cm b/parseq.cm index 57488973..396222be 100644 --- a/parseq.cm +++ b/parseq.cm @@ -25,7 +25,7 @@ function make_reason (factory, excuse, evidence) { } function is_requestor (fn) { - return typeof fn == 'function' && (fn.length == 1 || fn.length == 2) + return is_function(fn) && (fn.length == 1 || fn.length == 2) } function check_requestors (list, factory) { @@ -34,13 +34,13 @@ function check_requestors (list, factory) { } function check_callback (cb, factory) { - if (typeof cb != 'function' || cb.length != 2) + if (!is_function(cb) || cb.length != 2) throw make_reason(factory, 'Not a callback.', cb) } function schedule (fn, seconds) { if (seconds == null || seconds <= 0) return fn() - if (typeof delay == 'function') return delay(fn, seconds) + if (is_function(delay)) return delay(fn, seconds) throw make_reason('schedule', '@.delay capability required for timeouts.') } @@ -54,7 +54,7 @@ function run (factory, requestors, initial, action, time_limit, throttle = 0) { function cancel (reason = make_reason(factory, 'Cancel.')) { if (timer_cancel) timer_cancel(), timer_cancel = null if (!cancel_list) return - cancel_list.forEach(c => { try { if (typeof c == 'function') c(reason) } catch (_) {} }) + cancel_list.forEach(c => { try { if (is_function(c)) c(reason) } catch (_) {} }) cancel_list = null } @@ -81,7 +81,7 @@ function run (factory, requestors, initial, action, time_limit, throttle = 0) { } if (time_limit != null) { - if (typeof time_limit != 'number' || time_limit < 0) + if (!is_number(time_limit) || time_limit < 0) throw make_reason(factory, 'Bad time limit.', time_limit) if (time_limit > 0) timer_cancel = schedule(() => cancel(make_reason(factory, 'Timeout.', time_limit)), time_limit) } @@ -96,7 +96,7 @@ function run (factory, requestors, initial, action, time_limit, throttle = 0) { function _normalize (collection, factory) { if (isa(collection)) return { names: null, list: collection } - if (collection && typeof collection == 'object') { + if (collection && is_object(collection)) { def names = array(collection) def list = names.map(k => collection[k]).filter(is_requestor) return { names, list } diff --git a/pronto.cm b/pronto.cm index a31c58ea..95b54c0d 100644 --- a/pronto.cm +++ b/pronto.cm @@ -10,7 +10,7 @@ function make_reason(factory, excuse, evidence) { } function is_requestor(fn) { - return typeof fn == 'function' && (fn.length == 1 || fn.length == 2) + return is_function(fn) && (fn.length == 1 || fn.length == 2) } function check_requestors(list, factory) { @@ -19,7 +19,7 @@ function check_requestors(list, factory) { } function check_callback(cb, factory) { - if (typeof cb != 'function' || cb.length != 2) + if (!is_function(cb) || cb.length != 2) throw make_reason(factory, 'Not a callback.', cb) } @@ -88,10 +88,10 @@ function parallel(requestor_array, throttle, need) { return function(callback, value) { callback([]) } if (need == null) need = length - if (typeof need != 'number' || need < 0 || need > length) + if (!is_number(need) || need < 0 || need > length) throw make_reason(factory, 'Bad need.', need) - if (throttle != null && (typeof throttle != 'number' || throttle < 1)) + if (throttle != null && (!is_number(throttle) || throttle < 1)) throw make_reason(factory, 'Bad throttle.', throttle) return function parallel_requestor(callback, value) { @@ -107,7 +107,7 @@ function parallel(requestor_array, throttle, need) { if (finished) return finished = true cancel_list.forEach(c => { - try { if (typeof c == 'function') c(reason) } catch (_) {} + try { if (is_function(c)) c(reason) } catch (_) {} }) } @@ -170,10 +170,10 @@ function race(requestor_array, throttle, need) { def length = requestor_array.length if (need == null) need = 1 - if (typeof need != 'number' || need < 1 || need > length) + if (!is_number(need) || need < 1 || need > length) throw make_reason(factory, 'Bad need.', need) - if (throttle != null && (typeof throttle != 'number' || throttle < 1)) + if (throttle != null && (!is_number(throttle) || throttle < 1)) throw make_reason(factory, 'Bad throttle.', throttle) return function race_requestor(callback, value) { @@ -189,7 +189,7 @@ function race(requestor_array, throttle, need) { if (finished) return finished = true cancel_list.forEach(c => { - try { if (typeof c == 'function') c(reason) } catch (_) {} + try { if (is_function(c)) c(reason) } catch (_) {} }) } @@ -304,7 +304,7 @@ function sequence(requestor_array) { // Converts a unary function into a requestor. function requestorize(unary) { def factory = 'requestorize' - if (typeof unary != 'function') + if (!is_function(unary)) throw make_reason(factory, 'Not a function.', unary) return function requestorized(callback, value) { @@ -322,7 +322,7 @@ function requestorize(unary) { // Converts a factory that takes arrays to one that takes objects. function objectify(factory_fn) { def factory = 'objectify' - if (typeof factory_fn != 'function') + if (!is_function(factory_fn)) throw make_reason(factory, 'Not a factory.', factory_fn) return function objectified_factory(object_of_requestors, ...rest) { diff --git a/qopconv.ce b/qopconv.ce index a0d04376..e4c6d6c2 100644 --- a/qopconv.ce +++ b/qopconv.ce @@ -111,7 +111,7 @@ function pack(sources, archive_path, read_dir) { log.console("Created " + archive_path) } -if (typeof arg == 'undefined' || arg.length < 1) { +if (!is_array(arg) || arg.length < 1) { print_usage() } else { if (arg[0] == "-l") { diff --git a/source/quickjs-atom.h b/source/quickjs-atom.h index 17ae7693..b0ebcdbb 100644 --- a/source/quickjs-atom.h +++ b/source/quickjs-atom.h @@ -38,7 +38,6 @@ DEF(def, "def") DEF(this, "this") DEF(delete, "delete") DEF(void, "void") -DEF(typeof, "typeof") DEF(new, "new") DEF(in, "in") DEF(instanceof, "instanceof") diff --git a/source/quickjs-opcode.h b/source/quickjs-opcode.h index 1bb4ff71..52aa3524 100644 --- a/source/quickjs-opcode.h +++ b/source/quickjs-opcode.h @@ -202,7 +202,6 @@ DEF( inc_loc, 2, 0, 0, loc8) DEF( add_loc, 2, 1, 0, loc8) DEF( not, 1, 1, 1, none) DEF( lnot, 1, 1, 1, none) -DEF( typeof, 1, 1, 1, none) DEF( delete, 1, 2, 1, none) DEF( delete_var, 5, 0, 1, atom) @@ -328,7 +327,6 @@ DEF( call2, 1, 1, 1, npopx) DEF( call3, 1, 1, 1, npopx) DEF( is_null, 1, 1, 1, none) -DEF( typeof_is_function, 1, 1, 1, none) #endif #undef DEF diff --git a/source/quickjs.c b/source/quickjs.c index 0b895136..ab3364c9 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -11696,48 +11696,6 @@ static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp) return 0; } -static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1) -{ - JSAtom atom; - uint32_t tag; - - tag = JS_VALUE_GET_NORM_TAG(op1); - switch(tag) { - case JS_TAG_INT: - case JS_TAG_FLOAT64: - atom = JS_ATOM_number; - break; - case JS_TAG_BOOL: - atom = JS_ATOM_boolean; - break; - case JS_TAG_STRING: - case JS_TAG_STRING_ROPE: - atom = JS_ATOM_string; - break; - case JS_TAG_OBJECT: - { - if (JS_IsFunction(ctx, op1)) - atom = JS_ATOM_function; - else - goto obj_type; - } - break; - case JS_TAG_NULL: - atom = JS_ATOM_null; - break; - obj_type: - atom = JS_ATOM_object; - break; - case JS_TAG_SYMBOL: - atom = JS_ATOM_symbol; - break; - default: - atom = JS_ATOM_unknown; - break; - } - return atom; -} - static __exception int js_operator_delete(JSContext *ctx, JSValue *sp) { JSValue op1, op2; @@ -15553,17 +15511,6 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj, goto exception; sp--; BREAK; - CASE(OP_typeof): - { - JSValue op1; - JSAtom atom; - - op1 = sp[-1]; - atom = js_operator_typeof(ctx, op1); - JS_FreeValue(ctx, op1); - sp[-1] = JS_AtomToString(ctx, atom); - } - BREAK; CASE(OP_delete): sf->cur_pc = pc; if (js_operator_delete(ctx, sp)) @@ -15622,16 +15569,6 @@ static JSValue JS_CallInternal_OLD(JSContext *caller_ctx, JSValueConst func_obj, } else { goto free_and_set_false; } -#if SHORT_OPCODES - CASE(OP_typeof_is_function): - if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) { - goto free_and_set_true; - } else { - goto free_and_set_false; - } - free_and_set_true: - JS_FreeValue(ctx, sp[-1]); -#endif set_true: sp[-1] = JS_TRUE; BREAK; @@ -15915,7 +15852,6 @@ enum { TOK_THIS, TOK_DELETE, TOK_VOID, - TOK_TYPEOF, TOK_NEW, TOK_IN, TOK_INSTANCEOF, @@ -20459,23 +20395,6 @@ static __exception int js_parse_unary(JSParseState *s, int parse_flags) FALSE); } break; - case TOK_TYPEOF: - { - JSFunctionDef *fd; - if (next_token(s)) - return -1; - if (js_parse_unary(s, PF_POW_FORBIDDEN)) - return -1; - /* reference access should not return an exception, so we - patch the get_var */ - fd = s->cur_func; - if (get_prev_opcode(fd) == OP_scope_get_var) { - fd->byte_code.buf[fd->last_opcode_pos] = OP_scope_get_var_undef; - } - emit_op(s, OP_typeof); - parse_flags = 0; - } - break; case TOK_DELETE: if (js_parse_delete(s)) return -1; @@ -25130,48 +25049,6 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) } goto no_change; -#if SHORT_OPCODES - case OP_typeof: - if (OPTIMIZE) { - /* simplify typeof tests */ - if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) { - if (cc.line_num >= 0) line_num = cc.line_num; - int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq; - int op2 = -1; - switch (cc.atom) { - case JS_ATOM_null: - op2 = OP_is_null; - break; - case JS_ATOM_function: - op2 = OP_typeof_is_function; - break; - } - if (op2 >= 0) { - /* transform typeof(s) == "" into is_ */ - if (op1 == OP_strict_eq) { - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, op2); - JS_FreeAtom(ctx, cc.atom); - pos_next = cc.pos; - break; - } - if (op1 == OP_strict_neq && code_match(&cc, cc.pos, OP_if_false, -1)) { - /* transform typeof(s) != "" if_false into is_ if_true */ - if (cc.line_num >= 0) line_num = cc.line_num; - add_pc2line_info(s, bc_out.size, line_num); - dbuf_putc(&bc_out, op2); - JS_FreeAtom(ctx, cc.atom); - pos_next = cc.pos; - label = cc.label; - op = OP_if_true; - goto has_label; - } - } - } - } - goto no_change; -#endif - default: no_change: add_pc2line_info(s, bc_out.size, line_num); @@ -25873,7 +25750,6 @@ static __exception int js_parse_directives(JSParseState *s) case TOK_VAR: case TOK_THIS: case TOK_DELETE: - case TOK_TYPEOF: case TOK_NEW: case TOK_DO: case TOK_WHILE: diff --git a/test.ce b/test.ce index 8b3f4415..99b2fbec 100644 --- a/test.ce +++ b/test.ce @@ -287,11 +287,11 @@ function run_tests(package_name, specific_test) { test_mod = shop.use(mod_path, use_pkg) var tests = [] - if (typeof test_mod == 'function') { + if (is_function(test_mod)) { tests.push({name: 'main', fn: test_mod}) - } else if (typeof test_mod == 'object') { + } else if (is_object(test_mod)) { for (var k in test_mod) { - if (typeof test_mod[k] == 'function') { + if (is_function(test_mod[k])) { tests.push({name: k, fn: test_mod[k]}) } } @@ -312,9 +312,9 @@ function run_tests(package_name, specific_test) { try { var ret = t.fn() - if (typeof ret == 'string') { + if (is_text(ret)) { throw new Error(ret) - } else if (ret && (typeof ret.message == 'string' || ret instanceof Error)) { + } else if (ret && (is_text(ret.message) || ret instanceof Error)) { throw ret } @@ -330,7 +330,7 @@ function run_tests(package_name, specific_test) { } if (e.name) test_entry.error.name = e.name - if (typeof e == 'object' && e.message) { + if (is_object(e) && e.message) { test_entry.error.message = e.message } diff --git a/tests/nota.cm b/tests/nota.cm index 54d8092c..51da14a0 100644 --- a/tests/nota.cm +++ b/tests/nota.cm @@ -20,7 +20,7 @@ function deepCompare(expected, actual, path) { path = path || '' if (expected == actual) return { passed: true, messages: [] }; - if (typeof expected == 'number' && typeof actual == 'number') { + if (is_number(expected) && is_number(actual)) { if (isNaN(expected) && isNaN(actual)) return { passed: true, messages: [] }; @@ -160,13 +160,13 @@ var testCases = [ { name: 'empty_key_value', input: { "": "" } }, { name: 'small_float', input: 1e-10 }, { name: 'replacer_multiply', input: { a: 1, b: 2 }, - replacer: (key, value) => typeof value == 'number' ? value * 2 : value, + replacer: (key, value) => is_number(value) ? value * 2 : value, expected: { a: 2, b: 4 } }, { name: 'replacer_string_append', input: { x: "test", y: 5 }, replacer: (key, value) => key == 'x' ? value + "!" : value, expected: { x: "test!", y: 5 } }, { name: 'reviver_multiply', input: { a: 1, b: 2 }, - reviver: (key, value) => typeof value == 'number' ? value * 3 : value, + reviver: (key, value) => is_number(value) ? value * 3 : value, expected: { a: 3, b: 6 } }, { name: 'reviver_increment', input: { x: "test", y: 10 }, reviver: (key, value) => key == 'y' ? value + 1 : value, diff --git a/tests/suite.cm b/tests/suite.cm index af3fe2f9..124357f2 100644 --- a/tests/suite.cm +++ b/tests/suite.cm @@ -924,32 +924,93 @@ return { }, // ============================================================================ - // TYPEOF AND TYPE CHECKING + // TYPE CHECKING WITH is_* FUNCTIONS // ============================================================================ - test_typeof_number: function() { - if (typeof 42 != "number") throw "typeof number failed" - if (typeof 3.14 != "number") throw "typeof float failed" - if (typeof -5 != "number") throw "typeof negative failed" + test_is_number: function() { + if (!is_number(42)) throw "is_number 42 failed" + if (!is_number(3.14)) throw "is_number float failed" + if (!is_number(-5)) throw "is_number negative failed" + if (is_number("42")) throw "is_number string should be false" + if (is_number(true)) throw "is_number boolean should be false" + if (is_number(null)) throw "is_number null should be false" + if (is_number({})) throw "is_number object should be false" + if (is_number([])) throw "is_number array should be false" }, - test_typeof_string: function() { - if (typeof "hello" != "string") throw "typeof string failed" - if (typeof "" != "string") throw "typeof empty string failed" + test_is_text: function() { + if (!is_text("hello")) throw "is_text string failed" + if (!is_text("")) throw "is_text empty string failed" + if (is_text(42)) throw "is_text number should be false" + if (is_text(true)) throw "is_text boolean should be false" + if (is_text(null)) throw "is_text null should be false" + if (is_text({})) throw "is_text object should be false" + if (is_text([])) throw "is_text array should be false" }, - test_typeof_boolean: function() { - if (typeof true != "boolean") throw "typeof true failed" - if (typeof false != "boolean") throw "typeof false failed" + test_is_logical: function() { + if (!is_logical(true)) throw "is_logical true failed" + if (!is_logical(false)) throw "is_logical false failed" + if (is_logical(1)) throw "is_logical number should be false" + if (is_logical("true")) throw "is_logical string should be false" + if (is_logical(null)) throw "is_logical null should be false" + if (is_logical({})) throw "is_logical object should be false" + if (is_logical([])) throw "is_logical array should be false" }, - test_typeof_object: function() { - if (typeof {} != "object") throw "typeof object failed" - if (typeof [] != "object") throw "typeof array failed" + test_is_object: function() { + if (!is_object({})) throw "is_object empty object failed" + if (!is_object({a: 1})) throw "is_object object failed" + if (is_object([])) throw "is_object array should be false" + if (is_object(null)) throw "is_object null should be false" + if (is_object(42)) throw "is_object number should be false" + if (is_object("hello")) throw "is_object string should be false" + if (is_object(true)) throw "is_object boolean should be false" }, - test_typeof_function: function() { - if (typeof function(){} != "function") throw "typeof function failed" + test_is_array: function() { + if (!is_array([])) throw "is_array empty array failed" + if (!is_array([1, 2, 3])) throw "is_array array failed" + if (is_array({})) throw "is_array object should be false" + if (is_array(null)) throw "is_array null should be false" + if (is_array(42)) throw "is_array number should be false" + if (is_array("hello")) throw "is_array string should be false" + if (is_array(true)) throw "is_array boolean should be false" + }, + + test_is_function: function() { + if (!is_function(function(){})) throw "is_function function failed" + var fn = function(x) { return x * 2 } + if (!is_function(fn)) throw "is_function named function failed" + if (is_function({})) throw "is_function object should be false" + if (is_function([])) throw "is_function array should be false" + if (is_function(null)) throw "is_function null should be false" + if (is_function(42)) throw "is_function number should be false" + if (is_function("hello")) throw "is_function string should be false" + if (is_function(true)) throw "is_function boolean should be false" + }, + + test_is_null: function() { + if (!is_null(null)) throw "is_null null failed" + if (is_null(0)) throw "is_null zero should be false" + if (is_null(false)) throw "is_null false should be false" + if (is_null("")) throw "is_null empty string should be false" + if (is_null({})) throw "is_null object should be false" + if (is_null([])) throw "is_null array should be false" + var x + if (!is_null(x)) throw "is_null undefined variable should be true" + }, + + test_is_blob: function() { + // Note: blob testing would require actual blob values + // For now, just test that other types return false + if (is_blob(null)) throw "is_blob null should be false" + if (is_blob(42)) throw "is_blob number should be false" + if (is_blob("hello")) throw "is_blob string should be false" + if (is_blob(true)) throw "is_blob boolean should be false" + if (is_blob({})) throw "is_blob object should be false" + if (is_blob([])) throw "is_blob array should be false" + if (is_blob(function(){})) throw "is_blob function should be false" }, // ============================================================================ diff --git a/tests/toml.cm b/tests/toml.cm index 00ccd22f..a40b1001 100644 --- a/tests/toml.cm +++ b/tests/toml.cm @@ -2,10 +2,10 @@ var toml = use('toml') function deep_equal(a, b) { if (a == b) return true - if (a == null || b == null) return false - if (typeof a != typeof b) return false + if (is_null(a) || is_null(b)) return false + if ((is_number(a) && !is_number(b)) || (is_text(a) && !is_text(b)) || (is_object(a) && !is_object(b)) || (is_array(a) && !is_array(b)) || (is_blob(a) && !is_blob(b)) || (is_function(a) && !is_function(b)) || (is_logical(a) && !is_logical(b))) return false - if (typeof a == 'object') { + if (is_object(a)) { var keys_a = array(a) var keys_b = array(b) if (keys_a.length != keys_b.length) return false diff --git a/tests/wota.cm b/tests/wota.cm index ae73a98a..62b1893d 100644 --- a/tests/wota.cm +++ b/tests/wota.cm @@ -12,7 +12,7 @@ function deep_compare(expected, actual, path) { path = path || '' if (expected == actual) return { passed: true, messages: [] } - if (typeof expected == 'number' && typeof actual == 'number') { + if (is_number(expected) && is_number(actual)) { if (isNaN(expected) && isNaN(actual)) return { passed: true, messages: [] } var diff = number.abs(expected - actual) if (diff <= EPSILON) return { passed: true, messages: [] } diff --git a/time.cm b/time.cm index a813018d..bb3a811f 100644 --- a/time.cm +++ b/time.cm @@ -60,7 +60,7 @@ function time_record(num = now(), zone = computer_zone(), dst = computer_dst()) { - if (typeof num == "object") return num; + if (is_object(num)) return num; var monthdays = time.monthdays.slice(); var rec = { @@ -111,9 +111,8 @@ function time_record(num = now(), function time_number(rec = now()) { - if (typeof rec == "number") return rec; + if (is_number(rec)) return rec; - log.console(typeof rec) log.console(rec) log.console(rec.minute) @@ -157,7 +156,7 @@ function time_text(num = now(), zone = computer_zone(), dst = computer_dst()) { - var rec = (typeof num == "number") ? time_record(num, zone, dst) : num; + var rec = is_number(num) ? time_record(num, zone, dst) : num; zone = rec.zone; dst = rec.dst; diff --git a/toml.cm b/toml.cm index 14a44ebc..4b1469d1 100644 --- a/toml.cm +++ b/toml.cm @@ -2,7 +2,7 @@ // Supports basic TOML features needed for the module system function parse_toml(text) { - if (typeof text != 'string') return null + if (!is_text(text)) return null var lines = text.split('\n') var result = {} var current_section = result @@ -141,11 +141,11 @@ function encode_toml(obj) { var result = [] function encode_value(value) { - if (typeof value == 'string') { + if (is_text(value)) { return '"' + value.replace(/"/g, '\\"') + '"' - } else if (typeof value == 'boolean') { + } else if (is_logical(value)) { return value ? 'true' : 'false' - } else if (typeof value == 'number') { + } else if (is_number(value)) { return text(value) } else if (isa(value, array)) { var items = []