From 76988731574607e0a5d644ada26a98f1567d1e95 Mon Sep 17 00:00:00 2001 From: Stupremee Date: Tue, 12 Nov 2019 17:34:58 +0100 Subject: [PATCH] Implement macro for setting builtin functions * Add make_fn macro in builtins module * Replace all array methods with the make_fn macro * Set builtins method with make_fn for bool, console, error, json, math, number, object, regexp and string * Rename make_fn macro to make_builtin_fn * Rename the actual macro rule to make_builtin_fn * make_builtin_fn macro without length will result to length 0 * Add length property for every builtin method * Remove duplicate definition of toString method in regexp * Add missing length attributes to builtins methods --- src/lib/builtins/array.rs | 51 +++++++++++++------------------------ src/lib/builtins/boolean.rs | 4 +-- src/lib/builtins/error.rs | 2 +- src/lib/builtins/json.rs | 4 +-- src/lib/builtins/math.rs | 38 +++++++++++++-------------- src/lib/builtins/mod.rs | 13 ++++++++++ src/lib/builtins/number.rs | 18 +++++-------- src/lib/builtins/object.rs | 15 +++-------- src/lib/builtins/regexp.rs | 6 ++--- src/lib/builtins/string.rs | 44 ++++++++++++++++---------------- 10 files changed, 89 insertions(+), 106 deletions(-) diff --git a/src/lib/builtins/array.rs b/src/lib/builtins/array.rs index 0b1dc7ddf2..ae0197449a 100644 --- a/src/lib/builtins/array.rs +++ b/src/lib/builtins/array.rs @@ -661,41 +661,26 @@ pub fn create_constructor(global: &Value) -> Value { // Create prototype let array_prototype = ValueData::new_obj(None); - let length = Property::default().get(to_value(get_array_length as NativeFunctionData)); - array_prototype.set_prop_slice("length", length); - let concat_func = to_value(concat as NativeFunctionData); - concat_func.set_field_slice("length", to_value(1_i32)); - array_prototype.set_field_slice("concat", concat_func); - let push_func = to_value(push as NativeFunctionData); - push_func.set_field_slice("length", to_value(1_i32)); - let index_of_func = to_value(index_of as NativeFunctionData); - index_of_func.set_field_slice("length", to_value(1_i32)); - let last_index_of_func = to_value(last_index_of as NativeFunctionData); - last_index_of_func.set_field_slice("length", to_value(1_i32)); - let includes_func = to_value(includes_value as NativeFunctionData); - includes_func.set_field_slice("length", to_value(1_i32)); - let map_func = to_value(map as NativeFunctionData); - map_func.set_field_slice("length", to_value(1_i32)); - let fill_func = to_value(fill as NativeFunctionData); - fill_func.set_field_slice("length", to_value(1_i32)); - - array_prototype.set_field_slice("push", push_func); - array_prototype.set_field_slice("pop", to_value(pop as NativeFunctionData)); - array_prototype.set_field_slice("join", to_value(join as NativeFunctionData)); - array_prototype.set_field_slice("reverse", to_value(reverse as NativeFunctionData)); - array_prototype.set_field_slice("shift", to_value(shift as NativeFunctionData)); - array_prototype.set_field_slice("unshift", to_value(unshift as NativeFunctionData)); - array_prototype.set_field_slice("every", to_value(every as NativeFunctionData)); - array_prototype.set_field_slice("find", to_value(find as NativeFunctionData)); - array_prototype.set_field_slice("findIndex", to_value(find_index as NativeFunctionData)); - array_prototype.set_field_slice("includes", includes_func); - array_prototype.set_field_slice("indexOf", index_of_func); - array_prototype.set_field_slice("lastIndexOf", last_index_of_func); - array_prototype.set_field_slice("fill", fill_func); - array_prototype.set_field_slice("slice", to_value(slice as NativeFunctionData)); - array_prototype.set_field_slice("map", map_func); + + make_builtin_fn!(concat, named "concat", with length 1, of array_prototype); + make_builtin_fn!(push, named "push", with length 1, of array_prototype); + make_builtin_fn!(index_of, named "indexOf", with length 1, of array_prototype); + make_builtin_fn!(last_index_of, named "lastIndexOf", with length 1, of array_prototype); + make_builtin_fn!(includes_value, named "includes", with length 1, of array_prototype); + make_builtin_fn!(map, named "map", with length 1, of array_prototype); + make_builtin_fn!(fill, named "fill", with length 1, of array_prototype); + + make_builtin_fn!(pop, named "pop", of array_prototype); + make_builtin_fn!(join, named "join", with length 1, of array_prototype); + make_builtin_fn!(reverse, named "reverse", of array_prototype); + make_builtin_fn!(shift, named "shift", of array_prototype); + make_builtin_fn!(unshift, named "unshift", with length 1, of array_prototype); + make_builtin_fn!(every, named "every", with length 1, of array_prototype); + make_builtin_fn!(find, named "find", with length 1, of array_prototype); + make_builtin_fn!(find_index, named "findIndex", with length 1, of array_prototype); + make_builtin_fn!(slice, named "slice", with length 2, of array_prototype); let array = to_value(array_constructor); array.set_field_slice(PROTOTYPE, to_value(array_prototype.clone())); diff --git a/src/lib/builtins/boolean.rs b/src/lib/builtins/boolean.rs index b5d9446c66..08ae55cc1d 100644 --- a/src/lib/builtins/boolean.rs +++ b/src/lib/builtins/boolean.rs @@ -56,8 +56,8 @@ pub fn create_constructor(global: &Value) -> Value { // https://tc39.es/ecma262/#sec-properties-of-the-boolean-prototype-object let boolean_prototype = ValueData::new_obj(Some(global)); boolean_prototype.set_internal_slot("BooleanData", to_boolean(&to_value(false))); - boolean_prototype.set_field_slice("toString", to_value(to_string as NativeFunctionData)); - boolean_prototype.set_field_slice("valueOf", to_value(value_of as NativeFunctionData)); + make_builtin_fn!(to_string, named "toString", of boolean_prototype); + make_builtin_fn!(value_of, named "valueOf", of boolean_prototype); let boolean_value = to_value(boolean); boolean_prototype.set_field_slice("constructor", to_value(boolean_value.clone())); diff --git a/src/lib/builtins/error.rs b/src/lib/builtins/error.rs index 1fa3e7a0c8..a272a8561e 100644 --- a/src/lib/builtins/error.rs +++ b/src/lib/builtins/error.rs @@ -36,7 +36,7 @@ pub fn _create(global: &Value) -> Value { let prototype = ValueData::new_obj(Some(global)); prototype.set_field_slice("message", to_value("")); prototype.set_field_slice("name", to_value("Error")); - prototype.set_field_slice("toString", to_value(to_string as NativeFunctionData)); + make_builtin_fn!(to_string, named "toString", of prototype); let error = to_value(make_error as NativeFunctionData); error.set_field_slice(PROTOTYPE, prototype); error diff --git a/src/lib/builtins/json.rs b/src/lib/builtins/json.rs index 8f184fb2f1..8be05f1450 100644 --- a/src/lib/builtins/json.rs +++ b/src/lib/builtins/json.rs @@ -33,8 +33,8 @@ pub fn create_constructor(global: &Value) -> Value { json.kind = ObjectKind::Ordinary; let prototype = ValueData::new_obj(Some(global)); - prototype.set_field_slice("parse", to_value(parse as NativeFunctionData)); - prototype.set_field_slice("stringify", to_value(stringify as NativeFunctionData)); + make_builtin_fn!(parse, named "parse", with length 2, of prototype); + make_builtin_fn!(stringify, named "stringify", with length 3, of prototype); let json_value = to_value(json); json_value.set_field_slice(PROTOTYPE, prototype); diff --git a/src/lib/builtins/math.rs b/src/lib/builtins/math.rs index cfdabf50cd..b8e337c1e4 100644 --- a/src/lib/builtins/math.rs +++ b/src/lib/builtins/math.rs @@ -203,24 +203,24 @@ pub fn create_constructor(global: &Value) -> Value { math.set_field_slice("SQRT1_2", to_value(0.5_f64.sqrt())); math.set_field_slice("SQRT2", to_value(f64::consts::SQRT_2)); math.set_field_slice("PI", to_value(f64::consts::PI)); - math.set_field_slice("abs", to_value(abs as NativeFunctionData)); - math.set_field_slice("acos", to_value(acos as NativeFunctionData)); - math.set_field_slice("asin", to_value(asin as NativeFunctionData)); - math.set_field_slice("atan", to_value(atan as NativeFunctionData)); - math.set_field_slice("atan2", to_value(atan2 as NativeFunctionData)); - math.set_field_slice("cbrt", to_value(cbrt as NativeFunctionData)); - math.set_field_slice("ceil", to_value(ceil as NativeFunctionData)); - math.set_field_slice("cos", to_value(cos as NativeFunctionData)); - math.set_field_slice("exp", to_value(exp as NativeFunctionData)); - math.set_field_slice("floor", to_value(floor as NativeFunctionData)); - math.set_field_slice("log", to_value(log as NativeFunctionData)); - math.set_field_slice("max", to_value(max as NativeFunctionData)); - math.set_field_slice("min", to_value(min as NativeFunctionData)); - math.set_field_slice("pow", to_value(pow as NativeFunctionData)); - math.set_field_slice("random", to_value(_random as NativeFunctionData)); - math.set_field_slice("round", to_value(round as NativeFunctionData)); - math.set_field_slice("sin", to_value(sin as NativeFunctionData)); - math.set_field_slice("sqrt", to_value(sqrt as NativeFunctionData)); - math.set_field_slice("tan", to_value(tan as NativeFunctionData)); + make_builtin_fn!(abs, named "abs", with length 1, of math); + make_builtin_fn!(acos, named "acos", with length 1, of math); + make_builtin_fn!(asin, named "asin", with length 1, of math); + make_builtin_fn!(atan, named "atan", with length 1, of math); + make_builtin_fn!(atan2, named "atan2", with length 2, of math); + make_builtin_fn!(cbrt, named "cbrt", with length 1, of math); + make_builtin_fn!(ceil, named "ceil", with length 1, of math); + make_builtin_fn!(cos, named "cos", with length 1, of math); + make_builtin_fn!(exp, named "exp", with length 1, of math); + make_builtin_fn!(floor, named "floor", with length 1, of math); + make_builtin_fn!(log, named "log", with length 1, of math); + make_builtin_fn!(max, named "max", with length 2, of math); + make_builtin_fn!(min, named "min", with length 2, of math); + make_builtin_fn!(pow, named "pow", with length 2, of math); + make_builtin_fn!(_random, named "random", of math); + make_builtin_fn!(round, named "round", with length 1, of math); + make_builtin_fn!(sin, named "sin", with length 1, of math); + make_builtin_fn!(sqrt, named "sqrt", with length 1, of math); + make_builtin_fn!(tan, named "tan", with length 1, of math); math } diff --git a/src/lib/builtins/mod.rs b/src/lib/builtins/mod.rs index a1c89dada9..18e79c7b0b 100644 --- a/src/lib/builtins/mod.rs +++ b/src/lib/builtins/mod.rs @@ -1,3 +1,16 @@ +/// Macro to create a new member function of a prototype +/// If no length is provided, the length will be set to 0. +macro_rules! make_builtin_fn { + ($fn:ident, named $name:expr, with length $l:tt, of $p:ident) => { + let $fn = to_value($fn as NativeFunctionData); + $fn.set_field_slice("length", to_value($l)); + $p.set_field_slice($name, $fn); + }; + ($fn:ident, named $name:expr, of $p:ident) => { + make_builtin_fn!($fn, named $name, with length 0, of $p); + }; +} + /// The global `Array` object pub mod array; /// the global `Symbol` Object diff --git a/src/lib/builtins/number.rs b/src/lib/builtins/number.rs index 6b99046235..8426a17647 100644 --- a/src/lib/builtins/number.rs +++ b/src/lib/builtins/number.rs @@ -145,18 +145,12 @@ pub fn create_constructor(global: &Value) -> Value { number_prototype.set_internal_slot("NumberData", to_value(0)); - number_prototype.set_field_slice( - "toExponential", - to_value(to_exponential as NativeFunctionData), - ); - number_prototype.set_field_slice("toFixed", to_value(to_fixed as NativeFunctionData)); - number_prototype.set_field_slice( - "toLocaleString", - to_value(to_locale_string as NativeFunctionData), - ); - number_prototype.set_field_slice("toPrecision", to_value(to_precision as NativeFunctionData)); - number_prototype.set_field_slice("toString", to_value(to_string as NativeFunctionData)); - number_prototype.set_field_slice("valueOf", to_value(value_of as NativeFunctionData)); + make_builtin_fn!(to_exponential, named "toExponential", with length 1, of number_prototype); + make_builtin_fn!(to_fixed, named "toFixed", with length 1, of number_prototype); + make_builtin_fn!(to_locale_string, named "toLocaleString", of number_prototype); + make_builtin_fn!(to_precision, named "toPrecision", with length 1, of number_prototype); + make_builtin_fn!(to_string, named "toString", with length 1, of number_prototype); + make_builtin_fn!(value_of, named "valueOf", of number_prototype); let number = to_value(number_constructor); number_prototype.set_field_slice("constructor", number.clone()); diff --git a/src/lib/builtins/object.rs b/src/lib/builtins/object.rs index 6bac66b72b..01cb83209c 100644 --- a/src/lib/builtins/object.rs +++ b/src/lib/builtins/object.rs @@ -565,17 +565,8 @@ pub fn create_constructor(_: &Value) -> Value { object.set_field_slice("length", to_value(1_i32)); object.set_field_slice(PROTOTYPE, to_value(prototype)); - object.set_field_slice( - "setPrototypeOf", - to_value(set_proto_of as NativeFunctionData), - ); - object.set_field_slice( - "getPrototypeOf", - to_value(get_proto_of as NativeFunctionData), - ); - object.set_field_slice( - "defineProperty", - to_value(define_prop as NativeFunctionData), - ); + make_builtin_fn!(set_proto_of, named "setPrototypeOf", with length 2, of object); + make_builtin_fn!(get_proto_of, named "getPrototypeOf", with length 1, of object); + make_builtin_fn!(define_prop, named "defineProperty", with length 3, of object); object } diff --git a/src/lib/builtins/regexp.rs b/src/lib/builtins/regexp.rs index 5fd97217a3..a0878860f5 100644 --- a/src/lib/builtins/regexp.rs +++ b/src/lib/builtins/regexp.rs @@ -336,9 +336,9 @@ pub fn create_constructor(global: &Value) -> Value { // Create prototype let proto = ValueData::new_obj(Some(global)); - proto.set_field_slice("test", to_value(test as NativeFunctionData)); - proto.set_field_slice("exec", to_value(exec as NativeFunctionData)); - proto.set_field_slice("toString", to_value(to_string as NativeFunctionData)); + make_builtin_fn!(test, named "test", with length 1, of proto); + make_builtin_fn!(exec, named "exec", with length 1, of proto); + make_builtin_fn!(to_string, named "toString", of proto); proto.set_field_slice("lastIndex", to_value(0)); proto.set_prop_slice("dotAll", _make_prop(get_dot_all)); proto.set_prop_slice("flags", _make_prop(get_flags)); diff --git a/src/lib/builtins/string.rs b/src/lib/builtins/string.rs index d543072c09..1ea1e73cf3 100644 --- a/src/lib/builtins/string.rs +++ b/src/lib/builtins/string.rs @@ -744,28 +744,28 @@ pub fn create_constructor(global: &Value) -> Value { let prop = Property::default().get(to_value(get_string_length as NativeFunctionData)); proto.set_prop_slice("length", prop); - proto.set_field_slice("charAt", to_value(char_at as NativeFunctionData)); - proto.set_field_slice("charCodeAt", to_value(char_code_at as NativeFunctionData)); - proto.set_field_slice("toString", to_value(to_string as NativeFunctionData)); - proto.set_field_slice("concat", to_value(concat as NativeFunctionData)); - proto.set_field_slice("repeat", to_value(repeat as NativeFunctionData)); - proto.set_field_slice("slice", to_value(slice as NativeFunctionData)); - proto.set_field_slice("startsWith", to_value(starts_with as NativeFunctionData)); - proto.set_field_slice("endsWith", to_value(ends_with as NativeFunctionData)); - proto.set_field_slice("includes", to_value(includes as NativeFunctionData)); - proto.set_field_slice("indexOf", to_value(index_of as NativeFunctionData)); - proto.set_field_slice("lastIndexOf", to_value(last_index_of as NativeFunctionData)); - proto.set_field_slice("match", to_value(r#match as NativeFunctionData)); - proto.set_field_slice("padEnd", to_value(pad_end as NativeFunctionData)); - proto.set_field_slice("padStart", to_value(pad_start as NativeFunctionData)); - proto.set_field_slice("trim", to_value(trim as NativeFunctionData)); - proto.set_field_slice("trimStart", to_value(trim_start as NativeFunctionData)); - proto.set_field_slice("toLowerCase", to_value(to_lowercase as NativeFunctionData)); - proto.set_field_slice("toUpperCase", to_value(to_uppercase as NativeFunctionData)); - proto.set_field_slice("substring", to_value(substring as NativeFunctionData)); - proto.set_field_slice("substr", to_value(substr as NativeFunctionData)); - proto.set_field_slice("valueOf", to_value(value_of as NativeFunctionData)); - proto.set_field_slice("matchAll", to_value(match_all as NativeFunctionData)); + make_builtin_fn!(char_at, named "charAt", with length 1, of proto); + make_builtin_fn!(char_code_at, named "charCodeAt", with length 1, of proto); + make_builtin_fn!(to_string, named "toString", of proto); + make_builtin_fn!(concat, named "concat", with length 1, of proto); + make_builtin_fn!(repeat, named "repeat", with length 1, of proto); + make_builtin_fn!(slice, named "slice", with length 2, of proto); + make_builtin_fn!(starts_with, named "startsWith", with length 1, of proto); + make_builtin_fn!(ends_with, named "endsWith", with length 1, of proto); + make_builtin_fn!(includes, named "includes", with length 1, of proto); + make_builtin_fn!(index_of, named "indexOf", with length 1, of proto); + make_builtin_fn!(last_index_of, named "lastIndexOf", with length 1, of proto); + make_builtin_fn!(r#match, named "match", with length 1, of proto); + make_builtin_fn!(pad_end, named "padEnd", with length 1, of proto); + make_builtin_fn!(pad_start, named "padStart", with length 1, of proto); + make_builtin_fn!(trim, named "trim", of proto); + make_builtin_fn!(trim_start, named "trimStart", of proto); + make_builtin_fn!(to_lowercase, named "toLowerCase", of proto); + make_builtin_fn!(to_uppercase, named "toUpperCase", of proto); + make_builtin_fn!(substring, named "substring", with length 2, of proto); + make_builtin_fn!(substr, named "substr", with length 2, of proto); + make_builtin_fn!(value_of, named "valueOf", of proto); + make_builtin_fn!(match_all, named "matchAll", with length 1, of proto); let string = to_value(string_constructor); proto.set_field_slice("constructor", string.clone());