Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
godot
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
community
godot
Commits
9e477bab
Commit
9e477bab
authored
Jan 04, 2017
by
Juan Linietsky
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
-GDScript support for accessing properties directly
-Added code lookup and code completion support for properties too
parent
76c2e858
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
200 additions
and
13 deletions
+200
-13
test_gdscript.cpp
bin/tests/test_gdscript.cpp
+22
-0
object_type_db.cpp
core/object_type_db.cpp
+16
-0
object_type_db.h
core/object_type_db.h
+1
-0
gd_compiler.cpp
modules/gdscript/gd_compiler.cpp
+108
-10
gd_compiler.h
modules/gdscript/gd_compiler.h
+4
-0
gd_editor.cpp
modules/gdscript/gd_editor.cpp
+0
-0
gd_function.cpp
modules/gdscript/gd_function.cpp
+41
-1
gd_function.h
modules/gdscript/gd_function.h
+2
-0
script_text_editor.cpp
tools/editor/plugins/script_text_editor.cpp
+6
-2
No files found.
bin/tests/test_gdscript.cpp
View file @
9e477bab
...
...
@@ -581,6 +581,28 @@ static void _disassemble_class(const Ref<GDScript>& p_class,const Vector<String>
incr
+=
4
;
}
break
;
case
GDFunction
:
:
OPCODE_SET_MEMBER
:
{
txt
+=
" set_member "
;
txt
+=
"[
\"
"
;
txt
+=
func
.
get_global_name
(
code
[
ip
+
1
]);
txt
+=
"
\"
]="
;
txt
+=
DADDR
(
2
);
incr
+=
3
;
}
break
;
case
GDFunction
:
:
OPCODE_GET_MEMBER
:
{
txt
+=
" get_member "
;
txt
+=
DADDR
(
2
);
txt
+=
"="
;
txt
+=
"[
\"
"
;
txt
+=
func
.
get_global_name
(
code
[
ip
+
1
]);
txt
+=
"
\"
]"
;
incr
+=
3
;
}
break
;
case
GDFunction
:
:
OPCODE_ASSIGN
:
{
txt
+=
" assign "
;
...
...
core/object_type_db.cpp
View file @
9e477bab
...
...
@@ -991,6 +991,22 @@ StringName ClassDB::get_property_getter(StringName p_class,const StringName p_pr
return
StringName
();
}
bool
ClassDB
::
has_property
(
const
StringName
&
p_class
,
const
StringName
&
p_property
,
bool
p_no_inheritance
)
{
ClassInfo
*
type
=
classes
.
getptr
(
p_class
);
ClassInfo
*
check
=
type
;
while
(
check
)
{
if
(
check
->
property_setget
.
has
(
p_property
))
return
true
;
if
(
p_no_inheritance
)
break
;
check
=
check
->
inherits_ptr
;
}
return
false
;
}
void
ClassDB
::
set_method_flags
(
StringName
p_class
,
StringName
p_method
,
int
p_flags
)
{
...
...
core/object_type_db.h
View file @
9e477bab
...
...
@@ -481,6 +481,7 @@ public:
static
void
get_property_list
(
StringName
p_class
,
List
<
PropertyInfo
>
*
p_list
,
bool
p_no_inheritance
=
false
,
const
Object
*
p_validator
=
NULL
);
static
bool
set_property
(
Object
*
p_object
,
const
StringName
&
p_property
,
const
Variant
&
p_value
,
bool
*
r_valid
=
NULL
);
static
bool
get_property
(
Object
*
p_object
,
const
StringName
&
p_property
,
Variant
&
r_value
);
static
bool
has_property
(
const
StringName
&
p_class
,
const
StringName
&
p_property
,
bool
p_no_inheritance
=
false
);
static
Variant
::
Type
get_property_type
(
const
StringName
&
p_class
,
const
StringName
&
p_property
,
bool
*
r_is_valid
=
NULL
);
static
StringName
get_property_setter
(
StringName
p_class
,
const
StringName
p_property
);
static
StringName
get_property_getter
(
StringName
p_class
,
const
StringName
p_property
);
...
...
modules/gdscript/gd_compiler.cpp
View file @
9e477bab
...
...
@@ -29,6 +29,31 @@
#include "gd_compiler.h"
#include "gd_script.h"
bool
GDCompiler
::
_is_class_member_property
(
CodeGen
&
codegen
,
const
StringName
&
p_name
)
{
if
(
!
codegen
.
function_node
||
codegen
.
function_node
->
_static
)
return
false
;
return
_is_class_member_property
(
codegen
.
script
,
p_name
);
}
bool
GDCompiler
::
_is_class_member_property
(
GDScript
*
owner
,
const
StringName
&
p_name
)
{
GDScript
*
scr
=
owner
;
GDNativeClass
*
nc
=
NULL
;
while
(
scr
)
{
if
(
scr
->
native
.
is_valid
())
nc
=
scr
->
native
.
ptr
();
scr
=
scr
->
_base
;
}
ERR_FAIL_COND_V
(
!
nc
,
false
);
return
ClassDB
::
has_property
(
nc
->
get_name
(),
p_name
);
}
void
GDCompiler
::
_set_error
(
const
String
&
p_error
,
const
GDParser
::
Node
*
p_node
)
{
...
...
@@ -164,6 +189,17 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
StringName
identifier
=
in
->
name
;
if
(
_is_class_member_property
(
codegen
,
identifier
))
{
//get property
codegen
.
opcodes
.
push_back
(
GDFunction
::
OPCODE_GET_MEMBER
);
// perform operator
codegen
.
opcodes
.
push_back
(
codegen
.
get_name_map_pos
(
identifier
));
// argument 2 (unary only takes one parameter)
int
dst_addr
=
(
p_stack_level
)
|
(
GDFunction
::
ADDR_TYPE_STACK
<<
GDFunction
::
ADDR_BITS
);
codegen
.
opcodes
.
push_back
(
dst_addr
);
// append the stack level as destination address of the opcode
codegen
.
alloc_stack
(
p_stack_level
);
return
dst_addr
;
}
// TRY STACK!
if
(
!
p_initializer
&&
codegen
.
stack_identifiers
.
has
(
identifier
))
{
...
...
@@ -776,6 +812,8 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
/* Find chain of sets */
StringName
assign_property
;
List
<
GDParser
::
OperatorNode
*>
chain
;
{
...
...
@@ -784,8 +822,20 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
while
(
true
)
{
chain
.
push_back
(
n
);
if
(
n
->
arguments
[
0
]
->
type
!=
GDParser
::
Node
::
TYPE_OPERATOR
)
if
(
n
->
arguments
[
0
]
->
type
!=
GDParser
::
Node
::
TYPE_OPERATOR
)
{
//check for a built-in property
if
(
n
->
arguments
[
0
]
->
type
==
GDParser
::
Node
::
TYPE_IDENTIFIER
)
{
GDParser
::
IdentifierNode
*
identifier
=
static_cast
<
GDParser
::
IdentifierNode
*>
(
n
->
arguments
[
0
]);
if
(
_is_class_member_property
(
codegen
,
identifier
->
name
))
{
assign_property
=
identifier
->
name
;
}
}
break
;
}
n
=
static_cast
<
GDParser
::
OperatorNode
*>
(
n
->
arguments
[
0
]);
if
(
n
->
op
!=
GDParser
::
OperatorNode
::
OP_INDEX
&&
n
->
op
!=
GDParser
::
OperatorNode
::
OP_INDEX_NAMED
)
break
;
...
...
@@ -810,6 +860,17 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
Vector
<
int
>
setchain
;
if
(
assign_property
!=
StringName
())
{
// recover and assign at the end, this allows stuff like
// position.x+=2.0
// in Node2D
setchain
.
push_back
(
prev_pos
);
setchain
.
push_back
(
codegen
.
get_name_map_pos
(
assign_property
));
setchain
.
push_back
(
GDFunction
::
OPCODE_SET_MEMBER
);
}
for
(
List
<
GDParser
::
OperatorNode
*>::
Element
*
E
=
chain
.
back
();
E
;
E
=
E
->
prev
())
{
...
...
@@ -840,7 +901,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
}
if
(
key_idx
<
0
)
if
(
key_idx
<
0
)
//error
return
key_idx
;
codegen
.
opcodes
.
push_back
(
named
?
GDFunction
::
OPCODE_GET_NAMED
:
GDFunction
::
OPCODE_GET
);
...
...
@@ -852,7 +913,10 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
codegen
.
opcodes
.
push_back
(
dst_pos
);
//add in reverse order, since it will be reverted
setchain
.
push_back
(
dst_pos
);
setchain
.
push_back
(
key_idx
);
setchain
.
push_back
(
prev_pos
);
...
...
@@ -881,7 +945,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
}
if
(
set_index
<
0
)
if
(
set_index
<
0
)
//error
return
set_index
;
if
(
set_index
&
GDFunction
::
ADDR_TYPE_STACK
<<
GDFunction
::
ADDR_BITS
)
{
...
...
@@ -891,7 +955,7 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
int
set_value
=
_parse_assign_right_expression
(
codegen
,
on
,
slevel
+
1
);
if
(
set_value
<
0
)
if
(
set_value
<
0
)
//error
return
set_value
;
codegen
.
opcodes
.
push_back
(
named
?
GDFunction
::
OPCODE_SET_NAMED
:
GDFunction
::
OPCODE_SET
);
...
...
@@ -899,20 +963,36 @@ int GDCompiler::_parse_expression(CodeGen& codegen,const GDParser::Node *p_expre
codegen
.
opcodes
.
push_back
(
set_index
);
codegen
.
opcodes
.
push_back
(
set_value
);
for
(
int
i
=
0
;
i
<
setchain
.
size
();
i
+
=
4
)
{
for
(
int
i
=
0
;
i
<
setchain
.
size
();
i
+
+
)
{
codegen
.
opcodes
.
push_back
(
setchain
[
i
+
0
]);
codegen
.
opcodes
.
push_back
(
setchain
[
i
+
1
]);
codegen
.
opcodes
.
push_back
(
setchain
[
i
+
2
]);
codegen
.
opcodes
.
push_back
(
setchain
[
i
+
3
]);
codegen
.
opcodes
.
push_back
(
setchain
[
i
]);
}
return
retval
;
}
else
if
(
on
->
arguments
[
0
]
->
type
==
GDParser
::
Node
::
TYPE_IDENTIFIER
&&
_is_class_member_property
(
codegen
,
static_cast
<
GDParser
::
IdentifierNode
*>
(
on
->
arguments
[
0
])
->
name
))
{
//assignment to member property
int
slevel
=
p_stack_level
;
int
src_address
=
_parse_assign_right_expression
(
codegen
,
on
,
slevel
);
if
(
src_address
<
0
)
return
-
1
;
StringName
name
=
static_cast
<
GDParser
::
IdentifierNode
*>
(
on
->
arguments
[
0
])
->
name
;
codegen
.
opcodes
.
push_back
(
GDFunction
::
OPCODE_SET_MEMBER
);
codegen
.
opcodes
.
push_back
(
codegen
.
get_name_map_pos
(
name
));
codegen
.
opcodes
.
push_back
(
src_address
);
return
GDFunction
::
ADDR_TYPE_NIL
<<
GDFunction
::
ADDR_BITS
;
}
else
{
//ASSIGNMENT MODE!!
//REGULAR ASSIGNMENT MODE!!
int
slevel
=
p_stack_level
;
...
...
@@ -1211,6 +1291,11 @@ Error GDCompiler::_parse_block(CodeGen& codegen,const GDParser::BlockNode *p_blo
const
GDParser
::
LocalVarNode
*
lv
=
static_cast
<
const
GDParser
::
LocalVarNode
*>
(
s
);
if
(
_is_class_member_property
(
codegen
,
lv
->
name
))
{
_set_error
(
"Name for local variable '"
+
String
(
lv
->
name
)
+
"' can't shadow class property of the same name."
,
lv
);
return
ERR_ALREADY_EXISTS
;
}
codegen
.
add_stack_identifier
(
lv
->
name
,
p_stack_level
++
);
codegen
.
alloc_stack
(
p_stack_level
);
new_identifiers
++
;
...
...
@@ -1249,6 +1334,10 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
if
(
p_func
)
{
for
(
int
i
=
0
;
i
<
p_func
->
arguments
.
size
();
i
++
)
{
if
(
_is_class_member_property
(
p_script
,
p_func
->
arguments
[
i
]))
{
_set_error
(
"Name for argument '"
+
String
(
p_func
->
arguments
[
i
])
+
"' can't shadow class property of the same name."
,
p_func
);
return
ERR_ALREADY_EXISTS
;
}
codegen
.
add_stack_identifier
(
p_func
->
arguments
[
i
],
i
);
#ifdef TOOLS_ENABLED
argnames
.
push_back
(
p_func
->
arguments
[
i
]);
...
...
@@ -1653,6 +1742,10 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa
_set_error
(
"Member '"
+
name
+
"' already exists (in current or parent class)"
,
p_class
);
return
ERR_ALREADY_EXISTS
;
}
if
(
_is_class_member_property
(
p_script
,
name
))
{
_set_error
(
"Member '"
+
name
+
"' already exists as a class property."
,
p_class
);
return
ERR_ALREADY_EXISTS
;
}
if
(
p_class
->
variables
[
i
].
_export
.
type
!=
Variant
::
NIL
)
{
...
...
@@ -1691,6 +1784,11 @@ Error GDCompiler::_parse_class(GDScript *p_script, GDScript *p_owner, const GDPa
StringName
name
=
p_class
->
constant_expressions
[
i
].
identifier
;
ERR_CONTINUE
(
p_class
->
constant_expressions
[
i
].
expression
->
type
!=
GDParser
::
Node
::
TYPE_CONSTANT
);
if
(
_is_class_member_property
(
p_script
,
name
))
{
_set_error
(
"Member '"
+
name
+
"' already exists as a class property."
,
p_class
);
return
ERR_ALREADY_EXISTS
;
}
GDParser
::
ConstantNode
*
constant
=
static_cast
<
GDParser
::
ConstantNode
*>
(
p_class
->
constant_expressions
[
i
].
expression
);
p_script
->
constants
.
insert
(
name
,
constant
->
value
);
...
...
modules/gdscript/gd_compiler.h
View file @
9e477bab
...
...
@@ -37,6 +37,7 @@ class GDCompiler {
const
GDParser
*
parser
;
struct
CodeGen
{
GDScript
*
script
;
const
GDParser
::
ClassNode
*
class_node
;
const
GDParser
::
FunctionNode
*
function_node
;
...
...
@@ -134,6 +135,9 @@ class GDCompiler {
Ref<GDScript> _parse_class(GDParser::ClassNode *p_class);
#endif
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
GDParser
::
Node
*
p_node
);
bool
_create_unary_operator
(
CodeGen
&
codegen
,
const
GDParser
::
OperatorNode
*
on
,
Variant
::
Operator
op
,
int
p_stack_level
);
...
...
modules/gdscript/gd_editor.cpp
View file @
9e477bab
This diff is collapsed.
Click to expand it.
modules/gdscript/gd_function.cpp
View file @
9e477bab
...
...
@@ -487,7 +487,7 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
case
OPCODE_GET_NAMED
:
{
CHECK_SPACE
(
3
);
CHECK_SPACE
(
4
);
GET_VARIANT_PTR
(
src
,
1
);
GET_VARIANT_PTR
(
dst
,
3
);
...
...
@@ -519,6 +519,46 @@ Variant GDFunction::call(GDInstance *p_instance, const Variant **p_args, int p_a
#endif
ip
+=
4
;
}
continue
;
case
OPCODE_SET_MEMBER
:
{
CHECK_SPACE
(
3
);
int
indexname
=
_code_ptr
[
ip
+
1
];
ERR_BREAK
(
indexname
<
0
||
indexname
>=
_global_names_count
);
const
StringName
*
index
=
&
_global_names_ptr
[
indexname
];
GET_VARIANT_PTR
(
src
,
2
);
bool
valid
;
bool
ok
=
ClassDB
::
set_property
(
p_instance
->
owner
,
*
index
,
*
src
,
&
valid
);
#ifdef DEBUG_ENABLED
if
(
!
ok
)
{
err_text
=
"Internal error setting property: "
+
String
(
*
index
);
break
;
}
else
if
(
!
valid
)
{
err_text
=
"Error setting property '"
+
String
(
*
index
)
+
"' with value of type "
+
Variant
::
get_type_name
(
src
->
get_type
())
+
"."
;
break
;
}
#endif
ip
+=
3
;
}
continue
;
case
OPCODE_GET_MEMBER
:
{
CHECK_SPACE
(
3
);
int
indexname
=
_code_ptr
[
ip
+
1
];
ERR_BREAK
(
indexname
<
0
||
indexname
>=
_global_names_count
);
const
StringName
*
index
=
&
_global_names_ptr
[
indexname
];
GET_VARIANT_PTR
(
dst
,
2
);
bool
ok
=
ClassDB
::
get_property
(
p_instance
->
owner
,
*
index
,
*
dst
);
#ifdef DEBUG_ENABLED
if
(
!
ok
)
{
err_text
=
"Internal error getting property: "
+
String
(
*
index
);
break
;
}
#endif
ip
+=
3
;
}
continue
;
case
OPCODE_ASSIGN
:
{
CHECK_SPACE
(
3
);
...
...
modules/gdscript/gd_function.h
View file @
9e477bab
...
...
@@ -23,6 +23,8 @@ public:
OPCODE_GET
,
OPCODE_SET_NAMED
,
OPCODE_GET_NAMED
,
OPCODE_SET_MEMBER
,
OPCODE_GET_MEMBER
,
OPCODE_ASSIGN
,
OPCODE_ASSIGN_TRUE
,
OPCODE_ASSIGN_FALSE
,
...
...
tools/editor/plugins/script_text_editor.cpp
View file @
9e477bab
...
...
@@ -1363,8 +1363,12 @@ void ScriptTextEditor::register_editor() {
ED_SHORTCUT
(
"script_text_editor/select_all"
,
TTR
(
"Select All"
),
KEY_MASK_CMD
|
KEY_A
);
ED_SHORTCUT
(
"script_text_editor/move_up"
,
TTR
(
"Move Up"
),
KEY_MASK_ALT
|
KEY_UP
);
ED_SHORTCUT
(
"script_text_editor/move_down"
,
TTR
(
"Move Down"
),
KEY_MASK_ALT
|
KEY_DOWN
);
ED_SHORTCUT
(
"script_text_editor/indent_left"
,
TTR
(
"Indent Left"
),
KEY_MASK_ALT
|
KEY_LEFT
);
ED_SHORTCUT
(
"script_text_editor/indent_right"
,
TTR
(
"Indent Right"
),
KEY_MASK_ALT
|
KEY_RIGHT
);
//leave these at zero, same can be accomplished with tab/shift-tab, including selection
//the next/previous in history shortcut in this case makes a lot more sene.
ED_SHORTCUT
(
"script_text_editor/indent_left"
,
TTR
(
"Indent Left"
),
0
);
ED_SHORTCUT
(
"script_text_editor/indent_right"
,
TTR
(
"Indent Right"
),
0
);
ED_SHORTCUT
(
"script_text_editor/toggle_comment"
,
TTR
(
"Toggle Comment"
),
KEY_MASK_CMD
|
KEY_K
);
ED_SHORTCUT
(
"script_text_editor/clone_down"
,
TTR
(
"Clone Down"
),
KEY_MASK_CMD
|
KEY_B
);
#ifdef OSX_ENABLED
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment