mirror of
https://github.com/google/pebble.git
synced 2025-06-07 02:33:12 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
260
src/fw/applib/rockyjs/api/rocky_api_util.c
Normal file
260
src/fw/applib/rockyjs/api/rocky_api_util.c
Normal file
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "rocky_api_util.h"
|
||||
#include "rocky_api_errors.h"
|
||||
|
||||
#include "applib/app_logging.h"
|
||||
#include "kernel/pbl_malloc.h"
|
||||
#include "system/passert.h"
|
||||
#include "util/size.h"
|
||||
#include "util/trig.h"
|
||||
#include "vendor/jerryscript/jerry-libm/include/math.h" // easiest way to get M_PI
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define ROCKY_SINGLETON "_rocky"
|
||||
|
||||
// [MT] including <math.h> causes the jerry-libm header to get included again :(
|
||||
extern double round(double d);
|
||||
|
||||
uintptr_t rocky_util_uint_from_value(const jerry_value_t value) {
|
||||
uintptr_t rv = 0;
|
||||
if (jerry_value_is_number(value)) {
|
||||
rv = jerry_get_number_value(value);
|
||||
} else if (jerry_value_is_string(value)) {
|
||||
uint32_t sz = jerry_get_utf8_string_size(value);
|
||||
char buf[sz + 1];
|
||||
memset(buf, 0, sz + 1);
|
||||
jerry_string_to_utf8_char_buffer(value, (jerry_char_t *)buf, sz);
|
||||
rv = strtoul(buf, NULL, 0);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int32_t jerry_get_int32_value(jerry_value_t value) {
|
||||
return (int32_t)(round(jerry_get_number_value(value)));
|
||||
}
|
||||
|
||||
int32_t jerry_get_angle_value(jerry_value_t value) {
|
||||
return (int32_t)
|
||||
(jerry_get_number_value(value) * TRIG_MAX_ANGLE / (2 * M_PI)) + TRIG_MAX_ANGLE / 4;
|
||||
}
|
||||
|
||||
char *rocky_string_alloc_and_copy(const jerry_value_t string) {
|
||||
char *out_str = NULL;
|
||||
|
||||
if (jerry_value_is_string(string)) {
|
||||
uint32_t sz = jerry_get_utf8_string_size(string);
|
||||
out_str = task_zalloc_check(sz + 1);
|
||||
jerry_string_to_utf8_char_buffer(string, (jerry_char_t *)out_str, sz);
|
||||
}
|
||||
return out_str;
|
||||
}
|
||||
|
||||
void rocky_log_exception(const char *message, jerry_value_t exception) {
|
||||
// using APP_LOG in this function so that 3rd-parties will know what went wrong with their JS
|
||||
APP_LOG(APP_LOG_LEVEL_ERROR, "Exception while %s", message);
|
||||
|
||||
jerry_char_t buffer[100] = {};
|
||||
const ssize_t written = jerry_object_to_string_to_utf8_char_buffer(exception, buffer,
|
||||
sizeof(buffer) - 1);
|
||||
if (written > 0) {
|
||||
APP_LOG(APP_LOG_LEVEL_ERROR, "%s", buffer);
|
||||
} else {
|
||||
APP_LOG(APP_LOG_LEVEL_ERROR, "no further info.");
|
||||
}
|
||||
}
|
||||
|
||||
void jerry_set_object_field(jerry_value_t object, const char *field, jerry_value_t value) {
|
||||
JS_VAR prop_name = jerry_create_string((jerry_char_t *)field);
|
||||
JS_UNUSED_VAL = jerry_set_property(object, prop_name, value);
|
||||
}
|
||||
|
||||
jerry_value_t jerry_get_object_field(jerry_value_t object, const char* field) {
|
||||
JS_VAR prop_name = jerry_create_string((jerry_char_t *) field);
|
||||
const bool has_property = jerry_has_property(object, prop_name);
|
||||
JS_VAR value = (has_property) ? jerry_get_property(object, prop_name) : jerry_create_undefined();
|
||||
return jerry_acquire_value(value);
|
||||
}
|
||||
|
||||
bool rocky_str_equal(jerry_value_t str_js, const char *str) {
|
||||
char buffer[40] = {0};
|
||||
PBL_ASSERTN(strlen(str) < sizeof(buffer));
|
||||
jerry_string_to_utf8_char_buffer(str_js, (jerry_char_t *) buffer, sizeof(buffer));
|
||||
return strcmp(buffer, str) == 0;
|
||||
}
|
||||
|
||||
jerry_value_t jerry_get_object_getter_result(jerry_value_t object, const char *getter_name) {
|
||||
JS_VAR getter = jerry_get_object_field(object, getter_name);
|
||||
const bool is_function = jerry_value_is_function(getter);
|
||||
JS_VAR result = (is_function) ? jerry_call_function(getter, object, NULL, 0)
|
||||
: jerry_create_undefined();
|
||||
return jerry_acquire_value(result);
|
||||
}
|
||||
|
||||
|
||||
jerry_value_t rocky_creator_object(void *ignore) {
|
||||
return jerry_create_object();
|
||||
}
|
||||
|
||||
jerry_value_t rocky_creator_empty_array(void *ignore) {
|
||||
return jerry_create_array(0);
|
||||
}
|
||||
|
||||
jerry_value_t rocky_get_or_create_object(jerry_value_t parent, const char *name,
|
||||
RockyObjectCreatorFunc creator_func, void *data,
|
||||
bool *was_created) {
|
||||
if (jerry_value_is_undefined(parent)) {
|
||||
parent = jerry_get_global_object();
|
||||
// it's safe to release the global object here already, it will never be destroyed
|
||||
jerry_release_value(parent);
|
||||
}
|
||||
|
||||
// check the object doesn't already exist
|
||||
JS_VAR val = jerry_get_object_field(parent, name);
|
||||
if (!jerry_value_is_undefined(val)) {
|
||||
if (was_created) {
|
||||
*was_created = false;
|
||||
}
|
||||
return jerry_acquire_value(val);
|
||||
}
|
||||
|
||||
JS_VAR result = creator_func(data);
|
||||
jerry_set_object_field(parent, name, result);
|
||||
|
||||
if (was_created) {
|
||||
*was_created = true;
|
||||
}
|
||||
return jerry_acquire_value(result);
|
||||
}
|
||||
|
||||
static jerry_value_t prv_create_function(void *c_function_ptr) {
|
||||
return jerry_create_external_function(c_function_ptr);
|
||||
}
|
||||
|
||||
bool rocky_add_function(jerry_value_t parent, char *name, jerry_external_handler_t handler) {
|
||||
bool result = false;
|
||||
JS_UNUSED_VAL = rocky_get_or_create_object(parent, name, prv_create_function, handler, &result);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool rocky_add_global_function(char *name, jerry_external_handler_t handler) {
|
||||
return rocky_add_function(jerry_create_undefined(), name, handler);
|
||||
}
|
||||
|
||||
jerry_value_t rocky_add_constructor(char *name, jerry_external_handler_t handler) {
|
||||
JS_VAR prototype = jerry_create_object();
|
||||
JS_VAR rocky_object = rocky_get_rocky_singleton();
|
||||
JS_VAR constructor = rocky_get_or_create_object(rocky_object, name,
|
||||
prv_create_function, handler, NULL);
|
||||
// JerryScript doesn't create a prototype for external/C functions :( probably to save memory?
|
||||
jerry_set_object_field(prototype, "constructor", constructor);
|
||||
jerry_set_object_field(constructor, "prototype", prototype);
|
||||
return jerry_acquire_value(prototype);
|
||||
}
|
||||
|
||||
jerry_value_t rocky_create_with_constructor(const char *rocky_constructor_name,
|
||||
const jerry_value_t args_p[],
|
||||
jerry_size_t args_count) {
|
||||
JS_VAR rocky_object = rocky_get_rocky_singleton();
|
||||
JS_VAR constructor = jerry_get_object_field(rocky_object, rocky_constructor_name);
|
||||
JS_VAR object = jerry_construct_object(constructor, args_p, args_count);
|
||||
|
||||
return jerry_acquire_value(object);
|
||||
}
|
||||
|
||||
// TODO: PBL-35780 make this part of app_state_get_rocky_runtime_context()
|
||||
SECTION(".rocky_bss") static jerry_value_t s_rocky_singleton;
|
||||
void rocky_set_rocky_singleton(jerry_value_t v) {
|
||||
s_rocky_singleton = jerry_acquire_value(v);
|
||||
JS_VAR global = jerry_get_global_object();
|
||||
jerry_set_object_field(global, ROCKY_SINGLETON, v);
|
||||
}
|
||||
|
||||
jerry_value_t rocky_get_rocky_singleton(void) {
|
||||
return jerry_acquire_value(s_rocky_singleton);
|
||||
}
|
||||
|
||||
void rocky_delete_singleton(void) {
|
||||
JS_VAR rocky_str = jerry_create_string((const jerry_char_t *)ROCKY_SINGLETON);
|
||||
JS_VAR global = jerry_get_global_object();
|
||||
jerry_delete_property(global, rocky_str);
|
||||
}
|
||||
|
||||
void rocky_define_property(jerry_value_t parent, const char *prop_name,
|
||||
jerry_external_handler_t getter,
|
||||
jerry_external_handler_t setter) {
|
||||
jerry_property_descriptor_t prop_desc = {};
|
||||
jerry_init_property_descriptor_fields(&prop_desc);
|
||||
prop_desc.is_get_defined = getter != NULL;
|
||||
prop_desc.getter = jerry_create_external_function(getter);
|
||||
prop_desc.is_set_defined = setter != NULL;
|
||||
prop_desc.setter = jerry_create_external_function(setter);
|
||||
JS_VAR prop_name_js = jerry_create_string((const jerry_char_t *) prop_name);
|
||||
JS_UNUSED_VAL = jerry_define_own_property(parent, prop_name_js, &prop_desc);
|
||||
jerry_release_value(prop_desc.getter);
|
||||
jerry_release_value(prop_desc.setter);
|
||||
}
|
||||
|
||||
// If result has an error flag set, log the error.
|
||||
// Note: this function releases the passed in value.
|
||||
T_STATIC void prv_log_uncaught_error(const jerry_value_t result) {
|
||||
if (jerry_value_has_error_flag(result)) {
|
||||
rocky_error_print(result);
|
||||
}
|
||||
jerry_release_value(result);
|
||||
}
|
||||
|
||||
void rocky_util_eval_and_log_uncaught_error(const jerry_char_t *source_p, size_t source_size) {
|
||||
prv_log_uncaught_error(jerry_eval(source_p, source_size, false /*strict*/));
|
||||
}
|
||||
|
||||
void rocky_util_call_user_function_and_log_uncaught_error(const jerry_value_t func_obj_val,
|
||||
const jerry_value_t this_val,
|
||||
const jerry_value_t args_p[],
|
||||
jerry_size_t args_count) {
|
||||
prv_log_uncaught_error(jerry_call_function(func_obj_val, this_val, args_p, args_count));
|
||||
}
|
||||
|
||||
jerry_value_t rocky_util_create_date(struct tm *tick_time) {
|
||||
JS_VAR date_constructor = jerry_get_global_builtin((const jerry_char_t *)"Date");
|
||||
if (!jerry_value_is_constructor(date_constructor)) {
|
||||
return jerry_create_undefined();
|
||||
}
|
||||
|
||||
jerry_value_t date_obj;
|
||||
if (tick_time) {
|
||||
jerry_value_t args[] = {
|
||||
jerry_create_number(1900 + tick_time->tm_year), jerry_create_number(tick_time->tm_mon),
|
||||
jerry_create_number(tick_time->tm_mday), jerry_create_number(tick_time->tm_hour),
|
||||
jerry_create_number(tick_time->tm_min), jerry_create_number(tick_time->tm_sec)
|
||||
};
|
||||
date_obj = jerry_construct_object(date_constructor, args, ARRAY_LENGTH(args));
|
||||
for (unsigned i = 0; i < ARRAY_LENGTH(args); ++i) {
|
||||
jerry_release_value(args[i]);
|
||||
}
|
||||
} else {
|
||||
date_obj = jerry_construct_object(date_constructor, NULL, 0);
|
||||
}
|
||||
return date_obj;
|
||||
}
|
||||
|
||||
void rocky_cleanup_js_var(const jerry_value_t *var) {
|
||||
jerry_release_value(*var);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue