Added a new cscript module. It's a copy of gdscript, and it's build is disabled for now. I plan to experiment with it to have a scripting language that's syntax is as close to c (c++) as possible.

This commit is contained in:
Relintai 2022-07-12 12:20:34 +02:00
parent 4afcf246aa
commit e687fc6a4a
22 changed files with 26678 additions and 0 deletions

12
modules/cscript/SCsub Normal file
View File

@ -0,0 +1,12 @@
#!/usr/bin/env python
Import("env")
Import("env_modules")
env_gdscript = env_modules.Clone()
env_gdscript.add_source_files(env.modules_sources, "*.cpp")
if env["tools"]:
env_gdscript.add_source_files(env.modules_sources, "./editor/*.cpp")

21
modules/cscript/config.py Normal file
View File

@ -0,0 +1,21 @@
def can_build(env, platform):
#return True
#not yet
return False
def configure(env):
pass
def get_doc_classes():
return [
"@CScript",
"CScript",
"CScriptFunctionState",
]
def get_doc_path():
return "doc_classes"

2293
modules/cscript/cscript.cpp Normal file

File diff suppressed because it is too large Load Diff

567
modules/cscript/cscript.h Normal file
View File

@ -0,0 +1,567 @@
#ifndef CSCRIPT_H
#define CSCRIPT_H
/*************************************************************************/
/* gdscript.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/io/resource_loader.h"
#include "core/io/resource_saver.h"
#include "core/script_language.h"
#include "cscript_function.h"
class GDScriptNativeClass : public Reference {
GDCLASS(GDScriptNativeClass, Reference);
StringName name;
protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
static void _bind_methods();
public:
_FORCE_INLINE_ const StringName &get_name() const { return name; }
Variant _new();
Object *instance();
GDScriptNativeClass(const StringName &p_name);
};
class GDScript : public Script {
GDCLASS(GDScript, Script);
bool tool;
bool valid;
struct MemberInfo {
int index;
StringName setter;
StringName getter;
MultiplayerAPI::RPCMode rpc_mode;
GDScriptDataType data_type;
};
friend class GDScriptInstance;
friend class GDScriptFunction;
friend class GDScriptCompiler;
friend class GDScriptFunctions;
friend class GDScriptLanguage;
Ref<GDScriptNativeClass> native;
Ref<GDScript> base;
GDScript *_base; //fast pointer access
GDScript *_owner; //for subclasses
Set<StringName> members; //members are just indices to the instanced script.
Map<StringName, Variant> constants;
Map<StringName, GDScriptFunction *> member_functions;
Map<StringName, MemberInfo> member_indices; //members are just indices to the instanced script.
Map<StringName, Ref<GDScript>> subclasses;
Map<StringName, Vector<StringName>> _signals;
#ifdef TOOLS_ENABLED
Map<StringName, int> member_lines;
Map<StringName, Variant> member_default_values;
List<PropertyInfo> members_cache;
Map<StringName, Variant> member_default_values_cache;
Ref<GDScript> base_cache;
Set<ObjectID> inheriters_cache;
bool source_changed_cache;
bool placeholder_fallback_enabled;
void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
#endif
Map<StringName, PropertyInfo> member_info;
GDScriptFunction *initializer; //direct pointer to _init , faster to locate
int subclass_count;
Set<Object *> instances;
//exported members
String source;
String path;
String name;
String fully_qualified_name;
SelfList<GDScript> script_list;
SelfList<GDScriptFunctionState>::List pending_func_states;
void _clear_pending_func_states();
GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_isref, Variant::CallError &r_error);
void _set_subclass_path(Ref<GDScript> &p_sc, const String &p_path);
String _get_debug_path() const;
#ifdef TOOLS_ENABLED
Set<PlaceHolderScriptInstance *> placeholders;
//void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder);
#endif
#ifdef DEBUG_ENABLED
Map<ObjectID, List<Pair<StringName, Variant>>> pending_reload_state;
#endif
bool _update_exports(bool *r_err = nullptr, bool p_recursive_call = false, PlaceHolderScriptInstance *p_instance_to_update = nullptr);
void _save_orphaned_subclasses();
protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
bool _set(const StringName &p_name, const Variant &p_value);
void _get_property_list(List<PropertyInfo> *p_properties) const;
Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
//void call_multilevel(const StringName& p_method,const Variant** p_args,int p_argcount);
static void _bind_methods();
public:
virtual bool is_valid() const {
return valid;
}
bool inherits_script(const Ref<Script> &p_script) const;
const Map<StringName, Ref<GDScript>> &get_subclasses() const {
return subclasses;
}
const Map<StringName, Variant> &get_constants() const {
return constants;
}
const Set<StringName> &get_members() const {
return members;
}
const GDScriptDataType &get_member_type(const StringName &p_member) const {
CRASH_COND(!member_indices.has(p_member));
return member_indices[p_member].data_type;
}
const Map<StringName, GDScriptFunction *> &get_member_functions() const {
return member_functions;
}
const Ref<GDScriptNativeClass> &get_native() const {
return native;
}
const String &get_script_class_name() const {
return name;
}
virtual bool has_script_signal(const StringName &p_signal) const;
virtual void get_script_signal_list(List<MethodInfo> *r_signals) const;
bool is_tool() const {
return tool;
}
Ref<GDScript> get_base() const;
const Map<StringName, MemberInfo> &debug_get_member_indices() const {
return member_indices;
}
const Map<StringName, GDScriptFunction *> &debug_get_member_functions() const; //this is debug only
StringName debug_get_member_by_index(int p_idx) const;
Variant _new(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
virtual bool can_instance() const;
virtual Ref<Script> get_base_script() const;
virtual StringName get_instance_base_type() const; // this may not work in all scripts, will return empty if so
virtual ScriptInstance *instance_create(Object *p_this);
virtual PlaceHolderScriptInstance *placeholder_instance_create(Object *p_this);
virtual bool instance_has(const Object *p_this) const;
virtual bool has_source_code() const;
virtual String get_source_code() const;
virtual void set_source_code(const String &p_code);
virtual void update_exports();
virtual Error reload(bool p_keep_state = false);
void set_script_path(const String &p_path) {
path = p_path;
} //because subclasses need a path too...
Error load_source_code(const String &p_path);
Error load_byte_code(const String &p_path);
Vector<uint8_t> get_as_byte_code() const;
bool get_property_default_value(const StringName &p_property, Variant &r_value) const;
virtual void get_script_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName &p_method) const;
virtual MethodInfo get_method_info(const StringName &p_method) const;
virtual void get_script_property_list(List<PropertyInfo> *p_list) const;
virtual ScriptLanguage *get_language() const;
virtual int get_member_line(const StringName &p_member) const {
#ifdef TOOLS_ENABLED
if (member_lines.has(p_member)) {
return member_lines[p_member];
}
#endif
return -1;
}
virtual void get_constants(Map<StringName, Variant> *p_constants);
virtual void get_members(Set<StringName> *p_members);
#ifdef TOOLS_ENABLED
virtual bool is_placeholder_fallback_enabled() const {
return placeholder_fallback_enabled;
}
#endif
GDScript();
~GDScript();
};
class GDScriptInstance : public ScriptInstance {
friend class GDScript;
friend class GDScriptFunction;
friend class GDScriptFunctions;
friend class GDScriptCompiler;
Object *owner;
Ref<GDScript> script;
#ifdef DEBUG_ENABLED
Map<StringName, int> member_indices_cache; //used only for hot script reloading
#endif
Vector<Variant> members;
bool base_ref;
SelfList<GDScriptFunctionState>::List pending_func_states;
void _ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount);
public:
virtual Object *get_owner() {
return owner;
}
virtual bool set(const StringName &p_name, const Variant &p_value);
virtual bool get(const StringName &p_name, Variant &r_ret) const;
virtual void get_property_list(List<PropertyInfo> *p_properties) const;
virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const;
virtual void get_method_list(List<MethodInfo> *p_list) const;
virtual bool has_method(const StringName &p_method) const;
virtual Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);
virtual void call_multilevel(const StringName &p_method, const Variant **p_args, int p_argcount);
virtual void call_multilevel_reversed(const StringName &p_method, const Variant **p_args, int p_argcount);
Variant debug_get_member_by_index(int p_idx) const {
return members[p_idx];
}
virtual void notification(int p_notification);
String to_string(bool *r_valid);
virtual Ref<Script> get_script() const;
virtual ScriptLanguage *get_language();
void reload_members();
virtual MultiplayerAPI::RPCMode get_rpc_mode(const StringName &p_method) const;
virtual MultiplayerAPI::RPCMode get_rset_mode(const StringName &p_variable) const;
GDScriptInstance();
~GDScriptInstance();
};
#ifdef DEBUG_ENABLED
struct GDScriptWarning {
enum Code {
UNASSIGNED_VARIABLE, // Variable used but never assigned
UNASSIGNED_VARIABLE_OP_ASSIGN, // Variable never assigned but used in an assignment operation (+=, *=, etc)
UNUSED_VARIABLE, // Local variable is declared but never used
SHADOWED_VARIABLE, // Variable name shadowed by other variable
UNUSED_CLASS_VARIABLE, // Class variable is declared but never used in the file
UNUSED_ARGUMENT, // Function argument is never used
UNREACHABLE_CODE, // Code after a return statement
STANDALONE_EXPRESSION, // Expression not assigned to a variable
VOID_ASSIGNMENT, // Function returns void but it's assigned to a variable
NARROWING_CONVERSION, // Float value into an integer slot, precision is lost
FUNCTION_MAY_YIELD, // Typed assign of function call that yields (it may return a function state)
VARIABLE_CONFLICTS_FUNCTION, // Variable has the same name of a function
FUNCTION_CONFLICTS_VARIABLE, // Function has the same name of a variable
FUNCTION_CONFLICTS_CONSTANT, // Function has the same name of a constant
INCOMPATIBLE_TERNARY, // Possible values of a ternary if are not mutually compatible
UNUSED_SIGNAL, // Signal is defined but never emitted
RETURN_VALUE_DISCARDED, // Function call returns something but the value isn't used
PROPERTY_USED_AS_FUNCTION, // Function not found, but there's a property with the same name
CONSTANT_USED_AS_FUNCTION, // Function not found, but there's a constant with the same name
FUNCTION_USED_AS_PROPERTY, // Property not found, but there's a function with the same name
INTEGER_DIVISION, // Integer divide by integer, decimal part is discarded
UNSAFE_PROPERTY_ACCESS, // Property not found in the detected type (but can be in subtypes)
UNSAFE_METHOD_ACCESS, // Function not found in the detected type (but can be in subtypes)
UNSAFE_CAST, // Cast used in an unknown type
UNSAFE_CALL_ARGUMENT, // Function call argument is of a supertype of the require argument
DEPRECATED_KEYWORD, // The keyword is deprecated and should be replaced
STANDALONE_TERNARY, // Return value of ternary expression is discarded
EXPORT_HINT_TYPE_MISTMATCH, // The type of the variable's default value doesn't match its export hint
WARNING_MAX,
} code;
Vector<String> symbols;
int line;
String get_name() const;
String get_message() const;
static String get_name_from_code(Code p_code);
static Code get_code_from_name(const String &p_name);
GDScriptWarning() :
code(WARNING_MAX),
line(-1) {}
};
#endif // DEBUG_ENABLED
class GDScriptLanguage : public ScriptLanguage {
friend class GDScriptFunctionState;
static GDScriptLanguage *singleton;
Variant *_global_array;
Vector<Variant> global_array;
Map<StringName, int> globals;
Map<StringName, Variant> named_globals;
struct CallLevel {
Variant *stack;
GDScriptFunction *function;
GDScriptInstance *instance;
int *ip;
int *line;
};
int _debug_parse_err_line;
String _debug_parse_err_file;
String _debug_error;
int _debug_call_stack_pos;
int _debug_max_call_stack;
CallLevel *_call_stack;
void _add_global(const StringName &p_name, const Variant &p_value);
friend class GDScriptInstance;
Mutex lock;
friend class GDScript;
SelfList<GDScript>::List script_list;
friend class GDScriptFunction;
SelfList<GDScriptFunction>::List function_list;
bool profiling;
uint64_t script_frame_time;
Map<String, ObjectID> orphan_subclasses;
public:
int calls;
bool debug_break(const String &p_error, bool p_allow_continue = true);
bool debug_break_parse(const String &p_file, int p_line, const String &p_error);
_FORCE_INLINE_ void enter_function(GDScriptInstance *p_instance, GDScriptFunction *p_function, Variant *p_stack, int *p_ip, int *p_line) {
if (Thread::get_main_id() != Thread::get_caller_id()) {
return; //no support for other threads than main for now
}
if (ScriptDebugger::get_singleton()->get_lines_left() > 0 && ScriptDebugger::get_singleton()->get_depth() >= 0) {
ScriptDebugger::get_singleton()->set_depth(ScriptDebugger::get_singleton()->get_depth() + 1);
}
if (_debug_call_stack_pos >= _debug_max_call_stack) {
//stack overflow
_debug_error = "Stack Overflow (Stack Size: " + itos(_debug_max_call_stack) + ")";
ScriptDebugger::get_singleton()->debug(this);
return;
}
_call_stack[_debug_call_stack_pos].stack = p_stack;
_call_stack[_debug_call_stack_pos].instance = p_instance;
_call_stack[_debug_call_stack_pos].function = p_function;
_call_stack[_debug_call_stack_pos].ip = p_ip;
_call_stack[_debug_call_stack_pos].line = p_line;
_debug_call_stack_pos++;
}
_FORCE_INLINE_ void exit_function() {
if (Thread::get_main_id() != Thread::get_caller_id()) {
return; //no support for other threads than main for now
}
if (ScriptDebugger::get_singleton()->get_lines_left() > 0 && ScriptDebugger::get_singleton()->get_depth() >= 0) {
ScriptDebugger::get_singleton()->set_depth(ScriptDebugger::get_singleton()->get_depth() - 1);
}
if (_debug_call_stack_pos == 0) {
_debug_error = "Stack Underflow (Engine Bug)";
ScriptDebugger::get_singleton()->debug(this);
return;
}
_debug_call_stack_pos--;
}
virtual Vector<StackInfo> debug_get_current_stack_info() {
if (Thread::get_main_id() != Thread::get_caller_id()) {
return Vector<StackInfo>();
}
Vector<StackInfo> csi;
csi.resize(_debug_call_stack_pos);
for (int i = 0; i < _debug_call_stack_pos; i++) {
csi.write[_debug_call_stack_pos - i - 1].line = _call_stack[i].line ? *_call_stack[i].line : 0;
if (_call_stack[i].function) {
csi.write[_debug_call_stack_pos - i - 1].func = _call_stack[i].function->get_name();
csi.write[_debug_call_stack_pos - i - 1].file = _call_stack[i].function->get_script()->get_path();
}
}
return csi;
}
struct {
StringName _init;
StringName _notification;
StringName _set;
StringName _get;
StringName _get_property_list;
StringName _script_source;
} strings;
_FORCE_INLINE_ int get_global_array_size() const { return global_array.size(); }
_FORCE_INLINE_ Variant *get_global_array() { return _global_array; }
_FORCE_INLINE_ const Map<StringName, int> &get_global_map() const { return globals; }
_FORCE_INLINE_ const Map<StringName, Variant> &get_named_globals_map() const { return named_globals; }
_FORCE_INLINE_ static GDScriptLanguage *get_singleton() { return singleton; }
virtual String get_name() const;
/* LANGUAGE FUNCTIONS */
virtual void init();
virtual String get_type() const;
virtual String get_extension() const;
virtual Error execute_file(const String &p_path);
virtual void finish();
/* EDITOR FUNCTIONS */
virtual void get_reserved_words(List<String> *p_words) const;
virtual bool is_control_flow_keyword(String p_keywords) const;
virtual void get_comment_delimiters(List<String> *p_delimiters) const;
virtual void get_string_delimiters(List<String> *p_delimiters) const;
virtual String _get_processed_template(const String &p_template, const String &p_base_class_name) const;
virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
virtual bool is_using_templates();
virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script);
virtual bool validate(const String &p_script, int &r_line_error, int &r_col_error, String &r_test_error, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const;
virtual Script *create_script() const;
virtual bool has_named_classes() const;
virtual bool supports_builtin_mode() const;
virtual bool can_inherit_from_file() { return true; }
virtual int find_function(const String &p_function, const String &p_code) const;
virtual String make_function(const String &p_class, const String &p_name, const PoolStringArray &p_args) const;
virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint);
#ifdef TOOLS_ENABLED
virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result);
#endif
virtual String _get_indentation() const;
virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const;
virtual void add_global_constant(const StringName &p_variable, const Variant &p_value);
virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value);
virtual void remove_named_global_constant(const StringName &p_name);
/* DEBUGGER FUNCTIONS */
virtual String debug_get_error() const;
virtual int debug_get_stack_level_count() const;
virtual int debug_get_stack_level_line(int p_level) const;
virtual String debug_get_stack_level_function(int p_level) const;
virtual String debug_get_stack_level_source(int p_level) const;
virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
virtual ScriptInstance *debug_get_stack_level_instance(int p_level);
virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1);
virtual void reload_all_scripts();
virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload);
virtual void frame();
virtual void get_public_functions(List<MethodInfo> *p_functions) const;
virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const;
virtual void profiling_start();
virtual void profiling_stop();
virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max);
virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max);
/* LOADER FUNCTIONS */
virtual void get_recognized_extensions(List<String> *p_extensions) const;
/* GLOBAL CLASSES */
virtual bool handles_global_class_type(const String &p_type) const;
virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const;
void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass);
Ref<GDScript> get_orphan_subclass(const String &p_qualified_name);
GDScriptLanguage();
~GDScriptLanguage();
};
class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
virtual void get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types = false);
};
class ResourceFormatSaverGDScript : public ResourceFormatSaver {
public:
virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
virtual bool recognize(const RES &p_resource) const;
};
#endif // GDSCRIPT_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,169 @@
#ifndef CSCRIPT_COMPILER_H
#define CSCRIPT_COMPILER_H
/*************************************************************************/
/* gdscript_compiler.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/set.h"
#include "cscript.h"
#include "cscript_parser.h"
class GDScriptCompiler {
const GDScriptParser *parser;
Set<GDScript *> parsed_classes;
Set<GDScript *> parsing_classes;
GDScript *main_script;
struct CodeGen {
GDScript *script;
const GDScriptParser::ClassNode *class_node;
const GDScriptParser::FunctionNode *function_node;
bool debug_stack;
List<Map<StringName, int>> stack_id_stack;
Map<StringName, int> stack_identifiers;
List<GDScriptFunction::StackDebug> stack_debug;
List<Map<StringName, int>> block_identifier_stack;
Map<StringName, int> block_identifiers;
void add_stack_identifier(const StringName &p_id, int p_stackpos) {
stack_identifiers[p_id] = p_stackpos;
if (debug_stack) {
block_identifiers[p_id] = p_stackpos;
GDScriptFunction::StackDebug sd;
sd.added = true;
sd.line = current_line;
sd.identifier = p_id;
sd.pos = p_stackpos;
stack_debug.push_back(sd);
}
}
void push_stack_identifiers() {
stack_id_stack.push_back(stack_identifiers);
if (debug_stack) {
block_identifier_stack.push_back(block_identifiers);
block_identifiers.clear();
}
}
void pop_stack_identifiers() {
stack_identifiers = stack_id_stack.back()->get();
stack_id_stack.pop_back();
if (debug_stack) {
for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) {
GDScriptFunction::StackDebug sd;
sd.added = false;
sd.identifier = E->key();
sd.line = current_line;
sd.pos = E->get();
stack_debug.push_back(sd);
}
block_identifiers = block_identifier_stack.back()->get();
block_identifier_stack.pop_back();
}
}
HashMap<Variant, int, VariantHasher, VariantComparator> constant_map;
Map<StringName, int> name_map;
#ifdef TOOLS_ENABLED
Vector<StringName> named_globals;
#endif
int get_name_map_pos(const StringName &p_identifier) {
int ret;
if (!name_map.has(p_identifier)) {
ret = name_map.size();
name_map[p_identifier] = ret;
} else {
ret = name_map[p_identifier];
}
return ret;
}
int get_constant_pos(const Variant &p_constant) {
if (constant_map.has(p_constant)) {
return constant_map[p_constant];
}
int pos = constant_map.size();
constant_map[p_constant] = pos;
return pos;
}
Vector<int> opcodes;
void alloc_stack(int p_level) {
if (p_level >= stack_max) {
stack_max = p_level + 1;
}
}
void alloc_call(int p_params) {
if (p_params >= call_max) {
call_max = p_params;
}
}
int current_line;
int stack_max;
int call_max;
};
bool _is_class_member_property(CodeGen &codegen, const StringName &p_name);
bool _is_class_member_property(GDScript *owner, const StringName &p_name);
void _set_error(const String &p_error, const GDScriptParser::Node *p_node);
bool _create_unary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level);
bool _create_binary_operator(CodeGen &codegen, const GDScriptParser::OperatorNode *on, Variant::Operator op, int p_stack_level, bool p_initializer = false, int p_index_addr = 0);
GDScriptDataType _gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner = nullptr) const;
int _parse_assign_right_expression(CodeGen &codegen, const GDScriptParser::OperatorNode *p_expression, int p_stack_level, int p_index_addr = 0);
int _parse_expression(CodeGen &codegen, const GDScriptParser::Node *p_expression, int p_stack_level, bool p_root = false, bool p_initializer = false, int p_index_addr = 0);
Error _parse_block(CodeGen &codegen, const GDScriptParser::BlockNode *p_block, int p_stack_level = 0, int p_break_addr = -1, int p_continue_addr = -1);
Error _parse_function(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false);
Error _parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
Error _parse_class_blocks(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
void _make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
int err_line;
int err_column;
StringName source;
String error;
public:
Error compile(const GDScriptParser *p_parser, GDScript *p_script, bool p_keep_state = false);
String get_error() const;
int get_error_line() const;
int get_error_column() const;
GDScriptCompiler();
};
#endif // GDSCRIPT_COMPILER_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,389 @@
#ifndef CSCRIPT_FUNCTION_H
#define CSCRIPT_FUNCTION_H
/*************************************************************************/
/* gdscript_function.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/os/thread.h"
#include "core/pair.h"
#include "core/reference.h"
#include "core/script_language.h"
#include "core/self_list.h"
#include "core/string_name.h"
#include "core/variant.h"
class GDScriptInstance;
class GDScript;
struct GDScriptDataType {
bool has_type;
enum {
UNINITIALIZED,
BUILTIN,
NATIVE,
SCRIPT,
GDSCRIPT,
} kind;
Variant::Type builtin_type;
StringName native_type;
Script *script_type;
Ref<Script> script_type_ref;
bool is_type(const Variant &p_variant, bool p_allow_implicit_conversion = false) const {
if (!has_type) {
return true; // Can't type check
}
switch (kind) {
case UNINITIALIZED:
break;
case BUILTIN: {
Variant::Type var_type = p_variant.get_type();
bool valid = builtin_type == var_type;
if (!valid && p_allow_implicit_conversion) {
valid = Variant::can_convert_strict(var_type, builtin_type);
}
return valid;
} break;
case NATIVE: {
if (p_variant.get_type() == Variant::NIL) {
return true;
}
if (p_variant.get_type() != Variant::OBJECT) {
return false;
}
Object *obj = p_variant.operator Object *();
if (!obj) {
return false;
}
if (!ClassDB::is_parent_class(obj->get_class_name(), native_type)) {
// Try with underscore prefix
StringName underscore_native_type = "_" + native_type;
if (!ClassDB::is_parent_class(obj->get_class_name(), underscore_native_type)) {
return false;
}
}
return true;
} break;
case SCRIPT:
case GDSCRIPT: {
if (p_variant.get_type() == Variant::NIL) {
return true;
}
if (p_variant.get_type() != Variant::OBJECT) {
return false;
}
Object *obj = p_variant.operator Object *();
if (!obj) {
return false;
}
Ref<Script> base = obj && obj->get_script_instance() ? obj->get_script_instance()->get_script() : nullptr;
bool valid = false;
while (base.is_valid()) {
if (base == script_type) {
valid = true;
break;
}
base = base->get_base_script();
}
return valid;
} break;
}
return false;
}
operator PropertyInfo() const {
PropertyInfo info;
if (has_type) {
switch (kind) {
case UNINITIALIZED:
break;
case BUILTIN: {
info.type = builtin_type;
} break;
case NATIVE: {
info.type = Variant::OBJECT;
info.class_name = native_type;
} break;
case SCRIPT:
case GDSCRIPT: {
info.type = Variant::OBJECT;
info.class_name = script_type->get_instance_base_type();
} break;
}
} else {
info.type = Variant::NIL;
info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
}
return info;
}
GDScriptDataType() :
has_type(false),
kind(UNINITIALIZED),
builtin_type(Variant::NIL),
script_type(nullptr) {}
};
class GDScriptFunction {
public:
enum Opcode {
OPCODE_OPERATOR,
OPCODE_EXTENDS_TEST,
OPCODE_IS_BUILTIN,
OPCODE_SET,
OPCODE_GET,
OPCODE_SET_NAMED,
OPCODE_GET_NAMED,
OPCODE_SET_MEMBER,
OPCODE_GET_MEMBER,
OPCODE_ASSIGN,
OPCODE_ASSIGN_TRUE,
OPCODE_ASSIGN_FALSE,
OPCODE_ASSIGN_TYPED_BUILTIN,
OPCODE_ASSIGN_TYPED_NATIVE,
OPCODE_ASSIGN_TYPED_SCRIPT,
OPCODE_CAST_TO_BUILTIN,
OPCODE_CAST_TO_NATIVE,
OPCODE_CAST_TO_SCRIPT,
OPCODE_CONSTRUCT, //only for basic types!!
OPCODE_CONSTRUCT_ARRAY,
OPCODE_CONSTRUCT_DICTIONARY,
OPCODE_CALL,
OPCODE_CALL_RETURN,
OPCODE_CALL_BUILT_IN,
OPCODE_CALL_SELF,
OPCODE_CALL_SELF_BASE,
OPCODE_YIELD,
OPCODE_YIELD_SIGNAL,
OPCODE_YIELD_RESUME,
OPCODE_JUMP,
OPCODE_JUMP_IF,
OPCODE_JUMP_IF_NOT,
OPCODE_JUMP_TO_DEF_ARGUMENT,
OPCODE_RETURN,
OPCODE_ITERATE_BEGIN,
OPCODE_ITERATE,
OPCODE_ASSERT,
OPCODE_BREAKPOINT,
OPCODE_LINE,
OPCODE_END
};
enum Address {
ADDR_BITS = 24,
ADDR_MASK = ((1 << ADDR_BITS) - 1),
ADDR_TYPE_MASK = ~ADDR_MASK,
ADDR_TYPE_SELF = 0,
ADDR_TYPE_CLASS = 1,
ADDR_TYPE_MEMBER = 2,
ADDR_TYPE_CLASS_CONSTANT = 3,
ADDR_TYPE_LOCAL_CONSTANT = 4,
ADDR_TYPE_STACK = 5,
ADDR_TYPE_STACK_VARIABLE = 6,
ADDR_TYPE_GLOBAL = 7,
ADDR_TYPE_NAMED_GLOBAL = 8,
ADDR_TYPE_NIL = 9
};
struct StackDebug {
int line;
int pos;
bool added;
StringName identifier;
};
private:
friend class GDScriptCompiler;
StringName source;
mutable Variant nil;
mutable Variant *_constants_ptr;
int _constant_count;
const StringName *_global_names_ptr;
int _global_names_count;
#ifdef TOOLS_ENABLED
const StringName *_named_globals_ptr;
int _named_globals_count;
#endif
const int *_default_arg_ptr;
int _default_arg_count;
const int *_code_ptr;
int _code_size;
int _argument_count;
int _stack_size;
int _call_size;
int _initial_line;
bool _static;
MultiplayerAPI::RPCMode rpc_mode;
GDScript *_script;
StringName name;
Vector<Variant> constants;
Vector<StringName> global_names;
#ifdef TOOLS_ENABLED
Vector<StringName> named_globals;
#endif
Vector<int> default_arguments;
Vector<int> code;
Vector<GDScriptDataType> argument_types;
GDScriptDataType return_type;
#ifdef TOOLS_ENABLED
Vector<StringName> arg_names;
#endif
List<StackDebug> stack_debug;
_FORCE_INLINE_ Variant *_get_variant(int p_address, GDScriptInstance *p_instance, GDScript *p_script, Variant &self, Variant &static_ref, Variant *p_stack, String &r_error) const;
_FORCE_INLINE_ String _get_call_error(const Variant::CallError &p_err, const String &p_where, const Variant **argptrs) const;
friend class GDScriptLanguage;
SelfList<GDScriptFunction> function_list;
#ifdef DEBUG_ENABLED
CharString func_cname;
const char *_func_cname;
struct Profile {
StringName signature;
uint64_t call_count;
uint64_t self_time;
uint64_t total_time;
uint64_t frame_call_count;
uint64_t frame_self_time;
uint64_t frame_total_time;
uint64_t last_frame_call_count;
uint64_t last_frame_self_time;
uint64_t last_frame_total_time;
} profile;
#endif
public:
struct CallState {
GDScript *script;
GDScriptInstance *instance;
#ifdef DEBUG_ENABLED
StringName function_name;
String script_path;
#endif
Vector<uint8_t> stack;
int stack_size;
Variant self;
uint32_t alloca_size;
int ip;
int line;
int defarg;
Variant result;
};
_FORCE_INLINE_ bool is_static() const {
return _static;
}
const int *get_code() const; //used for debug
int get_code_size() const;
Variant get_constant(int p_idx) const;
StringName get_global_name(int p_idx) const;
StringName get_name() const;
int get_max_stack_size() const;
int get_default_argument_count() const;
int get_default_argument_addr(int p_idx) const;
GDScriptDataType get_return_type() const;
GDScriptDataType get_argument_type(int p_idx) const;
GDScript *get_script() const {
return _script;
}
StringName get_source() const {
return source;
}
void debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const;
_FORCE_INLINE_ bool is_empty() const {
return _code_size == 0;
}
int get_argument_count() const {
return _argument_count;
}
StringName get_argument_name(int p_idx) const {
#ifdef TOOLS_ENABLED
ERR_FAIL_INDEX_V(p_idx, arg_names.size(), StringName());
return arg_names[p_idx];
#else
return StringName();
#endif
}
Variant get_default_argument(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, default_arguments.size(), Variant());
return default_arguments[p_idx];
}
Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Variant::CallError &r_err, CallState *p_state = nullptr);
_FORCE_INLINE_ MultiplayerAPI::RPCMode get_rpc_mode() const {
return rpc_mode;
}
GDScriptFunction();
~GDScriptFunction();
};
class GDScriptFunctionState : public Reference {
GDCLASS(GDScriptFunctionState, Reference);
friend class GDScriptFunction;
GDScriptFunction *function;
GDScriptFunction::CallState state;
Variant _signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error);
Ref<GDScriptFunctionState> first_state;
SelfList<GDScriptFunctionState> scripts_list;
SelfList<GDScriptFunctionState> instances_list;
protected:
static void _bind_methods();
public:
bool is_valid(bool p_extended_check = false) const;
Variant resume(const Variant &p_arg = Variant());
void _clear_stack();
GDScriptFunctionState();
~GDScriptFunctionState();
};
#endif // GDSCRIPT_FUNCTION_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,138 @@
#ifndef CSCRIPT_FUNCTIONS_H
#define CSCRIPT_FUNCTIONS_H
/*************************************************************************/
/* gdscript_functions.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/variant.h"
class GDScriptFunctions {
public:
enum Function {
MATH_SIN,
MATH_COS,
MATH_TAN,
MATH_SINH,
MATH_COSH,
MATH_TANH,
MATH_ASIN,
MATH_ACOS,
MATH_ATAN,
MATH_ATAN2,
MATH_SQRT,
MATH_FMOD,
MATH_FPOSMOD,
MATH_POSMOD,
MATH_FLOOR,
MATH_CEIL,
MATH_ROUND,
MATH_ABS,
MATH_SIGN,
MATH_POW,
MATH_LOG,
MATH_EXP,
MATH_ISNAN,
MATH_ISINF,
MATH_ISEQUALAPPROX,
MATH_ISZEROAPPROX,
MATH_EASE,
MATH_DECIMALS,
MATH_STEP_DECIMALS,
MATH_STEPIFY,
MATH_LERP,
MATH_LERP_ANGLE,
MATH_INVERSE_LERP,
MATH_RANGE_LERP,
MATH_SMOOTHSTEP,
MATH_MOVE_TOWARD,
MATH_DECTIME,
MATH_RANDOMIZE,
MATH_RAND,
MATH_RANDF,
MATH_RANDOM,
MATH_SEED,
MATH_RANDSEED,
MATH_DEG2RAD,
MATH_RAD2DEG,
MATH_LINEAR2DB,
MATH_DB2LINEAR,
MATH_POLAR2CARTESIAN,
MATH_CARTESIAN2POLAR,
MATH_WRAP,
MATH_WRAPF,
LOGIC_MAX,
LOGIC_MIN,
LOGIC_CLAMP,
LOGIC_NEAREST_PO2,
OBJ_WEAKREF,
FUNC_FUNCREF,
TYPE_CONVERT,
TYPE_OF,
TYPE_EXISTS,
TEXT_CHAR,
TEXT_ORD,
TEXT_STR,
TEXT_PRINT,
TEXT_PRINT_TABBED,
TEXT_PRINT_SPACED,
TEXT_PRINTERR,
TEXT_PRINTRAW,
TEXT_PRINT_DEBUG,
PUSH_ERROR,
PUSH_WARNING,
VAR_TO_STR,
STR_TO_VAR,
VAR_TO_BYTES,
BYTES_TO_VAR,
GEN_RANGE,
RESOURCE_LOAD,
INST2DICT,
DICT2INST,
VALIDATE_JSON,
PARSE_JSON,
TO_JSON,
HASH,
COLOR8,
COLORN,
PRINT_STACK,
GET_STACK,
INSTANCE_FROM_ID,
LEN,
IS_INSTANCE_VALID,
DEEP_EQUAL,
FUNC_MAX
};
static const char *get_func_name(Function p_func);
static void call(Function p_func, const Variant **p_args, int p_arg_count, Variant &r_ret, Variant::CallError &r_error);
static bool is_deterministic(Function p_func);
static MethodInfo get_info(Function p_func);
};
#endif // GDSCRIPT_FUNCTIONS_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,699 @@
#ifndef CSCRIPT_PARSER_H
#define CSCRIPT_PARSER_H
/*************************************************************************/
/* gdscript_parser.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/map.h"
#include "core/object.h"
#include "core/script_language.h"
#include "cscript_functions.h"
#include "cscript_tokenizer.h"
struct GDScriptDataType;
struct GDScriptWarning;
class GDScriptParser {
public:
struct ClassNode;
struct DataType {
enum {
BUILTIN,
NATIVE,
SCRIPT,
GDSCRIPT,
CLASS,
UNRESOLVED
} kind;
bool has_type;
bool is_constant;
bool is_meta_type; // Whether the value can be used as a type
bool infer_type;
bool may_yield; // For function calls
Variant::Type builtin_type;
StringName native_type;
Ref<Script> script_type;
ClassNode *class_type;
String to_string() const;
bool operator==(const DataType &other) const {
if (!has_type || !other.has_type) {
return true; // Can be considered equal for parsing purpose
}
if (kind != other.kind) {
return false;
}
switch (kind) {
case BUILTIN: {
return builtin_type == other.builtin_type;
} break;
case NATIVE: {
return native_type == other.native_type;
} break;
case GDSCRIPT:
case SCRIPT: {
return script_type == other.script_type;
} break;
case CLASS: {
return class_type == other.class_type;
} break;
case UNRESOLVED: {
} break;
}
return false;
}
DataType() :
kind(UNRESOLVED),
has_type(false),
is_constant(false),
is_meta_type(false),
infer_type(false),
may_yield(false),
builtin_type(Variant::NIL),
class_type(nullptr) {}
};
struct Node {
enum Type {
TYPE_CLASS,
TYPE_FUNCTION,
TYPE_BUILT_IN_FUNCTION,
TYPE_BLOCK,
TYPE_IDENTIFIER,
TYPE_TYPE,
TYPE_CONSTANT,
TYPE_ARRAY,
TYPE_DICTIONARY,
TYPE_SELF,
TYPE_OPERATOR,
TYPE_CONTROL_FLOW,
TYPE_LOCAL_VAR,
TYPE_CAST,
TYPE_ASSERT,
TYPE_BREAKPOINT,
TYPE_NEWLINE,
};
Node *next;
int line;
int column;
Type type;
virtual DataType get_datatype() const { return DataType(); }
virtual void set_datatype(const DataType &p_datatype) {}
virtual ~Node() {}
};
struct FunctionNode;
struct BlockNode;
struct ConstantNode;
struct LocalVarNode;
struct OperatorNode;
struct ClassNode : public Node {
bool tool;
StringName name;
bool extends_used;
bool classname_used;
StringName extends_file;
Vector<StringName> extends_class;
DataType base_type;
String icon_path;
struct Member {
PropertyInfo _export;
#ifdef TOOLS_ENABLED
Variant default_value;
#endif
StringName identifier;
DataType data_type;
StringName setter;
StringName getter;
int line;
Node *expression;
OperatorNode *initial_assignment;
MultiplayerAPI::RPCMode rpc_mode;
int usages;
};
struct Constant {
Node *expression;
DataType type;
};
struct Signal {
StringName name;
Vector<StringName> arguments;
int emissions;
int line;
};
Vector<ClassNode *> subclasses;
Vector<Member> variables;
Map<StringName, Constant> constant_expressions;
Vector<FunctionNode *> functions;
Vector<FunctionNode *> static_functions;
Vector<Signal> _signals;
BlockNode *initializer;
BlockNode *ready;
ClassNode *owner;
//Vector<Node*> initializers;
int end_line;
ClassNode() {
tool = false;
type = TYPE_CLASS;
extends_used = false;
classname_used = false;
end_line = -1;
owner = nullptr;
}
};
struct FunctionNode : public Node {
bool _static;
MultiplayerAPI::RPCMode rpc_mode;
bool has_yield;
bool has_unreachable_code;
StringName name;
DataType return_type;
Vector<StringName> arguments;
Vector<DataType> argument_types;
Vector<Node *> default_values;
BlockNode *body;
#ifdef DEBUG_ENABLED
Vector<int> arguments_usage;
#endif // DEBUG_ENABLED
virtual DataType get_datatype() const {
return return_type;
}
virtual void set_datatype(const DataType &p_datatype) {
return_type = p_datatype;
}
int get_required_argument_count() {
return arguments.size() - default_values.size();
}
FunctionNode() {
type = TYPE_FUNCTION;
_static = false;
rpc_mode = MultiplayerAPI::RPC_MODE_DISABLED;
has_yield = false;
has_unreachable_code = false;
}
};
struct BlockNode : public Node {
ClassNode *parent_class;
BlockNode *parent_block;
Vector<Node *> statements;
Map<StringName, LocalVarNode *> variables;
bool has_return = false;
bool can_break = false;
bool can_continue = false;
Node *if_condition; //tiny hack to improve code completion on if () blocks
//the following is useful for code completion
List<BlockNode *> sub_blocks;
int end_line;
BlockNode() {
if_condition = nullptr;
type = TYPE_BLOCK;
end_line = -1;
parent_block = nullptr;
parent_class = nullptr;
}
};
struct TypeNode : public Node {
Variant::Type vtype;
TypeNode() { type = TYPE_TYPE; }
};
struct BuiltInFunctionNode : public Node {
GDScriptFunctions::Function function;
BuiltInFunctionNode() { type = TYPE_BUILT_IN_FUNCTION; }
};
struct IdentifierNode : public Node {
StringName name;
BlockNode *declared_block; // Simplify lookup by checking if it is declared locally
DataType datatype;
virtual DataType get_datatype() const { return datatype; }
virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
IdentifierNode() {
type = TYPE_IDENTIFIER;
declared_block = nullptr;
}
};
struct LocalVarNode : public Node {
StringName name;
Node *assign;
OperatorNode *assign_op;
int assignments;
int usages;
DataType datatype;
virtual DataType get_datatype() const { return datatype; }
virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
LocalVarNode() {
type = TYPE_LOCAL_VAR;
assign = nullptr;
assign_op = nullptr;
assignments = 0;
usages = 0;
}
};
struct ConstantNode : public Node {
Variant value;
DataType datatype;
virtual DataType get_datatype() const { return datatype; }
virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
ConstantNode() { type = TYPE_CONSTANT; }
};
struct ArrayNode : public Node {
Vector<Node *> elements;
DataType datatype;
virtual DataType get_datatype() const { return datatype; }
virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
ArrayNode() {
type = TYPE_ARRAY;
datatype.has_type = true;
datatype.kind = DataType::BUILTIN;
datatype.builtin_type = Variant::ARRAY;
}
};
struct DictionaryNode : public Node {
struct Pair {
Node *key;
Node *value;
};
Vector<Pair> elements;
DataType datatype;
virtual DataType get_datatype() const { return datatype; }
virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
DictionaryNode() {
type = TYPE_DICTIONARY;
datatype.has_type = true;
datatype.kind = DataType::BUILTIN;
datatype.builtin_type = Variant::DICTIONARY;
}
};
struct SelfNode : public Node {
SelfNode() { type = TYPE_SELF; }
};
struct OperatorNode : public Node {
enum Operator {
//call/constructor operator
OP_CALL,
OP_PARENT_CALL,
OP_YIELD,
OP_IS,
OP_IS_BUILTIN,
//indexing operator
OP_INDEX,
OP_INDEX_NAMED,
//unary operators
OP_NEG,
OP_POS,
OP_NOT,
OP_BIT_INVERT,
//binary operators (in precedence order)
OP_IN,
OP_EQUAL,
OP_NOT_EQUAL,
OP_LESS,
OP_LESS_EQUAL,
OP_GREATER,
OP_GREATER_EQUAL,
OP_AND,
OP_OR,
OP_ADD,
OP_SUB,
OP_MUL,
OP_DIV,
OP_MOD,
OP_SHIFT_LEFT,
OP_SHIFT_RIGHT,
OP_INIT_ASSIGN,
OP_ASSIGN,
OP_ASSIGN_ADD,
OP_ASSIGN_SUB,
OP_ASSIGN_MUL,
OP_ASSIGN_DIV,
OP_ASSIGN_MOD,
OP_ASSIGN_SHIFT_LEFT,
OP_ASSIGN_SHIFT_RIGHT,
OP_ASSIGN_BIT_AND,
OP_ASSIGN_BIT_OR,
OP_ASSIGN_BIT_XOR,
OP_BIT_AND,
OP_BIT_OR,
OP_BIT_XOR,
//ternary operators
OP_TERNARY_IF,
OP_TERNARY_ELSE,
};
Operator op;
Vector<Node *> arguments;
DataType datatype;
virtual DataType get_datatype() const { return datatype; }
virtual void set_datatype(const DataType &p_datatype) { datatype = p_datatype; }
OperatorNode() { type = TYPE_OPERATOR; }
};
struct PatternNode : public Node {
enum PatternType {
PT_CONSTANT,
PT_BIND,
PT_DICTIONARY,
PT_ARRAY,
PT_IGNORE_REST,
PT_WILDCARD
};
PatternType pt_type;
Node *constant;
StringName bind;
Map<ConstantNode *, PatternNode *> dictionary;
Vector<PatternNode *> array;
};
struct PatternBranchNode : public Node {
Vector<PatternNode *> patterns;
BlockNode *body;
};
struct MatchNode : public Node {
Node *val_to_match;
Vector<PatternBranchNode *> branches;
struct CompiledPatternBranch {
Node *compiled_pattern;
BlockNode *body;
};
Vector<CompiledPatternBranch> compiled_pattern_branches;
};
struct ControlFlowNode : public Node {
enum CFType {
CF_IF,
CF_FOR,
CF_WHILE,
CF_BREAK,
CF_CONTINUE,
CF_RETURN,
CF_MATCH
};
CFType cf_type;
Vector<Node *> arguments;
BlockNode *body;
BlockNode *body_else;
MatchNode *match;
ControlFlowNode *_else; //used for if
ControlFlowNode() {
type = TYPE_CONTROL_FLOW;
cf_type = CF_IF;
body = nullptr;
body_else = nullptr;
}
};
struct CastNode : public Node {
Node *source_node;
DataType cast_type;
DataType return_type;
virtual DataType get_datatype() const { return return_type; }
virtual void set_datatype(const DataType &p_datatype) { return_type = p_datatype; }
CastNode() { type = TYPE_CAST; }
};
struct AssertNode : public Node {
Node *condition;
Node *message;
AssertNode() :
condition(nullptr),
message(nullptr) {
type = TYPE_ASSERT;
}
};
struct BreakpointNode : public Node {
BreakpointNode() { type = TYPE_BREAKPOINT; }
};
struct NewLineNode : public Node {
NewLineNode() { type = TYPE_NEWLINE; }
};
struct Expression {
bool is_op;
union {
OperatorNode::Operator op;
Node *node;
};
};
enum CompletionType {
COMPLETION_NONE,
COMPLETION_BUILT_IN_TYPE_CONSTANT,
COMPLETION_GET_NODE,
COMPLETION_FUNCTION,
COMPLETION_IDENTIFIER,
COMPLETION_EXTENDS,
COMPLETION_PARENT_FUNCTION,
COMPLETION_METHOD,
COMPLETION_CALL_ARGUMENTS,
COMPLETION_RESOURCE_PATH,
COMPLETION_INDEX,
COMPLETION_VIRTUAL_FUNC,
COMPLETION_YIELD,
COMPLETION_ASSIGN,
COMPLETION_TYPE_HINT,
COMPLETION_TYPE_HINT_INDEX,
};
private:
GDScriptTokenizer *tokenizer;
Node *head;
Node *list;
template <class T>
T *alloc_node();
bool validating;
bool for_completion;
int parenthesis;
bool error_set;
String error;
int error_line;
int error_column;
bool check_types;
bool dependencies_only;
List<String> dependencies;
#ifdef DEBUG_ENABLED
Set<int> *safe_lines;
#endif // DEBUG_ENABLED
#ifdef DEBUG_ENABLED
List<GDScriptWarning> warnings;
#endif // DEBUG_ENABLED
int pending_newline;
struct IndentLevel {
int indent;
int tabs;
bool is_mixed(IndentLevel other) {
return (
(indent == other.indent && tabs != other.tabs) ||
(indent > other.indent && tabs < other.tabs) ||
(indent < other.indent && tabs > other.tabs));
}
IndentLevel() :
indent(0),
tabs(0) {}
IndentLevel(int p_indent, int p_tabs) :
indent(p_indent),
tabs(p_tabs) {}
};
List<IndentLevel> indent_level;
String base_path;
String self_path;
ClassNode *current_class;
FunctionNode *current_function;
BlockNode *current_block;
bool _get_completable_identifier(CompletionType p_type, StringName &identifier);
void _make_completable_call(int p_arg);
CompletionType completion_type;
StringName completion_cursor;
Variant::Type completion_built_in_constant;
Node *completion_node;
ClassNode *completion_class;
FunctionNode *completion_function;
BlockNode *completion_block;
int completion_line;
int completion_argument;
bool completion_found;
bool completion_ident_is_call;
PropertyInfo current_export;
MultiplayerAPI::RPCMode rpc_mode;
void _set_error(const String &p_error, int p_line = -1, int p_column = -1);
#ifdef DEBUG_ENABLED
void _add_warning(int p_code, int p_line = -1, const String &p_symbol1 = String(), const String &p_symbol2 = String(), const String &p_symbol3 = String(), const String &p_symbol4 = String());
void _add_warning(int p_code, int p_line, const Vector<String> &p_symbols);
#endif // DEBUG_ENABLED
bool _recover_from_completion();
bool _parse_arguments(Node *p_parent, Vector<Node *> &p_args, bool p_static, bool p_can_codecomplete = false, bool p_parsing_constant = false);
bool _enter_indent_block(BlockNode *p_block = nullptr);
bool _parse_newline();
Node *_parse_expression(Node *p_parent, bool p_static, bool p_allow_assign = false, bool p_parsing_constant = false);
Node *_reduce_expression(Node *p_node, bool p_to_const = false);
Node *_parse_and_reduce_expression(Node *p_parent, bool p_static, bool p_reduce_const = false, bool p_allow_assign = false);
bool _reduce_export_var_type(Variant &p_value, int p_line = 0);
PatternNode *_parse_pattern(bool p_static);
void _parse_pattern_block(BlockNode *p_block, Vector<PatternBranchNode *> &p_branches, bool p_static);
void _transform_match_statment(MatchNode *p_match_statement);
void _generate_pattern(PatternNode *p_pattern, Node *p_node_to_match, Node *&p_resulting_node, Map<StringName, Node *> &p_bindings);
void _parse_block(BlockNode *p_block, bool p_static);
void _parse_extends(ClassNode *p_class);
void _parse_class(ClassNode *p_class);
bool _end_statement();
void _set_end_statement_error(String p_name);
void _determine_inheritance(ClassNode *p_class, bool p_recursive = true);
bool _parse_type(DataType &r_type, bool p_can_be_void = false);
DataType _resolve_type(const DataType &p_source, int p_line);
DataType _type_from_variant(const Variant &p_value) const;
DataType _type_from_property(const PropertyInfo &p_property, bool p_nil_is_variant = true) const;
DataType _type_from_gdtype(const GDScriptDataType &p_gdtype) const;
DataType _get_operation_type(const Variant::Operator p_op, const DataType &p_a, const DataType &p_b, bool &r_valid) const;
Variant::Operator _get_variant_operation(const OperatorNode::Operator &p_op) const;
bool _get_function_signature(DataType &p_base_type, const StringName &p_function, DataType &r_return_type, List<DataType> &r_arg_types, int &r_default_arg_count, bool &r_static, bool &r_vararg) const;
bool _get_member_type(const DataType &p_base_type, const StringName &p_member, DataType &r_member_type, bool *r_is_const = nullptr) const;
bool _is_type_compatible(const DataType &p_container, const DataType &p_expression, bool p_allow_implicit_conversion = false) const;
Node *_get_default_value_for_type(const DataType &p_type, int p_line = -1);
DataType _reduce_node_type(Node *p_node);
DataType _reduce_function_call_type(const OperatorNode *p_call);
DataType _reduce_identifier_type(const DataType *p_base_type, const StringName &p_identifier, int p_line, bool p_is_indexing);
void _check_class_level_types(ClassNode *p_class);
void _check_class_blocks_types(ClassNode *p_class);
void _check_function_types(FunctionNode *p_function);
void _check_block_types(BlockNode *p_block);
_FORCE_INLINE_ void _mark_line_as_safe(int p_line) const {
#ifdef DEBUG_ENABLED
if (safe_lines) {
safe_lines->insert(p_line);
}
#endif // DEBUG_ENABLED
}
_FORCE_INLINE_ void _mark_line_as_unsafe(int p_line) const {
#ifdef DEBUG_ENABLED
if (safe_lines) {
safe_lines->erase(p_line);
}
#endif // DEBUG_ENABLED
}
Error _parse(const String &p_base_path);
public:
bool has_error() const;
String get_error() const;
int get_error_line() const;
int get_error_column() const;
#ifdef DEBUG_ENABLED
const List<GDScriptWarning> &get_warnings() const {
return warnings;
}
#endif // DEBUG_ENABLED
Error parse(const String &p_code, const String &p_base_path = "", bool p_just_validate = false, const String &p_self_path = "", bool p_for_completion = false, Set<int> *r_safe_lines = nullptr, bool p_dependencies_only = false);
Error parse_bytecode(const Vector<uint8_t> &p_bytecode, const String &p_base_path = "", const String &p_self_path = "");
bool is_tool_script() const;
const Node *get_parse_tree() const;
//completion info
CompletionType get_completion_type();
StringName get_completion_cursor();
int get_completion_line();
Variant::Type get_completion_built_in_constant();
Node *get_completion_node();
ClassNode *get_completion_class();
BlockNode *get_completion_block();
FunctionNode *get_completion_function();
int get_completion_argument_index();
int get_completion_identifier_is_function();
const List<String> &get_dependencies() const {
return dependencies;
}
void clear();
GDScriptParser();
~GDScriptParser();
};
#endif // GDSCRIPT_PARSER_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,306 @@
#ifndef CSCRIPT_TOKENIZER_H
#define CSCRIPT_TOKENIZER_H
/*************************************************************************/
/* gdscript_tokenizer.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "core/pair.h"
#include "core/string_name.h"
#include "core/ustring.h"
#include "core/variant.h"
#include "core/vmap.h"
#include "cscript_functions.h"
class GDScriptTokenizer {
public:
enum Token {
TK_EMPTY,
TK_IDENTIFIER,
TK_CONSTANT,
TK_SELF,
TK_BUILT_IN_TYPE,
TK_BUILT_IN_FUNC,
TK_OP_IN,
TK_OP_EQUAL,
TK_OP_NOT_EQUAL,
TK_OP_LESS,
TK_OP_LESS_EQUAL,
TK_OP_GREATER,
TK_OP_GREATER_EQUAL,
TK_OP_AND,
TK_OP_OR,
TK_OP_NOT,
TK_OP_ADD,
TK_OP_SUB,
TK_OP_MUL,
TK_OP_DIV,
TK_OP_MOD,
TK_OP_SHIFT_LEFT,
TK_OP_SHIFT_RIGHT,
TK_OP_ASSIGN,
TK_OP_ASSIGN_ADD,
TK_OP_ASSIGN_SUB,
TK_OP_ASSIGN_MUL,
TK_OP_ASSIGN_DIV,
TK_OP_ASSIGN_MOD,
TK_OP_ASSIGN_SHIFT_LEFT,
TK_OP_ASSIGN_SHIFT_RIGHT,
TK_OP_ASSIGN_BIT_AND,
TK_OP_ASSIGN_BIT_OR,
TK_OP_ASSIGN_BIT_XOR,
TK_OP_BIT_AND,
TK_OP_BIT_OR,
TK_OP_BIT_XOR,
TK_OP_BIT_INVERT,
//TK_OP_PLUS_PLUS,
//TK_OP_MINUS_MINUS,
TK_CF_IF,
TK_CF_ELIF,
TK_CF_ELSE,
TK_CF_FOR,
TK_CF_WHILE,
TK_CF_BREAK,
TK_CF_CONTINUE,
TK_CF_PASS,
TK_CF_RETURN,
TK_CF_MATCH,
TK_PR_FUNCTION,
TK_PR_CLASS,
TK_PR_CLASS_NAME,
TK_PR_EXTENDS,
TK_PR_IS,
TK_PR_ONREADY,
TK_PR_TOOL,
TK_PR_STATIC,
TK_PR_EXPORT,
TK_PR_SETGET,
TK_PR_CONST,
TK_PR_VAR,
TK_PR_AS,
TK_PR_VOID,
TK_PR_ENUM,
TK_PR_PRELOAD,
TK_PR_ASSERT,
TK_PR_YIELD,
TK_PR_SIGNAL,
TK_PR_BREAKPOINT,
TK_PR_REMOTE,
TK_PR_SYNC,
TK_PR_MASTER,
TK_PR_SLAVE, // Deprecated by TK_PR_PUPPET, to remove in 4.0
TK_PR_PUPPET,
TK_PR_REMOTESYNC,
TK_PR_MASTERSYNC,
TK_PR_PUPPETSYNC,
TK_BRACKET_OPEN,
TK_BRACKET_CLOSE,
TK_CURLY_BRACKET_OPEN,
TK_CURLY_BRACKET_CLOSE,
TK_PARENTHESIS_OPEN,
TK_PARENTHESIS_CLOSE,
TK_COMMA,
TK_SEMICOLON,
TK_PERIOD,
TK_QUESTION_MARK,
TK_COLON,
TK_DOLLAR,
TK_FORWARD_ARROW,
TK_NEWLINE,
TK_CONST_PI,
TK_CONST_TAU,
TK_WILDCARD,
TK_CONST_INF,
TK_CONST_NAN,
TK_ERROR,
TK_EOF,
TK_CURSOR, //used for code completion
TK_MAX
};
protected:
enum StringMode {
STRING_SINGLE_QUOTE,
STRING_DOUBLE_QUOTE,
STRING_MULTILINE
};
static const char *token_names[TK_MAX];
public:
static const char *get_token_name(Token p_token);
bool is_token_literal(int p_offset = 0, bool variable_safe = false) const;
StringName get_token_literal(int p_offset = 0) const;
virtual const Variant &get_token_constant(int p_offset = 0) const = 0;
virtual Token get_token(int p_offset = 0) const = 0;
virtual StringName get_token_identifier(int p_offset = 0) const = 0;
virtual GDScriptFunctions::Function get_token_built_in_func(int p_offset = 0) const = 0;
virtual Variant::Type get_token_type(int p_offset = 0) const = 0;
virtual int get_token_line(int p_offset = 0) const = 0;
virtual int get_token_column(int p_offset = 0) const = 0;
virtual int get_token_line_indent(int p_offset = 0) const = 0;
virtual int get_token_line_tab_indent(int p_offset = 0) const = 0;
virtual String get_token_error(int p_offset = 0) const = 0;
virtual void advance(int p_amount = 1) = 0;
#ifdef DEBUG_ENABLED
virtual const Vector<Pair<int, String>> &get_warning_skips() const = 0;
virtual const Set<String> &get_warning_global_skips() const = 0;
virtual bool is_ignoring_warnings() const = 0;
#endif // DEBUG_ENABLED
virtual ~GDScriptTokenizer(){};
};
class GDScriptTokenizerText : public GDScriptTokenizer {
enum {
MAX_LOOKAHEAD = 4,
TK_RB_SIZE = MAX_LOOKAHEAD * 2 + 1
};
struct TokenData {
Token type;
StringName identifier; //for identifier types
Variant constant; //for constant types
union {
Variant::Type vtype; //for type types
GDScriptFunctions::Function func; //function for built in functions
int warning_code; //for warning skip
};
int line, col;
TokenData() {
type = TK_EMPTY;
line = col = 0;
vtype = Variant::NIL;
}
};
void _make_token(Token p_type);
void _make_newline(int p_indentation = 0, int p_tabs = 0);
void _make_identifier(const StringName &p_identifier);
void _make_built_in_func(GDScriptFunctions::Function p_func);
void _make_constant(const Variant &p_constant);
void _make_type(const Variant::Type &p_type);
void _make_error(const String &p_error);
String code;
int len;
int code_pos;
const CharType *_code;
int line;
int column;
TokenData tk_rb[TK_RB_SIZE * 2 + 1];
int tk_rb_pos;
String last_error;
bool error_flag;
#ifdef DEBUG_ENABLED
Vector<Pair<int, String>> warning_skips;
Set<String> warning_global_skips;
bool ignore_warnings;
#endif // DEBUG_ENABLED
void _advance();
public:
void set_code(const String &p_code);
virtual Token get_token(int p_offset = 0) const;
virtual StringName get_token_identifier(int p_offset = 0) const;
virtual GDScriptFunctions::Function get_token_built_in_func(int p_offset = 0) const;
virtual Variant::Type get_token_type(int p_offset = 0) const;
virtual int get_token_line(int p_offset = 0) const;
virtual int get_token_column(int p_offset = 0) const;
virtual int get_token_line_indent(int p_offset = 0) const;
virtual int get_token_line_tab_indent(int p_offset = 0) const;
virtual const Variant &get_token_constant(int p_offset = 0) const;
virtual String get_token_error(int p_offset = 0) const;
virtual void advance(int p_amount = 1);
#ifdef DEBUG_ENABLED
virtual const Vector<Pair<int, String>> &get_warning_skips() const {
return warning_skips;
}
virtual const Set<String> &get_warning_global_skips() const {
return warning_global_skips;
}
virtual bool is_ignoring_warnings() const {
return ignore_warnings;
}
#endif // DEBUG_ENABLED
};
class GDScriptTokenizerBuffer : public GDScriptTokenizer {
enum {
TOKEN_BYTE_MASK = 0x80,
TOKEN_BITS = 8,
TOKEN_MASK = (1 << TOKEN_BITS) - 1,
TOKEN_LINE_BITS = 24,
TOKEN_LINE_MASK = (1 << TOKEN_LINE_BITS) - 1,
};
Vector<StringName> identifiers;
Vector<Variant> constants;
VMap<uint32_t, uint32_t> lines;
Vector<uint32_t> tokens;
Variant nil;
int token;
public:
Error set_code_buffer(const Vector<uint8_t> &p_buffer);
static Vector<uint8_t> parse_code_string(const String &p_code);
virtual Token get_token(int p_offset = 0) const;
virtual StringName get_token_identifier(int p_offset = 0) const;
virtual GDScriptFunctions::Function get_token_built_in_func(int p_offset = 0) const;
virtual Variant::Type get_token_type(int p_offset = 0) const;
virtual int get_token_line(int p_offset = 0) const;
virtual int get_token_column(int p_offset = 0) const;
virtual int get_token_line_indent(int p_offset = 0) const;
virtual int get_token_line_tab_indent(int p_offset = 0) const { return 0; }
virtual const Variant &get_token_constant(int p_offset = 0) const;
virtual String get_token_error(int p_offset = 0) const;
virtual void advance(int p_amount = 1);
#ifdef DEBUG_ENABLED
virtual const Vector<Pair<int, String>> &get_warning_skips() const {
static Vector<Pair<int, String>> v;
return v;
}
virtual const Set<String> &get_warning_global_skips() const {
static Set<String> s;
return s;
}
virtual bool is_ignoring_warnings() const {
return true;
}
#endif // DEBUG_ENABLED
GDScriptTokenizerBuffer();
};
#endif // GDSCRIPT_TOKENIZER_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GDScript" inherits="Script" version="3.5">
<brief_description>
A script implemented in the GDScript programming language.
</brief_description>
<description>
A script implemented in the GDScript programming language. The script extends the functionality of all objects that instance it.
[method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
<tutorials>
<link>$DOCS_URL/tutorials/scripting/gdscript/index.html</link>
</tutorials>
<methods>
<method name="get_as_byte_code" qualifiers="const">
<return type="PoolByteArray" />
<description>
Returns byte code for the script source code.
</description>
</method>
<method name="new" qualifiers="vararg">
<return type="Variant" />
<description>
Returns a new instance of the script.
For example:
[codeblock]
var MyClass = load("myclass.gd")
var instance = MyClass.new()
assert(instance.get_script() == MyClass)
[/codeblock]
</description>
</method>
</methods>
<constants>
</constants>
</class>

View File

@ -0,0 +1,395 @@
/*************************************************************************/
/* gdscript_highlighter.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "gdscript_highlighter.h"
#include "../gdscript_tokenizer.h"
#include "editor/editor_settings.h"
#include "scene/gui/text_edit.h"
inline bool _is_symbol(CharType c) {
return is_symbol(c);
}
static bool _is_text_char(CharType c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_';
}
static bool _is_char(CharType c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
}
static bool _is_number(CharType c) {
return (c >= '0' && c <= '9');
}
static bool _is_hex_symbol(CharType c) {
return ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'));
}
static bool _is_bin_symbol(CharType c) {
return (c == '0' || c == '1');
}
Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_highlighting(int p_line) {
Map<int, TextEdit::HighlighterInfo> color_map;
Type next_type = NONE;
Type current_type = NONE;
Type previous_type = NONE;
String previous_text = "";
int previous_column = 0;
bool prev_is_char = false;
bool prev_is_number = false;
bool in_keyword = false;
bool in_word = false;
bool in_function_name = false;
bool in_variable_declaration = false;
bool in_function_args = false;
bool in_member_variable = false;
bool in_node_path = false;
bool is_hex_notation = false;
bool is_bin_notation = false;
bool expect_type = false;
Color keyword_color;
Color color;
int in_region = text_editor->_is_line_in_region(p_line);
int deregion = 0;
const Map<int, TextEdit::Text::ColorRegionInfo> cri_map = text_editor->_get_line_color_region_info(p_line);
const String &str = text_editor->get_line(p_line);
Color prev_color;
for (int j = 0; j < str.length(); j++) {
TextEdit::HighlighterInfo highlighter_info;
if (deregion > 0) {
deregion--;
if (deregion == 0) {
in_region = -1;
}
}
if (deregion != 0) {
if (color != prev_color) {
prev_color = color;
highlighter_info.color = color;
color_map[j] = highlighter_info;
}
continue;
}
color = font_color;
bool is_char = _is_text_char(str[j]);
bool is_symbol = _is_symbol(str[j]);
bool is_number = _is_number(str[j]);
// allow ABCDEF in hex notation
if (is_hex_notation && (_is_hex_symbol(str[j]) || is_number)) {
is_number = true;
} else {
is_hex_notation = false;
}
// disallow anything not a 0 or 1
if (is_bin_notation && (_is_bin_symbol(str[j]))) {
is_number = true;
} else if (is_bin_notation) {
is_bin_notation = false;
is_number = false;
} else {
is_bin_notation = false;
}
// check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation
if ((str[j] == '.' || str[j] == 'x' || str[j] == 'b' || str[j] == '_' || str[j] == 'e') && !in_word && prev_is_number && !is_number) {
is_number = true;
is_symbol = false;
is_char = false;
if (str[j] == 'x' && str[j - 1] == '0') {
is_hex_notation = true;
} else if (str[j] == 'b' && str[j - 1] == '0') {
is_bin_notation = true;
}
}
if (!in_word && _is_char(str[j]) && !is_number) {
in_word = true;
}
if ((in_keyword || in_word) && !is_hex_notation) {
is_number = false;
}
if (is_symbol && str[j] != '.' && in_word) {
in_word = false;
}
if (is_symbol && cri_map.has(j)) {
const TextEdit::Text::ColorRegionInfo &cri = cri_map[j];
if (in_region == -1) {
if (!cri.end) {
in_region = cri.region;
}
} else {
TextEdit::ColorRegion cr = text_editor->_get_color_region(cri.region);
if (in_region == cri.region && !cr.line_only) { //ignore otherwise
if (cri.end || cr.eq) {
deregion = cr.eq ? cr.begin_key.length() : cr.end_key.length();
}
}
}
}
if (!is_char) {
in_keyword = false;
}
if (in_region == -1 && !in_keyword && is_char && !prev_is_char) {
int to = j;
while (to < str.length() && _is_text_char(str[to])) {
to++;
}
String word = str.substr(j, to - j);
Color col = Color();
if (text_editor->has_keyword_color(word)) {
col = text_editor->get_keyword_color(word);
} else if (text_editor->has_member_color(word)) {
col = text_editor->get_member_color(word);
}
if (col != Color()) {
for (int k = j - 1; k >= 0; k--) {
if (str[k] == '.') {
col = Color(); // keyword & member indexing not allowed
break;
} else if (str[k] > 32) {
break;
}
}
if (col != Color()) {
in_keyword = true;
keyword_color = col;
}
}
}
if (!in_function_name && in_word && !in_keyword) {
int k = j;
while (k < str.length() && !_is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') {
k++;
}
// check for space between name and bracket
while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
k++;
}
if (str[k] == '(') {
in_function_name = true;
} else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::TK_PR_VAR)) {
in_variable_declaration = true;
}
}
if (!in_function_name && !in_member_variable && !in_keyword && !is_number && in_word) {
int k = j;
while (k > 0 && !_is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') {
k--;
}
if (str[k] == '.') {
in_member_variable = true;
}
}
if (is_symbol) {
if (in_function_name) {
in_function_args = true;
}
if (in_function_args && str[j] == ')') {
in_function_args = false;
}
if (expect_type && (prev_is_char || str[j] == '=')) {
expect_type = false;
}
if (j > 0 && str[j] == '>' && str[j - 1] == '-') {
expect_type = true;
}
if (in_variable_declaration || in_function_args) {
int k = j;
// Skip space
while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
k++;
}
if (str[k] == ':') {
// has type hint
expect_type = true;
}
}
in_variable_declaration = false;
in_function_name = false;
in_member_variable = false;
}
if (!in_node_path && in_region == -1 && str[j] == '$') {
in_node_path = true;
} else if (in_region != -1 || (is_symbol && str[j] != '/')) {
in_node_path = false;
}
if (in_region >= 0) {
next_type = REGION;
color = text_editor->_get_color_region(in_region).color;
} else if (in_node_path) {
next_type = NODE_PATH;
color = node_path_color;
} else if (in_keyword) {
next_type = KEYWORD;
color = keyword_color;
} else if (in_member_variable) {
next_type = MEMBER;
color = member_color;
} else if (in_function_name) {
next_type = FUNCTION;
if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::TK_PR_FUNCTION)) {
color = function_definition_color;
} else {
color = function_color;
}
} else if (is_symbol) {
next_type = SYMBOL;
color = symbol_color;
} else if (is_number) {
next_type = NUMBER;
color = number_color;
} else if (expect_type) {
next_type = TYPE;
color = type_color;
} else {
next_type = IDENTIFIER;
}
if (next_type != current_type) {
if (current_type == NONE) {
current_type = next_type;
} else {
previous_type = current_type;
current_type = next_type;
// no need to store regions...
if (previous_type == REGION) {
previous_text = "";
previous_column = j;
} else {
String text = str.substr(previous_column, j - previous_column).strip_edges();
previous_column = j;
// ignore if just whitespace
if (text != "") {
previous_text = text;
}
}
}
}
prev_is_char = is_char;
prev_is_number = is_number;
if (color != prev_color) {
prev_color = color;
highlighter_info.color = color;
color_map[j] = highlighter_info;
}
}
return color_map;
}
String GDScriptSyntaxHighlighter::get_name() const {
return "GDScript";
}
List<String> GDScriptSyntaxHighlighter::get_supported_languages() {
List<String> languages;
languages.push_back("GDScript");
return languages;
}
void GDScriptSyntaxHighlighter::_update_cache() {
font_color = text_editor->get_color("font_color");
symbol_color = text_editor->get_color("symbol_color");
function_color = text_editor->get_color("function_color");
number_color = text_editor->get_color("number_color");
member_color = text_editor->get_color("member_variable_color");
const String text_editor_color_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
const bool default_theme = text_editor_color_theme == "Default";
if (default_theme || EditorSettings::get_singleton()->is_dark_theme()) {
function_definition_color = Color(0.4, 0.9, 1.0);
node_path_color = Color(0.39, 0.76, 0.35);
} else {
function_definition_color = Color(0.0, 0.65, 0.73);
node_path_color = Color(0.32, 0.55, 0.29);
}
EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", function_definition_color);
EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", node_path_color);
if (text_editor_color_theme == "Adaptive" || default_theme) {
EditorSettings::get_singleton()->set_initial_value(
"text_editor/highlighting/gdscript/function_definition_color",
function_definition_color,
true);
EditorSettings::get_singleton()->set_initial_value(
"text_editor/highlighting/gdscript/node_path_color",
node_path_color,
true);
}
function_definition_color = EDITOR_GET("text_editor/highlighting/gdscript/function_definition_color");
node_path_color = EDITOR_GET("text_editor/highlighting/gdscript/node_path_color");
type_color = EDITOR_GET("text_editor/highlighting/base_type_color");
}
SyntaxHighlighter *GDScriptSyntaxHighlighter::create() {
return memnew(GDScriptSyntaxHighlighter);
}

View File

@ -0,0 +1,71 @@
#ifndef CSCRIPT_HIGHLIGHTER_H
#define CSCRIPT_HIGHLIGHTER_H
/*************************************************************************/
/* gdscript_highlighter.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "scene/gui/text_edit.h"
class GDScriptSyntaxHighlighter : public SyntaxHighlighter {
private:
enum Type {
NONE,
REGION,
NODE_PATH,
SYMBOL,
NUMBER,
FUNCTION,
KEYWORD,
MEMBER,
IDENTIFIER,
TYPE,
};
// colours
Color font_color;
Color symbol_color;
Color function_color;
Color function_definition_color;
Color built_in_type_color;
Color number_color;
Color member_color;
Color node_path_color;
Color type_color;
public:
static SyntaxHighlighter *create();
virtual void _update_cache();
virtual Map<int, TextEdit::HighlighterInfo> _get_line_syntax_highlighting(int p_line);
virtual String get_name() const;
virtual List<String> get_supported_languages();
};
#endif // GDSCRIPT_HIGHLIGHTER_H

View File

@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="16"
height="16"
version="1.1"
viewBox="0 0 16 16"
id="svg6"
sodipodi:docname="icon_g_d_script.svg"
inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs10" />
<sodipodi:namedview
id="namedview8"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="38.404737"
inkscape:cx="10.701805"
inkscape:cy="7.2126519"
inkscape:window-width="1920"
inkscape:window-height="1023"
inkscape:window-x="3840"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<g
transform="translate(0 -1036.4)"
id="g4">
<path
transform="translate(0 1036.4)"
d="m7 1l-0.56445 2.2578a5 5 0 0 0 -0.68945 0.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941a5 5 0 0 0 -0.28516 0.68555l-2.2539 0.5625v2l2.2578 0.56445a5 5 0 0 0 0.2793 0.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953a5 5 0 0 0 0.68555 0.28516l0.5625 2.2539h2l0.56445-2.2578a5 5 0 0 0 0.6875 -0.2793l1.9902 1.1934 1.4141-1.4141-1.1953-1.9941a5 5 0 0 0 0.28516 -0.68555l2.2539-0.5625v-2l-2.2578-0.56445a5 5 0 0 0 -0.2793 -0.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953a5 5 0 0 0 -0.68555 -0.28516l-0.5625-2.2539h-2zm1 5a2 2 0 0 1 2 2 2 2 0 0 1 -2 2 2 2 0 0 1 -2 -2 2 2 0 0 1 2 -2z"
fill="#e0e0e0"
id="path2" />
</g>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;fill:#000000;fill-opacity:1;stroke:none"
x="9.4249582"
y="10.451061"
id="text293"><tspan
sodipodi:role="line"
id="tspan291"
x="9.4249582"
y="10.451061"></tspan></text>
<text
xml:space="preserve"
style="font-style:normal;font-weight:normal;font-size:10.6667px;line-height:1.25;font-family:sans-serif;mix-blend-mode:luminosity;fill:#e0e0e0;fill-opacity:1;stroke:#707070;stroke-width:0.4;stroke-dasharray:none;stroke-opacity:1"
x="8.6932192"
y="15.296833"
id="text504-9"><tspan
sodipodi:role="line"
id="tspan502-2"
x="8.6932192"
y="15.296833"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:10.6667px;font-family:'Droid Arabic Kufi';-inkscape-font-specification:'Droid Arabic Kufi Bold';fill:#e0e0e0;fill-opacity:1;stroke:#707070;stroke-width:0.4;stroke-dasharray:none;stroke-opacity:1">C</tspan></text>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -0,0 +1,170 @@
/*************************************************************************/
/* register_types.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "register_types.h"
#include "core/io/file_access_encrypted.h"
#include "core/io/resource_loader.h"
#include "core/os/dir_access.h"
#include "core/os/file_access.h"
#include "cscript.h"
#include "cscript_tokenizer.h"
GDScriptLanguage *script_language_gd = nullptr;
Ref<ResourceFormatLoaderGDScript> resource_loader_gd;
Ref<ResourceFormatSaverGDScript> resource_saver_gd;
#ifdef TOOLS_ENABLED
#include "editor/editor_export.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/gdscript_highlighter.h"
class EditorExportGDScript : public EditorExportPlugin {
GDCLASS(EditorExportGDScript, EditorExportPlugin);
public:
virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features) {
int script_mode = EditorExportPreset::MODE_SCRIPT_COMPILED;
String script_key;
const Ref<EditorExportPreset> &preset = get_export_preset();
if (preset.is_valid()) {
script_mode = preset->get_script_export_mode();
script_key = preset->get_script_encryption_key().to_lower();
}
if (!p_path.ends_with(".gd") || script_mode == EditorExportPreset::MODE_SCRIPT_TEXT) {
return;
}
Vector<uint8_t> file = FileAccess::get_file_as_array(p_path);
if (file.empty()) {
return;
}
String txt;
txt.parse_utf8((const char *)file.ptr(), file.size());
file = GDScriptTokenizerBuffer::parse_code_string(txt);
if (!file.empty()) {
if (script_mode == EditorExportPreset::MODE_SCRIPT_ENCRYPTED) {
String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("script.gde");
FileAccess *fa = FileAccess::open(tmp_path, FileAccess::WRITE);
Vector<uint8_t> key;
key.resize(32);
for (int i = 0; i < 32; i++) {
int v = 0;
if (i * 2 < script_key.length()) {
CharType ct = script_key[i * 2];
if (ct >= '0' && ct <= '9') {
ct = ct - '0';
} else if (ct >= 'a' && ct <= 'f') {
ct = 10 + ct - 'a';
}
v |= ct << 4;
}
if (i * 2 + 1 < script_key.length()) {
CharType ct = script_key[i * 2 + 1];
if (ct >= '0' && ct <= '9') {
ct = ct - '0';
} else if (ct >= 'a' && ct <= 'f') {
ct = 10 + ct - 'a';
}
v |= ct;
}
key.write[i] = v;
}
FileAccessEncrypted *fae = memnew(FileAccessEncrypted);
Error err = fae->open_and_parse(fa, key, FileAccessEncrypted::MODE_WRITE_AES256);
if (err == OK) {
fae->store_buffer(file.ptr(), file.size());
}
memdelete(fae);
file = FileAccess::get_file_as_array(tmp_path);
add_file(p_path.get_basename() + ".gde", file, true);
// Clean up temporary file.
DirAccess::remove_file_or_error(tmp_path);
} else {
add_file(p_path.get_basename() + ".gdc", file, true);
}
}
}
};
static void _editor_init() {
Ref<EditorExportGDScript> gd_export;
gd_export.instance();
EditorExport::get_singleton()->add_export_plugin(gd_export);
}
#endif // TOOLS_ENABLED
void register_gdscript_types() {
ClassDB::register_class<GDScript>();
ClassDB::register_virtual_class<GDScriptFunctionState>();
script_language_gd = memnew(GDScriptLanguage);
ScriptServer::register_language(script_language_gd);
resource_loader_gd.instance();
ResourceLoader::add_resource_format_loader(resource_loader_gd);
resource_saver_gd.instance();
ResourceSaver::add_resource_format_saver(resource_saver_gd);
#ifdef TOOLS_ENABLED
ScriptEditor::register_create_syntax_highlighter_function(GDScriptSyntaxHighlighter::create);
EditorNode::add_init_callback(_editor_init);
#endif // TOOLS_ENABLED
}
void unregister_gdscript_types() {
ScriptServer::unregister_language(script_language_gd);
if (script_language_gd) {
memdelete(script_language_gd);
}
ResourceLoader::remove_resource_format_loader(resource_loader_gd);
resource_loader_gd.unref();
ResourceSaver::remove_resource_format_saver(resource_saver_gd);
resource_saver_gd.unref();
}

View File

@ -0,0 +1,36 @@
#ifndef CSCRIPT_REGISTER_TYPES_H
#define CSCRIPT_REGISTER_TYPES_H
/*************************************************************************/
/* register_types.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
void register_cscript_types();
void unregister_cscript_types();
#endif // GDSCRIPT_REGISTER_TYPES_H