Allow for omitting return keyword even when parsing as Expression fails, so long as the line of input does not look like a single non-expression statement legal in isolation in a function body.
This commit is contained in:
parent
c3b0f0033f
commit
7064808235
|
@ -38,10 +38,6 @@ there are some less-than-intuitive caveats:
|
|||
any variable assignments prior in the input line,
|
||||
even to preexisting variables, will be undone.
|
||||
This will preserve `x`: `x = 6`. This will not: `x = 6; return x`.
|
||||
3. For the sake of shorthand, an assignment statement alone on its input line
|
||||
and assigning to a nonexistent variable will act like a declaration instead.
|
||||
That is to say, if `x` does not exist, `x = 6` all by itself
|
||||
will act like `var x = 6`, but `x = 6; print(x)` will be an error.
|
||||
|
||||
You may not declare classes.
|
||||
|
||||
|
|
|
@ -37,11 +37,6 @@ there are some less-than-intuitive caveats:
|
|||
including a `return` statement, and that statement is reached,
|
||||
any variable assignments prior in the input line,
|
||||
even to preexisting variables, will be undone.
|
||||
This will preserve `x`: `x = 6`. This will not: `x = 6; return x`.
|
||||
3. For the sake of shorthand, an assignment statement alone on its input line
|
||||
and assigning to a nonexistent variable will act like a declaration instead.
|
||||
That is to say, if `x` does not exist, `x = 6` all by itself
|
||||
will act like `var x = 6`, but `x = 6; print(x)` will be an error.
|
||||
|
||||
You may not declare classes.
|
||||
|
||||
|
|
|
@ -8,6 +8,12 @@ var _session: Object
|
|||
var _expression: Expression
|
||||
var _assignment_regex: RegEx
|
||||
var _function_regex: RegEx
|
||||
var _if_regex: RegEx
|
||||
var _for_regex: RegEx
|
||||
var _while_regex: RegEx
|
||||
var _match_regex: RegEx
|
||||
var _return_regex: RegEx
|
||||
var _pass_regex: RegEx
|
||||
|
||||
|
||||
## Traverses the editor's interface tree in search of the EditorLog.
|
||||
|
@ -34,6 +40,38 @@ func _find_parent_for_field() -> VBoxContainer:
|
|||
return null
|
||||
|
||||
|
||||
## Checks if a code snippet is multiple statements
|
||||
## (has semicolons outside strings).
|
||||
func _is_multiple_statements(code: String) -> bool:
|
||||
var quotetype: int = 0x0
|
||||
var escape := false
|
||||
for i in code.length():
|
||||
match code.unicode_at(i):
|
||||
0x22: # "
|
||||
if quotetype == 0x22:
|
||||
if not escape:
|
||||
quotetype = 0x0
|
||||
else:
|
||||
quotetype = 0x22
|
||||
escape = false
|
||||
0x27: # '
|
||||
if quotetype == 0x27:
|
||||
if not escape:
|
||||
quotetype = 0x0
|
||||
else:
|
||||
quotetype = 0x27
|
||||
escape = false
|
||||
0x3b: # ;
|
||||
if quotetype == 0x0:
|
||||
return true
|
||||
0x5c: # \
|
||||
if quotetype != 0x0:
|
||||
escape = not escape
|
||||
_:
|
||||
escape = false
|
||||
return false
|
||||
|
||||
|
||||
## Creates and executes a GDScript function from a given code string.
|
||||
func _exec(code: String) -> Variant:
|
||||
var result: Variant
|
||||
|
@ -42,13 +80,12 @@ func _exec(code: String) -> Variant:
|
|||
var oneliner = code.replace("\n", ' ').replace("\r", ' ')
|
||||
var rxmatch: RegExMatch
|
||||
# First check if it's a variable assignment.
|
||||
if oneliner.find(';') < 0:
|
||||
rxmatch = _assignment_regex.search(oneliner)
|
||||
if rxmatch:
|
||||
_session._vars[rxmatch.get_string(1)] = _exec(
|
||||
rxmatch.get_string(2)
|
||||
)
|
||||
return null
|
||||
rxmatch = _assignment_regex.search(oneliner)
|
||||
if rxmatch:
|
||||
_session._vars[rxmatch.get_string(1)] = _exec(
|
||||
rxmatch.get_string(2)
|
||||
)
|
||||
return null
|
||||
# Otherwise:
|
||||
# Collect varnames and varvals.
|
||||
for varname in _session._vars:
|
||||
|
@ -87,7 +124,23 @@ func _exec(code: String) -> Variant:
|
|||
""".dedent()
|
||||
for varname in varnames:
|
||||
src += "\tvar %s = _vars['%s']\n" % [varname, varname]
|
||||
src += code.indent("\t") + "\n"
|
||||
# Check if we should prepend `return`.
|
||||
var should_prepend_return := true
|
||||
# If the code is any of these kinds of statement, we should not:
|
||||
if _if_regex.search(oneliner) or \
|
||||
_for_regex.search(oneliner) or \
|
||||
_while_regex.search(oneliner) or \
|
||||
_match_regex.search(oneliner) or \
|
||||
_return_regex.search(oneliner) or \
|
||||
_pass_regex.search(oneliner):
|
||||
should_prepend_return = false
|
||||
# If the code is multiple statements, we should not:
|
||||
if _is_multiple_statements(code):
|
||||
should_prepend_return = false
|
||||
if should_prepend_return:
|
||||
src += ("return " + code).indent("\t") + "\n"
|
||||
else:
|
||||
src += code.indent("\t") + "\n"
|
||||
for varname in varnames:
|
||||
src += "\t_vars['%s'] = %s\n" % [varname, varname]
|
||||
_session_script.source_code = src
|
||||
|
@ -123,12 +176,25 @@ func _enter_tree() -> void:
|
|||
_session_script.reload()
|
||||
_session = _session_script.new()
|
||||
_expression = Expression.new()
|
||||
# Create regex.
|
||||
_assignment_regex = RegEx.new()
|
||||
_assignment_regex.compile("^\\s*(?:var)?\\s*([a-zA-Z0-9_]+)\\s*=(.+)$")
|
||||
_assignment_regex.compile("^\\s*var\\s*([a-zA-Z0-9_]+)\\s*=(.+)$")
|
||||
_function_regex = RegEx.new()
|
||||
_function_regex.compile(
|
||||
"^\\s*func\\s*([a-zA-Z0-9_]+)\\s*\\((.+?)\\)\\s*:\\s*(.+)$"
|
||||
)
|
||||
_if_regex = RegEx.new()
|
||||
_if_regex.compile("^\\s*if[\\s\\(].*$")
|
||||
_for_regex = RegEx.new()
|
||||
_for_regex.compile("^\\s*for[\\s\\(].*$")
|
||||
_while_regex = RegEx.new()
|
||||
_while_regex.compile("^\\s*while[\\s\\(].*$")
|
||||
_match_regex = RegEx.new()
|
||||
_match_regex.compile("^\\s*match[\\s\\(].*$")
|
||||
_return_regex = RegEx.new()
|
||||
_return_regex.compile("^\\s*return(?:[\\s\\(].*)?$")
|
||||
_pass_regex = RegEx.new()
|
||||
_pass_regex.compile("^\\s*pass(?:[\\s\\(].*)?$")
|
||||
# Add input field to tree.
|
||||
var parent := _find_parent_for_field()
|
||||
if parent:
|
||||
|
|
|
@ -14,3 +14,7 @@ config/name="GDScript Input Field Plugin"
|
|||
config/description="Provides an input field in the editor output panel for executing arbitrary GDScript in a REPL-like fashion."
|
||||
config/features=PackedStringArray("4.1", "Forward Plus")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PackedStringArray("res://addons/gdscript_input_field/plugin.cfg")
|
||||
|
|
Loading…
Reference in New Issue