static void parseFloat_global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSNode *result_return, JSNode *args) { char *cp, *end; result_return->type = JS_FLOAT; if (args->u.vinteger != 1) { sprintf_P (vm->error, b_core_string_1); js_vm_error (vm); } if (args[1].type == JS_STRING) cp = js_string_to_c_string (vm, &args[1]); else { JSNode input; /* Convert the input to string. */ js_vm_to_string (vm, &args[1], &input); cp = js_string_to_c_string (vm, &input); } result_return->u.vfloat = strtod (cp, &end); js_free (cp); if (cp == end) /* Couldn't parse, return NaN. */ result_return->type = JS_NAN; }
static int sort_default_cmp_func (const void *aptr, const void *bptr, void *context) { JSVirtualMachine *vm = context; const JSNode *a = aptr; const JSNode *b = bptr; JSNode astr, bstr; if (a->type == JS_UNDEFINED) return 1; if (b->type == JS_UNDEFINED) return -1; js_vm_to_string (vm, a, &astr); js_vm_to_string (vm, b, &bstr); return js_compare_strings (&astr, &bstr); }
static void unescape_global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSNode *result_return, JSNode *args) { unsigned char *dp; unsigned int n, i; JSNode *source; JSNode source_n; if (args->u.vinteger != 1) { sprintf_P (vm->error, b_core_string_3); js_vm_error (vm); } if (args[1].type == JS_STRING) source = &args[1]; else { js_vm_to_string (vm, &args[1], &source_n); source = &source_n; } /* * Allocate the result string, Let's guess that we need at least * <source->u.vstring->len> bytes of data. */ n = source->u.vstring->len; dp = source->u.vstring->data; js_vm_make_string (vm, result_return, NULL, n); result_return->u.vstring->len = 0; /* * Scan for escapes requiring characters. */ for (i = 0; i < n;) { unsigned int c = dp[i]; if (c != '%') i += 1; else if (i <= n - 6 && dp[i + 1] == 'u' && scanhexdigits (dp + i + 2, 4, &c)) i += 6; else if (i <= n - 3 && scanhexdigits (dp + i + 1, 2, &c)) i += 3; else { c = dp[i]; i += 1; } EMIT_TO_RESULT (c); } }
static void parseInt_global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSNode *result_return, JSNode *args) { JSInt32 base = 0; char *cp, *end; result_return->type = JS_INTEGER; if (args->u.vinteger != 1 && args->u.vinteger != 2) { sprintf_P (vm->error, b_core_string_0); js_vm_error (vm); } if (args[1].type == JS_STRING) cp = js_string_to_c_string (vm, &args[1]); else { JSNode input; /* Convert the input to string. */ js_vm_to_string (vm, &args[1], &input); cp = js_string_to_c_string (vm, &input); } if (args->u.vinteger == 2) { if (args[2].type == JS_INTEGER) base = args[2].u.vinteger; else base = js_vm_to_int32 (vm, &args[2]); } result_return->u.vinteger = strtol (cp, &end, base); js_free (cp); if (cp == end) result_return->type = JS_NAN; }
static void escape_global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSNode *result_return, JSNode *args) { unsigned char *dp; unsigned int n, i; JSNode *source; JSNode source_n; static const prog_char charset[] PROGMEM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@*_+-./"; if (args->u.vinteger != 1) { sprintf (vm->error, b_core_string_2); js_vm_error (vm); } if (args[1].type == JS_STRING) source = &args[1]; else { /* Convert the argument to string. */ js_vm_to_string (vm, &args[1], &source_n); source = &source_n; } /* * Allocate the result string, Let's guess that we need at least * <source->u.vstring->len> bytes of data. */ n = source->u.vstring->len; dp = source->u.vstring->data; js_vm_make_string (vm, result_return, NULL, n); result_return->u.vstring->len = 0; /* * Scan for characters requiring escapes. */ for (i = 0; i < n; i += 1) { unsigned int c = dp[i]; if (strchr_P (charset, c)) EMIT_TO_RESULT (c); else if (c > 0xFF) { unsigned char buf[6]; sprintf (buf, "%04x", c); EMIT_TO_RESULT ('%'); EMIT_TO_RESULT ('u'); EMIT_TO_RESULT (buf[0]); EMIT_TO_RESULT (buf[1]); EMIT_TO_RESULT (buf[2]); EMIT_TO_RESULT (buf[3]); } else { unsigned char buf[4]; sprintf (buf, "%02x", c); EMIT_TO_RESULT ('%'); EMIT_TO_RESULT (buf[0]); EMIT_TO_RESULT (buf[1]); } } }
/* Method proc. */ static int method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSSymbol method, JSNode *result_return, JSNode *args) { ArrayCtx *ctx = builtin_info->obj_context; JSNode *n = instance_context; int i; /* Set the default result type. */ result_return->type = JS_UNDEFINED; if (method == ctx->s_concat) { if (args->u.vinteger != 1) goto argument_error; if (args[1].type != JS_ARRAY) goto argument_type_error; js_vm_make_array (vm, result_return, n->u.varray->length + args[1].u.varray->length); memcpy (result_return->u.varray->data, n->u.varray->data, n->u.varray->length * sizeof (JSNode)); memcpy (&result_return->u.varray->data[n->u.varray->length], args[1].u.varray->data, args[1].u.varray->length * sizeof (JSNode)); } /* ********************************************************************** */ else if (method == ctx->s_join || method == vm->syms.s_toString) { char *glue = NULL; if (method == vm->syms.s_toString) { if (args->u.vinteger != 0) goto argument_error; } else { if (args->u.vinteger == 0) ; else if (args->u.vinteger == 1) { JSNode glue_result; js_vm_to_string (vm, &args[1], &glue_result); glue = js_string_to_c_string (vm, &glue_result); } else goto argument_error; } /* Ok, ready to run. */ if (n->u.varray->length == 0) js_vm_make_static_string (vm, result_return, "", 0); else { int len; int glue_len = glue ? strlen (glue) : 1; /* Estimate the result length. */ len = (n->u.varray->length * 5 + (n->u.varray->length - 1) * glue_len); js_vm_make_string (vm, result_return, NULL, len); result_return->u.vstring->len = 0; /* Do the join. */ for (i = 0; i < n->u.varray->length; i++) { JSNode sitem; int delta; js_vm_to_string (vm, &n->u.varray->data[i], &sitem); delta = sitem.u.vstring->len; if (i + 1 < n->u.varray->length) delta += glue_len; result_return->u.vstring->data = js_vm_realloc (vm, result_return->u.vstring->data, result_return->u.vstring->len + delta); memcpy (result_return->u.vstring->data + result_return->u.vstring->len, sitem.u.vstring->data, sitem.u.vstring->len); result_return->u.vstring->len += sitem.u.vstring->len; if (i + 1 < n->u.varray->length) { if (glue) { memcpy (result_return->u.vstring->data + result_return->u.vstring->len, glue, glue_len); result_return->u.vstring->len += glue_len; } else result_return->u.vstring->data [result_return->u.vstring->len++] = ','; } } } if (glue) js_free (glue); } /* ********************************************************************** */ else if (method == ctx->s_pop) { if (args->u.vinteger != 0) goto argument_error; if (n->u.varray->length == 0) result_return->type = JS_UNDEFINED; else { JS_COPY (result_return, &n->u.varray->data[n->u.varray->length - 1]); n->u.varray->length--; } } /* ********************************************************************** */ else if (method == ctx->s_push) { int old_len; if (args->u.vinteger == 0) goto argument_error; old_len = n->u.varray->length; js_vm_expand_array (vm, n, n->u.varray->length + args->u.vinteger); for (i = 0; i < args->u.vinteger; i++) JS_COPY (&n->u.varray->data[old_len + i], &args[i + 1]); JS_COPY (result_return, &args[i]); } /* ********************************************************************** */ else if (method == ctx->s_reverse) { if (args->u.vinteger != 0) goto argument_error; for (i = 0; i < n->u.varray->length / 2; i++) { JSNode tmp; JS_COPY (&tmp, &n->u.varray->data[i]); JS_COPY (&n->u.varray->data[i], &n->u.varray->data[n->u.varray->length - i - 1]); JS_COPY (&n->u.varray->data[n->u.varray->length - i - 1], &tmp); } } /* ********************************************************************** */ else if (method == ctx->s_shift) { if (args->u.vinteger != 0) goto argument_error; if (n->u.varray->length == 0) result_return->type = JS_UNDEFINED; else { JS_COPY (result_return, &n->u.varray->data[0]); memmove (&n->u.varray->data[0], &n->u.varray->data[1], (n->u.varray->length - 1) * sizeof (JSNode)); n->u.varray->length--; } } /* ********************************************************************** */ else if (method == ctx->s_slice) { int start, end; if (args->u.vinteger < 1 || args->u.vinteger > 2) goto argument_error; if (args[1].type != JS_INTEGER) goto argument_type_error; start = args[1].u.vinteger; if (args->u.vinteger == 2) { if (args[2].type != JS_INTEGER) goto argument_type_error; end = args[2].u.vinteger; } else end = n->u.varray->length; if (end < 0) end += n->u.varray->length; if (end < 0) end = start; js_vm_make_array (vm, result_return, end - start); /* Copy items. */ for (i = 0; i < end - start; i++) JS_COPY (&result_return->u.varray->data[i], &n->u.varray->data[start + i]); } /* ********************************************************************** */ else if (method == ctx->s_splice) { unsigned int new_length; unsigned int old_length; int delta; if (args->u.vinteger < 2) goto argument_error; if (args[1].type != JS_INTEGER || args[2].type != JS_INTEGER) goto argument_type_error; if (args[2].u.vinteger == 0 && args->u.vinteger == 2) /* No deletions: must specify at least one item to insert. */ goto argument_error; old_length = new_length = n->u.varray->length; if (args[1].u.vinteger < new_length) { if (args[2].u.vinteger > new_length - args[1].u.vinteger) { args[2].u.vinteger = new_length - args[1].u.vinteger; new_length = args[1].u.vinteger; } else new_length -= args[2].u.vinteger; } else { new_length = args[1].u.vinteger; args[2].u.vinteger = 0; } new_length += args->u.vinteger - 2; if (new_length > n->u.varray->length) js_vm_expand_array (vm, n, new_length); else /* Cut the array. */ n->u.varray->length = new_length; /* Do the stuffs we must do. */ /* Create the result array. */ if (args[2].u.vinteger == 0) result_return->type = JS_UNDEFINED; else { js_vm_make_array (vm, result_return, args[2].u.vinteger); for (i = 0; i < args[2].u.vinteger; i++) JS_COPY (&result_return->u.varray->data[i], &n->u.varray->data[args[1].u.vinteger + i]); } /* Delete and move. */ delta = args->u.vinteger - 2 - args[2].u.vinteger; memmove (&n->u.varray->data[args[1].u.vinteger + args[2].u.vinteger + delta], &n->u.varray->data[args[1].u.vinteger + args[2].u.vinteger], (old_length - (args[1].u.vinteger + args[2].u.vinteger)) * sizeof (JSNode)); /* Insert. */ for (i = 0; i < args->u.vinteger - 2; i++) JS_COPY (&n->u.varray->data[args[1].u.vinteger + i], &args[i + 3]); } /* ********************************************************************** */ else if (method == ctx->s_sort) { MergesortCompFunc func; ArraySortCtx array_sort_ctx; void *func_ctx = NULL; /* Initialized to keep compiler quiet. */ if (args->u.vinteger == 0) { func = sort_default_cmp_func; func_ctx = vm; } else if (args->u.vinteger == 1) { if (args[1].type != JS_FUNC && args[1].type != JS_BUILTIN) goto argument_type_error; func = sort_js_cmp_func; /* Init context. */ array_sort_ctx.vm = vm; array_sort_ctx.func = &args[1]; /* Init the argc part of the argument vector here. */ array_sort_ctx.argv[0].type = JS_INTEGER; array_sort_ctx.argv[0].u.vinteger = 3; func_ctx = &array_sort_ctx; } else goto argument_error; mergesort_r (n->u.varray->data, n->u.varray->length, sizeof (JSNode), func, func_ctx); } /* ********************************************************************** */ else if (method == ctx->s_unshift) { int old_len; if (args->u.vinteger == 0) goto argument_error; old_len = n->u.varray->length; js_vm_expand_array (vm, n, n->u.varray->length + args->u.vinteger); memmove (&n->u.varray->data[args->u.vinteger], n->u.varray->data, old_len * sizeof (JSNode)); for (i = 0; i < args->u.vinteger; i++) JS_COPY (&n->u.varray->data[i], &args[args->u.vinteger - i]); result_return->type = JS_INTEGER; result_return->u.vinteger = n->u.varray->length; } /* ********************************************************************** */ else return JS_PROPERTY_UNKNOWN; return JS_PROPERTY_FOUND; /* * Error handling. */ argument_error: sprintf (vm->error, "Array.%s(): illegal amount of arguments", js_vm_symname (vm, method)); js_vm_error (vm); argument_type_error: sprintf (vm->error, "Array.%s(): illegal argument", js_vm_symname (vm, method)); js_vm_error (vm); /* NOTREACHED */ return 0; }