Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on: [push]
# Global Cache Settings
env:
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
GODOT_BASE_BRANCH: '3.2.3-stable'
GODOT_BASE_BRANCH: '3.3-stable'
BASE_BRANCH: master
SCONS_CACHE_LIMIT: 4096

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ You can also get the binaries with lastest commits from the [github build action
### Compilation
* Clone the source code of [godot](https://github.com/godotengine/godot)
* Clone this module and put it into `godot/modules/` and make sure the folder name of this module is `ECMAScript`
* [Recompile the godot engine](https://docs.godotengine.org/en/3.2/development/compiling/index.html) <b>(Only MinGW is supported on Windows for now!)</b>
* [Recompile the godot engine](https://docs.godotengine.org/en/3.3/development/compiling/index.html) <b>(Only MinGW is supported on Windows for now!)</b>

![Build Godot with ECMAScript](https://github.com/GodotExplorer/ECMAScript/workflows/Build%20Godot%20with%20ECMAScript/badge.svg)

Expand Down
5 changes: 2 additions & 3 deletions SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def dump_text_file_to_cpp(file):
length = len(lines)
for i in range(length):
line = lines[i].replace('"', '\\"')
line = '\t"' + line + '\\n"';
line = '\t"' + line + '\\n"'
if i < length -1:
line += "\n"
source += line
Expand Down Expand Up @@ -57,7 +57,7 @@ sources = [

if env['tools']:
with open_file("tools/godot.d.ts.gen.cpp", "w") as f:
text = '/* THIS FILE IS GENERATED DO NOT EDIT */\n#include "editor_tools.h"\nString ECMAScriptPlugin::BUILTIN_DECLEARATION_TEXT = \n${source};';
text = '/* THIS FILE IS GENERATED DO NOT EDIT */\n#include "editor_tools.h"\nString ECMAScriptPlugin::BUILTIN_DECLARATION_TEXT = \n${source};'
f.write(text.replace('${source}', dump_text_file_to_cpp("misc/godot.d.ts")))
with open_file("tools/tsconfig.json.gen.cpp", "w") as f:
text = '/* THIS FILE IS GENERATED DO NOT EDIT */\n#include "editor_tools.h"\nString ECMAScriptPlugin::TSCONFIG_CONTENT = \n${source};'
Expand All @@ -71,5 +71,4 @@ if env['tools']:
env_module.add_source_files(env.modules_sources, 'tools/*.cpp')

env_module.Append(CPPPATH=["#modules/ECMAScript"])
env_module.Append(CXXFLAGS=["-std=c++11"])
env_module.add_source_files(env.modules_sources, sources)
6 changes: 3 additions & 3 deletions generate_builtin_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@
]
}

def apply_parttern(template, values):
def apply_pattern(template, values):
for key in values:
template = template.replace( '${' + key + '}', values[key])
return template
Expand Down Expand Up @@ -405,15 +405,15 @@ def parse_class(cls):
if class_name in IGNORED_PROPS and const_name in IGNORED_PROPS[class_name]:
continue
constants.append(dict(c.attrib))
return json.loads(apply_parttern(json.dumps(ret), {
return json.loads(apply_pattern(json.dumps(ret), {
'class_name': class_name,
}))

def generate_api_json(MODULE_DIR):
DOCS_DIR = os.path.abspath(os.path.join(MODULE_DIR, "../../doc/classes"))
if not os.path.isdir(DOCS_DIR) and len(sys.argv) > 1:
DOCS_DIR = sys.argv[-1]
OUTPUT_FILE = os.path.join(MODULE_DIR, "buitin_api.gen.json");
OUTPUT_FILE = os.path.join(MODULE_DIR, "builtin_api.gen.json")

classes = []
for cls in BUILTIN_CLASSES:
Expand Down
88 changes: 44 additions & 44 deletions quickjs/builtin_binding_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

DIR = os.path.abspath( os.path.dirname(__file__) )
OUTPUT_FILE = os.path.join(DIR, "quickjs_builtin_binder.gen.cpp")
API = json.load(open(os.path.join(DIR, '..', 'buitin_api.gen.json'), 'r'))
API = json.load(open(os.path.join(DIR, '..', 'builtin_api.gen.json'), 'r'))

VariantTypes = {
"boolean": "Variant::BOOL",
Expand Down Expand Up @@ -104,7 +104,7 @@
"Variant": 'QuickJSBinder::variant_to_var(ctx, ${arg})',
}

def apply_parttern(template, values):
def apply_pattern(template, values):
for key in values:
template = template.replace( '${' + key + '}', values[key])
return template
Expand Down Expand Up @@ -411,22 +411,22 @@ def generate_constructor(cls):
}
}
''',
"PoolByteArray": apply_parttern(TemplatePoolArrays, {"class": "PoolByteArray", "type": "Variant::POOL_BYTE_ARRAY", "element": "uint8_t"}),
"PoolIntArray": apply_parttern(TemplatePoolArrays, {"class": "PoolIntArray", "type": "Variant::POOL_INT_ARRAY", "element": "int"}),
"PoolRealArray": apply_parttern(TemplatePoolArrays, {"class": "PoolRealArray", "type": "Variant::POOL_REAL_ARRAY", "element": "real_t"}),
"PoolVector2Array": apply_parttern(TemplatePoolArrays, {"class": "PoolVector2Array", "type": "Variant::POOL_VECTOR2_ARRAY", "element": "Vector2"}),
"PoolVector3Array": apply_parttern(TemplatePoolArrays, {"class": "PoolVector3Array", "type": "Variant::POOL_VECTOR3_ARRAY", "element": "Vector3"}),
"PoolColorArray": apply_parttern(TemplatePoolArrays, {"class": "PoolColorArray", "type": "Variant::POOL_COLOR_ARRAY", "element": "Color"}),
"PoolStringArray": apply_parttern(TemplateSimplePoolArrays,{"class": "PoolStringArray", "type": "Variant::POOL_STRING_ARRAY", "element": "String"}),
"PoolByteArray": apply_pattern(TemplatePoolArrays, {"class": "PoolByteArray", "type": "Variant::POOL_BYTE_ARRAY", "element": "uint8_t"}),
"PoolIntArray": apply_pattern(TemplatePoolArrays, {"class": "PoolIntArray", "type": "Variant::POOL_INT_ARRAY", "element": "int"}),
"PoolRealArray": apply_pattern(TemplatePoolArrays, {"class": "PoolRealArray", "type": "Variant::POOL_REAL_ARRAY", "element": "real_t"}),
"PoolVector2Array": apply_pattern(TemplatePoolArrays, {"class": "PoolVector2Array", "type": "Variant::POOL_VECTOR2_ARRAY", "element": "Vector2"}),
"PoolVector3Array": apply_pattern(TemplatePoolArrays, {"class": "PoolVector3Array", "type": "Variant::POOL_VECTOR3_ARRAY", "element": "Vector3"}),
"PoolColorArray": apply_pattern(TemplatePoolArrays, {"class": "PoolColorArray", "type": "Variant::POOL_COLOR_ARRAY", "element": "Color"}),
"PoolStringArray": apply_pattern(TemplateSimplePoolArrays,{"class": "PoolStringArray", "type": "Variant::POOL_STRING_ARRAY", "element": "String"}),
}
class_name = cls['name']
constructor_name = apply_parttern(TemplateConstructorName, {"class": class_name})
constructor_declare = apply_parttern(TemplateConstructorDeclare, {"class": class_name})
constructor_name = apply_pattern(TemplateConstructorName, {"class": class_name})
constructor_declare = apply_pattern(TemplateConstructorDeclare, {"class": class_name})

initializer = ''
if class_name in ConstructorInitializers:
initializer = ConstructorInitializers[class_name]
consturctor = apply_parttern(TemplateConstructor, {
consturctor = apply_pattern(TemplateConstructor, {
'class': class_name,
'type': VariantTypes[class_name],
'func': constructor_name,
Expand Down Expand Up @@ -479,21 +479,21 @@ def generate_members(cls):
type = p['type']
name = p['name']
native_name = p['native']
getters += apply_parttern(TemplateGetterItem, {
getters += apply_pattern(TemplateGetterItem, {
'index': str(i),
'value': apply_parttern(GodotToJSTemplates[type], { 'arg': apply_parttern('ptr->${native}', {'native': native_name}) })
'value': apply_pattern(GodotToJSTemplates[type], { 'arg': apply_pattern('ptr->${native}', {'native': native_name}) })
})
setters += apply_parttern(TemplateSetterItem, {
setters += apply_pattern(TemplateSetterItem, {
'index': str(i),
'name': name,
'native': native_name,
'type': VariantTypes[type],
'type_name': type,
'class': class_name,
'value': apply_parttern(JSToGodotTemplates[type], {'arg': 'argv[0]'})
'value': apply_pattern(JSToGodotTemplates[type], {'arg': 'argv[0]'})
})
bindings += apply_parttern(TemplateItemBinding, {'index': str(i), 'name': name, 'type': VariantTypes[class_name]})
return apply_parttern(Template, {
bindings += apply_pattern(TemplateItemBinding, {'index': str(i), 'name': name, 'type': VariantTypes[class_name]})
return apply_pattern(Template, {
'class': class_name,
'getters': getters,
'setters': setters,
Expand All @@ -509,12 +509,12 @@ def generate_methods(cls):
[](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
ECMAScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, this_val);
${class} *ptr = bind->get${class}();\
${arg_declars}
${arg_declares}
${call}
return ${return};
},
${argc});'''
TemplateArgDeclear = '''
TemplateArgDeclare = '''
#ifdef DEBUG_METHODS_ENABLED
ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, ${type}, argv[${index}]), (JS_ThrowTypeError(ctx, "${type_name} expected for argument ${index} of ${class}.${name}")));
#endif
Expand All @@ -524,39 +524,39 @@ def generate_methods(cls):
bindings = ''
for m in cls['methods']:
args = ''
arg_declars = ''
arg_declares = ''
for i in range(len(m['arguments'])):
arg = m['arguments'][i]
arg_type = arg['type']
arg_declars += apply_parttern(TemplateArgDeclear, {
arg_declares += apply_pattern(TemplateArgDeclare, {
'index': str(i),
'type': VariantTypes[arg_type],
'type_name': arg_type,
'class': class_name,
'name': m['name'],
'arg': apply_parttern(JSToGodotTemplates[arg_type], {'arg': 'argv[' + str(i) +']'}),
'arg': apply_pattern(JSToGodotTemplates[arg_type], {'arg': 'argv[' + str(i) +']'}),
'godot_type': GodotTypeNames[arg_type],
})
if i > 0: args += ', '
args += 'arg' + str(i)
CallTemplate = ('' if m['return'] == 'void' else (apply_parttern(TemplateReturnValue, {"godot_type": GodotTypeNames[m['return']]}))) + 'ptr->${native_method}(${args});'
call = apply_parttern(CallTemplate, {'native_method': m['native_method'], 'args': args})
bindings += apply_parttern(TemplateMethod, {
CallTemplate = ('' if m['return'] == 'void' else (apply_pattern(TemplateReturnValue, {"godot_type": GodotTypeNames[m['return']]}))) + 'ptr->${native_method}(${args});'
call = apply_pattern(CallTemplate, {'native_method': m['native_method'], 'args': args})
bindings += apply_pattern(TemplateMethod, {
"class": class_name,
"type": VariantTypes[class_name],
"name": m['name'],
"call": call,
"arg_declars": arg_declars,
"arg_declares": arg_declares,
"argc": str(len(m['arguments'])),
"return": 'JS_UNDEFINED' if m['return'] == 'void' else apply_parttern(GodotToJSTemplates[m['return']], {'arg': 'ret'}),
"return": 'JS_UNDEFINED' if m['return'] == 'void' else apply_pattern(GodotToJSTemplates[m['return']], {'arg': 'ret'}),
})
return bindings

def generate_constants(cls):
ConstTemplate = '\tbinder->get_builtin_binder().register_constant(${type}, "${name}", ${value});\n'
bindings = ''
for c in cls['constants']:
bindings += apply_parttern(ConstTemplate, {
bindings += apply_pattern(ConstTemplate, {
"name": c['name'],
"type": VariantTypes[class_name],
"value": c['value']
Expand All @@ -572,7 +572,7 @@ def genertate_operators(cls):
'operator==': '==',
'operator<': '<'
}
TargetDeclearTemplate = '''
TargetDeclareTemplate = '''
#ifdef DEBUG_METHODS_ENABLED
ERR_FAIL_COND_V(!QuickJSBinder::validate_type(ctx, ${type}, argv[1]), (JS_ThrowTypeError(ctx, "${target_class} expected for ${class}.${operator}")));
#endif
Expand All @@ -584,7 +584,7 @@ def genertate_operators(cls):
JS_NewCFunction(ctx, [](JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) {
ECMAScriptGCHandler *bind = BINDING_DATA_FROM_JS(ctx, argv[0]);
${class} *ptr = bind->get${class}();\
${target_declear}
${target_declare}
${call}
return ${return};
},
Expand All @@ -607,29 +607,29 @@ def genertate_operators(cls):
js_op = 'neg'

args = ''
target_declear = ''
target_declare = ''
if argc > 1:
arg_class = o['arguments'][0]['type']
target_declear = apply_parttern(TargetDeclearTemplate, {
target_declare = apply_pattern(TargetDeclareTemplate, {
'target_class': arg_class,
'type': VariantTypes[arg_class],
'class': class_name,
'operator': o['native_method'],
})
args = '*target'
CallTemplate = ('' if o['return'] == 'void' else apply_parttern(TemplateReturnValue, {'godot_type': GodotTypeNames[o['return']] })) + 'ptr->${op}(${args});'
call = apply_parttern(CallTemplate, {'op': op, 'args': args})
bindings += apply_parttern(OperatorTemplate, {
CallTemplate = ('' if o['return'] == 'void' else apply_pattern(TemplateReturnValue, {'godot_type': GodotTypeNames[o['return']] })) + 'ptr->${op}(${args});'
call = apply_pattern(CallTemplate, {'op': op, 'args': args})
bindings += apply_pattern(OperatorTemplate, {
'type': VariantTypes[class_name],
'class': class_name,
'js_op': js_op,
'call': call,
'name': o['name'],
'target_declear': target_declear,
"return": 'JS_UNDEFINED' if o['return'] == 'void' else apply_parttern(GodotToJSTemplates[o['return']], {'arg': 'ret'}),
'target_declare': target_declare,
"return": 'JS_UNDEFINED' if o['return'] == 'void' else apply_pattern(GodotToJSTemplates[o['return']], {'arg': 'ret'}),
'argc': str(argc)
})
bindings += apply_parttern('''
bindings += apply_pattern('''
operators.push_back(base_operators);
binder->get_builtin_binder().get_cross_type_operators(${type}, operators);
binder->get_builtin_binder().register_operators(${type}, operators);
Expand All @@ -646,21 +646,21 @@ def genertate_operators(cls):
}
'''
class_name = cls['name']
property_declare = apply_parttern(TemplateDeclar, {"class": class_name})
property_defines = apply_parttern(TemplateBindDefine, {
property_declare = apply_pattern(TemplateDeclar, {"class": class_name})
property_defines = apply_pattern(TemplateBindDefine, {
"class": class_name,
"members": generate_members(cls) if len(cls['properties']) else '',
"methods": generate_methods(cls),
"constants": generate_constants(cls),
"operators": genertate_operators(cls),
})
property_bind = apply_parttern(TemplateBind, {"class": class_name})
property_bind = apply_pattern(TemplateBind, {"class": class_name})
return property_declare, property_defines, property_bind


def generate_class_bind_action(cls, constructor):
Template = '\tregister_builtin_class(${type}, "${class}", ${constructor}, ${argc});\n'
return apply_parttern(Template, {
return apply_pattern(Template, {
'class': cls['name'],
'constructor': constructor,
'type': VariantTypes[cls['name']],
Expand Down Expand Up @@ -703,7 +703,7 @@ def generate_builtin_bindings():
definitions += property_defines
bindings += property_bind

output = apply_parttern(Template, {
output = apply_pattern(Template, {
'declarations': declarations,
'bindings': bindings,
'definitions': definitions,
Expand Down
17 changes: 9 additions & 8 deletions quickjs/quickjs_binder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
#include "editor/editor_settings.h"
#endif

uint32_t QuickJSBinder::global_context_id = 0;
uint64_t QuickJSBinder::global_transfer_id = 0;
SafeNumeric<uint32_t> QuickJSBinder::global_context_id;
SafeNumeric<uint64_t> QuickJSBinder::global_transfer_id;

HashMap<uint64_t, Variant> QuickJSBinder::transfer_deopot;
Map<String, const char *> QuickJSBinder::class_remap;
List<String> compiling_modules;
Expand Down Expand Up @@ -187,7 +188,7 @@ JSValue QuickJSBinder::object_method(JSContext *ctx, JSValueConst this_val, int
}
ERR_PRINTS(obj->get_class() + "." + mb->get_name() + ENDL + err_message + ENDL + stack_message);
JS_FreeValue(ctx, ret);
ret = JS_ThrowTypeError(ctx, err_message.utf8().get_data());
ret = JS_ThrowTypeError(ctx, "%s", err_message.utf8().get_data());
}
#endif

Expand Down Expand Up @@ -804,7 +805,7 @@ JSClassID QuickJSBinder::register_class(const ClassDB::ClassInfo *p_cls) {
if (class_remap.has(p_cls->name)) {
data.class_name = class_remap[p_cls->name];
data.jsclass.class_name = class_remap[p_cls->name];
if (data.jsclass.class_name == "") {
if (strcmp(data.jsclass.class_name, "") == 0) {
return 0;
}
} else {
Expand Down Expand Up @@ -1152,7 +1153,7 @@ void QuickJSBinder::add_godot_globals() {
}
}

// buitin functions
// builtin functions
for (int i = 0; i < Expression::FUNC_MAX; ++i) {
Expression::BuiltinFunc func = (Expression::BuiltinFunc)i;
String name = Expression::get_func_name(func);
Expand Down Expand Up @@ -1211,7 +1212,7 @@ void QuickJSBinder::add_godot_globals() {
}

QuickJSBinder::QuickJSBinder() {
context_id = global_context_id++;
context_id = QuickJSBinder::global_context_id.increment();
internal_godot_method_id = 0;
internal_godot_indexed_property_id = 0;
godot_allocator.js_malloc = QuickJSBinder::js_binder_malloc;
Expand Down Expand Up @@ -2214,7 +2215,7 @@ const ECMAClassInfo *QuickJSBinder::parse_ecma_class_from_module(ModuleCache *p_
if (!JS_IsFunction(ctx, default_entry)) {
String err = "Failed parse ECMAClass from script " + p_path + ENDL "\t" + "Default export entry must be a godot class!";
ERR_PRINTS(err);
JS_ThrowTypeError(ctx, err.utf8().get_data());
JS_ThrowTypeError(ctx, "%s", err.utf8().get_data());
goto fail;
}
ecma_class = register_ecma_class(default_entry, p_path);
Expand Down Expand Up @@ -2320,7 +2321,7 @@ JSValue QuickJSBinder::godot_abandon_value(JSContext *ctx, JSValue this_val, int

uint64_t id = 0;
if (valid) {
id = atomic_increment(&global_transfer_id);
id = QuickJSBinder::global_transfer_id.increment();
GLOBAL_LOCK_FUNCTION
transfer_deopot.set(id, gd_value);
}
Expand Down
4 changes: 2 additions & 2 deletions quickjs/quickjs_binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ class QuickJSBinder : public ECMAScriptBinder {
QuickJSBuiltinBinder builtin_binder;

protected:
static uint32_t global_context_id;
static uint64_t global_transfer_id;
static SafeNumeric<uint32_t> global_context_id;
static SafeNumeric<uint64_t> global_transfer_id;
JSRuntime *runtime;
JSContext *ctx;
JSMallocFunctions godot_allocator;
Expand Down
Loading