Skip to content

Commit 461016c

Browse files
committed
Fix v1.0 bugs
1 parent abe1993 commit 461016c

File tree

9 files changed

+477
-29
lines changed

9 files changed

+477
-29
lines changed

addons/gdscript_preprocessor/export_plugin.gd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ func _get_export_options(_platform: EditorExportPlatform) -> Array[Dictionary]:
2525
name = "gdscript_preprocessor/statement_removing_regex_release",
2626
type = TYPE_STRING,
2727
},
28-
default_value = r"^(?:breakpoint|assert\(|print_debug\(|print_stack\()",
28+
default_value = r"^(?:@tool|breakpoint|assert\(|print_debug\(|print_stack\()",
2929
},
3030
{
3131
option = {
@@ -73,6 +73,7 @@ func _export_file(path: String, type: String, _features: PackedStringArray) -> v
7373
return
7474

7575
if _preprocessor.preprocess(FileAccess.get_file_as_string(path)):
76+
skip()
7677
add_file(path, _preprocessor.result.to_utf8_buffer(), false)
7778
else:
7879
printerr("%s:%s - %s" % [

addons/gdscript_preprocessor/preprocessor.gd

Lines changed: 148 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,22 @@ enum _Trilean {FALSE = -1, UNKNOWN = 0, TRUE = +1}
66

77
enum _Status {
88
NORMAL, # Non-conditional block.
9-
# Conditional block (`if`/`elif`/`else`):
10-
WAITING, # Replace next non-`FALSE` `elif` with `if` or `else` with `if true`.
11-
STARTED, # `if` was outputted (some `if`/`elif` was UNKNOWN).
12-
FINISHED, # `TRUE` branch was found. Next `elif`/`else` blocks must be removed.
9+
# Conditional block (`if`/`elif`/`else`)
10+
# ======================================
11+
# Nothing outputted yet.
12+
# Replace next non-`FALSE` `elif` with `if` or `else` with `if true`.
13+
WAITING,
14+
# `if` was outputted (some `if`/`elif` was `UNKNOWN`).
15+
STARTED,
16+
# The end is reached (a `TRUE` branch or `else` in source code).
17+
# Next `elif`/`else` blocks must be removed.
18+
FINISHED,
1319
}
1420

1521
class _Block extends RefCounted:
1622
var indent: int
1723
var empty: bool
24+
var has_return: bool
1825
var state: _Trilean
1926
var status: _Status
2027

@@ -34,6 +41,51 @@ const _SMALL_R: int = 0x0072 # "r"
3441
const _BRACE_OPEN: int = 0x007B # "{"
3542
const _BRACE_CLOSE: int = 0x007D # "}"
3643

44+
enum _Context {
45+
NONE,
46+
FUNC,
47+
VAR,
48+
}
49+
50+
const _VARIANT_DEFAULTS: Dictionary = {
51+
"bool": "false",
52+
"int": "0",
53+
"float": "0.0",
54+
"String": '""',
55+
"Vector2": "Vector2()",
56+
"Vector2i": "Vector2i()",
57+
"Rect2": "Rect2()",
58+
"Rect2i": "Rect2i()",
59+
"Vector3": "Vector3()",
60+
"Vector3i": "Vector3i()",
61+
"Transform2D": "Transform2D()",
62+
"Vector4": "Vector4()",
63+
"Vector4i": "Vector4i()",
64+
"Plane": "Plane()",
65+
"Quaternion": "Quaternion()",
66+
"AABB": "AABB()",
67+
"Basis": "Basis()",
68+
"Transform3D": "Transform3D()",
69+
"Projection": "Projection()",
70+
"Color": "Color()",
71+
"StringName": '&""',
72+
"NodePath": '^""',
73+
"RID": "RID()",
74+
"Callable": "Callable()",
75+
"Signal": "Signal()",
76+
"Dictionary": "{}",
77+
"Array": "[]",
78+
"PackedByteArray": "PackedByteArray()",
79+
"PackedInt32Array": "PackedInt32Array()",
80+
"PackedInt64Array": "PackedInt64Array()",
81+
"PackedFloat32Array": "PackedFloat32Array()",
82+
"PackedFloat64Array": "PackedFloat64Array()",
83+
"PackedStringArray": "PackedStringArray()",
84+
"PackedVector2Array": "PackedVector2Array()",
85+
"PackedVector3Array": "PackedVector3Array()",
86+
"PackedColorArray": "PackedColorArray()",
87+
}
88+
3789
const _PARENS: Dictionary = {
3890
_PAREN_OPEN: _PAREN_CLOSE,
3991
_BRACKET_OPEN: _BRACKET_CLOSE,
@@ -59,12 +111,22 @@ var _indent_char_str: String
59111
var _indent_char: int
60112
var _indent_size: int
61113

62-
var _root_parent: _Block # A fake parent of root.
63-
var _block_stack: Array[_Block]
64114
var _if_directive_stack: Array[bool]
65115
var _output_enabled: bool = true
116+
117+
var _root_parent: _Block # A fake parent of root.
118+
var _block_stack: Array[_Block]
119+
120+
var _context: _Context = _Context.NONE
121+
var _fake_return: String
122+
var _var_fake_return: String
123+
66124
var _paren_stack: Array[int]
67125

126+
var _func_type_regex: RegEx = RegEx.create_from_string(
127+
r"""->\s*([^\s\["']+)\s*(?:\[[^\["']+\])?\s*:$""")
128+
var _var_type_regex: RegEx = RegEx.create_from_string(
129+
r"""^var[^:=]+:\s*([^\s:=\["']+)""")
68130
var _os_has_feature_regex: RegEx = RegEx.create_from_string(
69131
r"""OS\.has_feature\((["'])(\w+)\1\)""")
70132
var _condition_regex: RegEx = RegEx.create_from_string(
@@ -92,11 +154,17 @@ func preprocess(source_code: String) -> bool:
92154
_indent_char = 0
93155
_indent_size = 0
94156

157+
_if_directive_stack.clear()
158+
_output_enabled = true
159+
95160
_root_parent = _Block.new()
96161
_block_stack.clear()
97162
_block_stack.push_back(_Block.new())
98-
_if_directive_stack.clear()
99-
_output_enabled = true
163+
164+
_context = _Context.NONE
165+
_fake_return = ""
166+
_var_fake_return = ""
167+
100168
_paren_stack.clear()
101169

102170
while _position < _length:
@@ -120,8 +188,19 @@ func preprocess(source_code: String) -> bool:
120188
var last_empty_block: _Block = null
121189
while not _block_stack.is_empty():
122190
var block: _Block = _block_stack.pop_back()
191+
192+
if block.indent == 1:
193+
if _context == _Context.FUNC and _fake_return and not block.has_return:
194+
_append(block.indent, _fake_return)
195+
block.empty = false
196+
elif block.indent == 2:
197+
if _context == _Context.VAR and _fake_return and not block.has_return:
198+
_append(block.indent, _fake_return)
199+
block.empty = false
200+
123201
if block.empty:
124202
last_empty_block = block
203+
125204
if last_empty_block and last_empty_block.state != _Trilean.FALSE:
126205
_append(last_empty_block.indent + _indent_size, "pass")
127206

@@ -259,22 +338,61 @@ func _parse_statement() -> bool:
259338
var last_empty_block: _Block = null
260339
while indent_level < _block_stack.back().indent:
261340
var block: _Block = _block_stack.pop_back()
341+
342+
if block.indent == 1:
343+
if _context == _Context.FUNC and _fake_return and not block.has_return:
344+
_append(block.indent, _fake_return)
345+
block.empty = false
346+
elif block.indent == 2:
347+
if _context == _Context.VAR and _fake_return and not block.has_return:
348+
_append(block.indent, _fake_return)
349+
block.empty = false
350+
262351
if block.empty:
263352
last_empty_block = block
353+
264354
current_block = _block_stack.back()
265355
if current_block.empty:
266356
last_empty_block = current_block
357+
267358
if last_empty_block and last_empty_block.state != _Trilean.FALSE:
268359
_append(last_empty_block.indent + _indent_size, "pass")
269360

361+
if indent_level == 0:
362+
_context = _Context.NONE
363+
_fake_return = ""
364+
_var_fake_return = ""
365+
366+
if string.begins_with("func"):
367+
_context = _Context.FUNC
368+
var regex_match: RegExMatch = _func_type_regex.search(string)
369+
if regex_match:
370+
var type: String = regex_match.get_string(1)
371+
if type != "void":
372+
_fake_return = "return " + _VARIANT_DEFAULTS.get(type, "null")
373+
elif string.begins_with("var"):
374+
_context = _Context.VAR
375+
var regex_match: RegExMatch = _var_type_regex.search(string)
376+
if regex_match:
377+
_var_fake_return = "return " + _VARIANT_DEFAULTS.get(
378+
regex_match.get_string(1), "null")
379+
else:
380+
_var_fake_return = "return null"
381+
elif indent_level == 1:
382+
if _context == _Context.VAR:
383+
if string.begins_with("get:") or string.begins_with("get():"):
384+
_fake_return = _var_fake_return
385+
else:
386+
_fake_return = ""
387+
270388
var parent_block: _Block
271389
if _block_stack.size() > 1:
272390
parent_block = _block_stack[-2]
273391
else:
274392
parent_block = _root_parent
275393

276394
if string.begins_with("if "):
277-
if parent_block.state == _Trilean.FALSE:
395+
if parent_block.state == _Trilean.FALSE or current_block.has_return:
278396
current_block.state = _Trilean.FALSE
279397
return true
280398

@@ -293,7 +411,8 @@ func _parse_statement() -> bool:
293411
current_block.status = _Status.FINISHED
294412

295413
elif string.begins_with("elif "):
296-
if parent_block.state == _Trilean.FALSE or current_block.status == _Status.FINISHED:
414+
if parent_block.state == _Trilean.FALSE or current_block.has_return \
415+
or current_block.status == _Status.FINISHED:
297416
current_block.state = _Trilean.FALSE
298417
return true
299418

@@ -316,30 +435,23 @@ func _parse_statement() -> bool:
316435
current_block.status = _Status.FINISHED
317436

318437
elif string.begins_with("else:"):
319-
if parent_block.state == _Trilean.FALSE or current_block.status == _Status.FINISHED:
438+
if parent_block.state == _Trilean.FALSE or current_block.has_return \
439+
or current_block.status == _Status.FINISHED:
320440
current_block.state = _Trilean.FALSE
321441
return true
322442

323443
@warning_ignore("int_as_enum_without_cast")
324444
current_block.state = -current_block.state # Fast trilean NOT.
325-
match current_block.state:
326-
_Trilean.UNKNOWN:
327-
if current_block.status == _Status.WAITING:
328-
_append(current_block.indent, "if true:" + string.substr(string_colon_pos + 1))
329-
parent_block.empty = false
330-
current_block.status = _Status.STARTED
331-
else:
332-
_append(current_block.indent, "else:" + string.substr(string_colon_pos + 1))
333-
_Trilean.TRUE:
334-
if current_block.status == _Status.WAITING:
335-
_append(current_block.indent, "if true:" + string.substr(string_colon_pos + 1))
336-
parent_block.empty = false
337-
else:
338-
_append(current_block.indent, "else:" + string.substr(string_colon_pos + 1))
339-
current_block.status = _Status.FINISHED
445+
# We don't care if it's `UNKNOWN` or `TRUE`.
446+
if current_block.status == _Status.WAITING:
447+
_append(current_block.indent, "if true:" + string.substr(string_colon_pos + 1))
448+
parent_block.empty = false
449+
else:
450+
_append(current_block.indent, string)
451+
current_block.status = _Status.FINISHED
340452

341453
else:
342-
if parent_block.state == _Trilean.FALSE \
454+
if parent_block.state == _Trilean.FALSE or current_block.has_return \
343455
or (statement_removing_regex and statement_removing_regex.search(string)):
344456
current_block.state = _Trilean.FALSE
345457
return true
@@ -351,6 +463,15 @@ func _parse_statement() -> bool:
351463
current_block.empty = false
352464
current_block.state = parent_block.state
353465
current_block.status = _Status.NORMAL
466+
if string.begins_with("return"):
467+
if string.length() == len("return"):
468+
current_block.has_return = true
469+
current_block.state = _Trilean.FALSE
470+
else:
471+
var c: int = string.unicode_at(len("return"))
472+
if c == _SPACE or c == _TAB or c == _PAREN_OPEN:
473+
current_block.has_return = true
474+
current_block.state = _Trilean.FALSE
354475

355476
return true
356477

tests/features/fake_return.gd

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# is_debug=true
2+
3+
var var_set_get: int:
4+
set(value):
5+
if OS.is_debug_build():
6+
prints(1, value)
7+
else:
8+
prints(2, value)
9+
get:
10+
if OS.is_debug_build():
11+
return 1
12+
else:
13+
return 2
14+
15+
var var_get_set: int:
16+
get:
17+
if OS.is_debug_build():
18+
return 1
19+
else:
20+
return 2
21+
set(value):
22+
if OS.is_debug_build():
23+
prints(1, value)
24+
else:
25+
prints(2, value)
26+
27+
@warning_ignore("untyped_declaration")
28+
var var_untyped:
29+
get:
30+
if OS.is_debug_build():
31+
return 1
32+
else:
33+
return 2
34+
35+
var var_int: int:
36+
get:
37+
if OS.is_debug_build():
38+
return 1
39+
else:
40+
return 2
41+
42+
var var_array_int: Array[int]:
43+
get:
44+
if OS.is_debug_build():
45+
return [1]
46+
else:
47+
return [2]
48+
49+
var var_object: Object:
50+
get:
51+
if OS.is_debug_build():
52+
return Node.new()
53+
else:
54+
return Resource.new()
55+
56+
@warning_ignore("untyped_declaration")
57+
func func_untyped():
58+
if OS.is_debug_build():
59+
return
60+
else:
61+
return
62+
63+
func func_void() -> void:
64+
if OS.is_debug_build():
65+
return
66+
else:
67+
return
68+
69+
func func_int() -> int:
70+
if OS.is_debug_build():
71+
return 1
72+
else:
73+
return 2
74+
75+
func func_array_int() -> Array[int]:
76+
if OS.is_debug_build():
77+
return [1]
78+
else:
79+
return [2]
80+
81+
func func_object() -> Object:
82+
if OS.is_debug_build():
83+
return Node.new()
84+
else:
85+
return Resource.new()

0 commit comments

Comments
 (0)