summaryrefslogtreecommitdiff
path: root/addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd
diff options
context:
space:
mode:
authorradiohotline <radoihotline@disroot.rg>2026-08-25 16:33:56 +0300
committerradiohotline <radoihotline@disroot.rg>2026-08-25 16:33:56 +0300
commita89e744ed0e8c759caf041a580112365bbfe4303 (patch)
treedd61e320904176995727e86a857d00c90d4933ba /addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd
parent6d53d8cac78250dc888aa49d5f9d4175c6652feb (diff)
escoria updateHEADmain
Diffstat (limited to 'addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd')
-rw-r--r--addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd74
1 files changed, 74 insertions, 0 deletions
diff --git a/addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd b/addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd
new file mode 100644
index 0000000..9faf830
--- /dev/null
+++ b/addons/gdUnit4/src/core/parse/GdUnitExpressionRunner.gd
@@ -0,0 +1,74 @@
+class_name GdUnitExpressionRunner
+extends RefCounted
+
+const CLASS_TEMPLATE = """
+class_name _ExpressionRunner extends '${clazz_path}'
+
+func __run_expression() -> Variant:
+ return $expression
+
+"""
+
+var constructor_args_regex := RegEx.create_from_string("new\\((?<args>.*)\\)")
+
+
+func execute(src_script: GDScript, value: Variant) -> Variant:
+ if typeof(value) != TYPE_STRING:
+ return value
+
+ var expression: String = value
+ var parameter_map := src_script.get_script_constant_map()
+ for key: String in parameter_map.keys():
+ var parameter_value: Variant = parameter_map[key]
+ # check we need to construct from inner class
+ # we need to use the original class instance from the script_constant_map otherwise we run into a runtime error
+ if expression.begins_with(key + ".new") and parameter_value is GDScript:
+ var object: GDScript = parameter_value
+ var args := build_constructor_arguments(parameter_map, expression.substr(expression.find("new")))
+ if args.is_empty():
+ return object.new()
+ return object.callv("new", args)
+
+ var script := GDScript.new()
+ var resource_path := "res://addons/gdUnit4/src/Fuzzers.gd" if src_script.resource_path.is_empty() else src_script.resource_path
+ script.source_code = CLASS_TEMPLATE.dedent()\
+ .replace("${clazz_path}", resource_path)\
+ .replace("$expression", expression)
+ #script.take_over_path(resource_path)
+ @warning_ignore("return_value_discarded")
+ script.reload(true)
+ var runner: Object = script.new()
+ if runner.has_method("queue_free"):
+ (runner as Node).queue_free()
+ @warning_ignore("unsafe_method_access")
+ return runner.__run_expression()
+
+
+func build_constructor_arguments(parameter_map: Dictionary, expression: String) -> Array[Variant]:
+ var result := constructor_args_regex.search(expression)
+ var extracted_arguments := result.get_string("args").strip_edges()
+ if extracted_arguments.is_empty():
+ return []
+ var arguments :Array = extracted_arguments.split(",")
+ return arguments.map(func(argument: String) -> Variant:
+ var value := argument.strip_edges()
+
+ # is argument an constant value
+ if parameter_map.has(value):
+ return parameter_map[value]
+ # is typed named value like Vector3.ONE
+ for type:int in GdObjects.TYPE_AS_STRING_MAPPINGS:
+ var type_as_string:String = GdObjects.TYPE_AS_STRING_MAPPINGS[type]
+ if value.begins_with(type_as_string):
+ return type_convert(value, type)
+ # is value a string
+ if value.begins_with("'") or value.begins_with('"'):
+ return value.trim_prefix("'").trim_suffix("'").trim_prefix('"').trim_suffix('"')
+ # fallback to default value converting
+ return str_to_var(value)
+ )
+
+
+func to_fuzzer(src_script: GDScript, expression: String) -> Fuzzer:
+ @warning_ignore("unsafe_cast")
+ return execute(src_script, expression) as Fuzzer