mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-01-30 12:59:18 +01:00
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:
parent
4afcf246aa
commit
e687fc6a4a
12
modules/cscript/SCsub
Normal file
12
modules/cscript/SCsub
Normal 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
21
modules/cscript/config.py
Normal 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
2293
modules/cscript/cscript.cpp
Normal file
File diff suppressed because it is too large
Load Diff
567
modules/cscript/cscript.h
Normal file
567
modules/cscript/cscript.h
Normal 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
|
2236
modules/cscript/cscript_compiler.cpp
Normal file
2236
modules/cscript/cscript_compiler.cpp
Normal file
File diff suppressed because it is too large
Load Diff
169
modules/cscript/cscript_compiler.h
Normal file
169
modules/cscript/cscript_compiler.h
Normal 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
|
3552
modules/cscript/cscript_editor.cpp
Normal file
3552
modules/cscript/cscript_editor.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1879
modules/cscript/cscript_function.cpp
Normal file
1879
modules/cscript/cscript_function.cpp
Normal file
File diff suppressed because it is too large
Load Diff
389
modules/cscript/cscript_function.h
Normal file
389
modules/cscript/cscript_function.h
Normal 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
|
1984
modules/cscript/cscript_functions.cpp
Normal file
1984
modules/cscript/cscript_functions.cpp
Normal file
File diff suppressed because it is too large
Load Diff
138
modules/cscript/cscript_functions.h
Normal file
138
modules/cscript/cscript_functions.h
Normal 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
|
8926
modules/cscript/cscript_parser.cpp
Normal file
8926
modules/cscript/cscript_parser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
699
modules/cscript/cscript_parser.h
Normal file
699
modules/cscript/cscript_parser.h
Normal 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
|
1498
modules/cscript/cscript_tokenizer.cpp
Normal file
1498
modules/cscript/cscript_tokenizer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
306
modules/cscript/cscript_tokenizer.h
Normal file
306
modules/cscript/cscript_tokenizer.h
Normal 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
|
1237
modules/cscript/doc_classes/@CScript.xml
Normal file
1237
modules/cscript/doc_classes/@CScript.xml
Normal file
File diff suppressed because it is too large
Load Diff
35
modules/cscript/doc_classes/CScript.xml
Normal file
35
modules/cscript/doc_classes/CScript.xml
Normal 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>
|
395
modules/cscript/editor/cscript_highlighter.cpp
Normal file
395
modules/cscript/editor/cscript_highlighter.cpp
Normal 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);
|
||||
}
|
71
modules/cscript/editor/cscript_highlighter.h
Normal file
71
modules/cscript/editor/cscript_highlighter.h
Normal 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
|
65
modules/cscript/icons/icon_c_script.svg
Normal file
65
modules/cscript/icons/icon_c_script.svg
Normal 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 |
170
modules/cscript/register_types.cpp
Normal file
170
modules/cscript/register_types.cpp
Normal 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();
|
||||
}
|
36
modules/cscript/register_types.h
Normal file
36
modules/cscript/register_types.h
Normal 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
|
Loading…
Reference in New Issue
Block a user