@@ -6,15 +6,22 @@ enum _Trilean {FALSE = -1, UNKNOWN = 0, TRUE = +1}
66
77enum _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
1521class _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"
3441const _BRACE_OPEN : int = 0x007B # "{"
3542const _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+
3789const _PARENS : Dictionary = {
3890 _PAREN_OPEN : _PAREN_CLOSE ,
3991 _BRACKET_OPEN : _BRACKET_CLOSE ,
@@ -59,12 +111,22 @@ var _indent_char_str: String
59111var _indent_char : int
60112var _indent_size : int
61113
62- var _root_parent : _Block # A fake parent of root.
63- var _block_stack : Array [_Block ]
64114var _if_directive_stack : Array [bool ]
65115var _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+
66124var _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 :=\[ "']+)""" )
68130var _os_has_feature_regex : RegEx = RegEx .create_from_string (
69131 r """OS\. has_feature\( (["'])(\w +)\1\) """ )
70132var _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
0 commit comments