diff --git a/Test/TestExecuter/TestMenu/TestMenu.gd b/Test/TestExecuter/TestMenu/TestMenu.gd new file mode 100644 index 0000000..115a085 --- /dev/null +++ b/Test/TestExecuter/TestMenu/TestMenu.gd @@ -0,0 +1,25 @@ +extends "res://Test/RakugoTest.gd" + +func test_menu(): + var file_path = "res://Test/TestParser/TestMenu/TestMenu.rk" + + var file_base_name = get_file_base_name(file_path) + + watch_rakugo_signals() + + await wait_parse_and_execute_script(file_path) + + await wait_menu(["Loop", "End"]) + + assert_menu_return(0); + + await wait_menu(["Loop", "End"]) + + assert_menu_return(1); + + await wait_execute_script_finished(file_base_name) + +func test_menu_choice_parse_fail(): + var file_path = "res://Test/TestParser/TestMenu/TestMenuChoiceParseFail.rk" + + assert_eq(Rakugo.parse_script(file_path), FAILED) diff --git a/Test/TestParser/TestMenu/TestMenu.rk b/Test/TestExecuter/TestMenu/TestMenu.rk similarity index 100% rename from Test/TestParser/TestMenu/TestMenu.rk rename to Test/TestExecuter/TestMenu/TestMenu.rk diff --git a/Test/TestExecuter/TestMenu/TestMenu.tscn b/Test/TestExecuter/TestMenu/TestMenu.tscn new file mode 100644 index 0000000..36de018 --- /dev/null +++ b/Test/TestExecuter/TestMenu/TestMenu.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://dmruluk7xrv2e"] + +[ext_resource type="Script" path="res://Test/TestParser/TestMenu/TestMenu.gd" id="1"] + +[node name="TestMenu" type="Node"] +script = ExtResource("1") diff --git a/Test/TestParser/TestMenu/TestMenuChoiceParseFail.rk b/Test/TestExecuter/TestMenu/TestMenuChoiceParseFail.rk similarity index 100% rename from Test/TestParser/TestMenu/TestMenuChoiceParseFail.rk rename to Test/TestExecuter/TestMenu/TestMenuChoiceParseFail.rk diff --git a/Test/TestExecuter/TestSay/TestSay.gd b/Test/TestExecuter/TestSay/TestSay.gd new file mode 100644 index 0000000..3c33a8e --- /dev/null +++ b/Test/TestExecuter/TestSay/TestSay.gd @@ -0,0 +1,28 @@ +extends "res://Test/RakugoTest.gd" + +const file_path = "res://Test/TestParser/TestSay/TestSay.rk" + +var file_base_name = get_file_base_name(file_path) + +func test_say(): + watch_rakugo_signals() + + await wait_parse_and_execute_script(file_path) + + await wait_say({}, "Hello, world !") + + assert_do_step() + + await wait_say({"name": "Sylvie"}, "Hello !") + + assert_do_step() + + await wait_say({}, "My name is Sylvie") + + assert_do_step() + + await wait_say({}, "I am 18") + + assert_do_step() + + await wait_execute_script_finished(file_base_name) diff --git a/Test/TestParser/TestSay/TestSay.rk b/Test/TestExecuter/TestSay/TestSay.rk similarity index 100% rename from Test/TestParser/TestSay/TestSay.rk rename to Test/TestExecuter/TestSay/TestSay.rk diff --git a/Test/TestExecuter/TestSay/TestSay.tscn b/Test/TestExecuter/TestSay/TestSay.tscn new file mode 100644 index 0000000..080bbfd --- /dev/null +++ b/Test/TestExecuter/TestSay/TestSay.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=3 uid="uid://dt8lnvj37mvw0"] + +[ext_resource type="Script" path="res://Test/TestParser/TestSay/TestSay.gd" id="1"] + +[node name="TestSay" type="Node"] +script = ExtResource("1") diff --git a/Test/TestParser/TestMenu/TestMenu.gd b/Test/TestParser/TestMenu/TestMenu.gd index 115a085..2064944 100644 --- a/Test/TestParser/TestMenu/TestMenu.gd +++ b/Test/TestParser/TestMenu/TestMenu.gd @@ -1,25 +1,66 @@ -extends "res://Test/RakugoTest.gd" +extends GutTest -func test_menu(): - var file_path = "res://Test/TestParser/TestMenu/TestMenu.rk" +const Parser = preload("res://addons/Rakugo/lib/systems/Parser.gd") - var file_base_name = get_file_base_name(file_path) +@onready var parser := Parser.new() - watch_rakugo_signals() - - await wait_parse_and_execute_script(file_path) - - await wait_menu(["Loop", "End"]) +var test_params = [ + [ + "menu menu:", + "\"loop\" > menu", + "\"end\"" + ], + [ + "menu menu:", + " \"loop\" > menu", + " \"end\"" + ], + [ + " menu menu: ", + " \"loop\" > menu ", + " \"end\"" + ], + [ + "menu menu:", + "\"loop\" > menu", + "\"end\"", + "" + ], + [ + "menu menu:", + "\"loop\" > menu", + "\"end\"", + " " + ], + [ + "menu menu:", + "\"loop\" > menu", + "\"end\"", + "\"hello, world !\"" + ], + [ + "menu menu:", + "\"loop\" > menu", + "\"end\"", + "# comment" + ] +] - assert_menu_return(0); +func test_menu(params=use_parameters(test_params)): + var parsed_script = parser.parse_script(params) - await wait_menu(["Loop", "End"]) - - assert_menu_return(1); + assert_false(parsed_script.is_empty()) + + var parsed_array = parsed_script["parse_array"] + + assert_false(parsed_array.is_empty()) + + assert_eq(parsed_script["labels"], {"menu":0}) + + var menu_choice_results = parsed_array[0][2] - await wait_execute_script_finished(file_base_name) + assert_eq(menu_choice_results[0].get_string("text"), "\"loop\"") -func test_menu_choice_parse_fail(): - var file_path = "res://Test/TestParser/TestMenu/TestMenuChoiceParseFail.rk" + assert_eq(menu_choice_results[0].get_string("label"), "menu") - assert_eq(Rakugo.parse_script(file_path), FAILED) + assert_eq(menu_choice_results[1].get_string("text"), "\"end\"") diff --git a/Test/TestParser/TestMenu/TestMenu.tscn b/Test/TestParser/TestMenu/TestMenu.tscn index 36de018..64a6151 100644 --- a/Test/TestParser/TestMenu/TestMenu.tscn +++ b/Test/TestParser/TestMenu/TestMenu.tscn @@ -1,6 +1,6 @@ -[gd_scene load_steps=2 format=3 uid="uid://dmruluk7xrv2e"] +[gd_scene load_steps=2 format=3 uid="uid://cryjirfvh5cuq"] -[ext_resource type="Script" path="res://Test/TestParser/TestMenu/TestMenu.gd" id="1"] +[ext_resource type="Script" path="res://Test/TestParser/TestMenu/TestMenu.gd" id="1_roxlx"] [node name="TestMenu" type="Node"] -script = ExtResource("1") +script = ExtResource("1_roxlx") diff --git a/Test/TestParser/TestSay/TestSay.gd b/Test/TestParser/TestSay/TestSay.gd index 3c33a8e..206ef18 100644 --- a/Test/TestParser/TestSay/TestSay.gd +++ b/Test/TestParser/TestSay/TestSay.gd @@ -1,28 +1,73 @@ -extends "res://Test/RakugoTest.gd" +extends GutTest -const file_path = "res://Test/TestParser/TestSay/TestSay.rk" +const Parser = preload("res://addons/Rakugo/lib/systems/Parser.gd") -var file_base_name = get_file_base_name(file_path) +@onready var parser := Parser.new() -func test_say(): - watch_rakugo_signals() +var test_params = [ + ["\"Hello, world !\""], + [" \"Hello, world !\""], + [" \"Hello, world !\""], + ["\"Hello, world !\" "] +] - await wait_parse_and_execute_script(file_path) +func test_say(params=use_parameters(test_params)): + var parsed_script = parser.parse_script(params) + + assert_false(parsed_script.is_empty()) - await wait_say({}, "Hello, world !") + var parsed_array = parsed_script["parse_array"] - assert_do_step() + assert_false(parsed_array.is_empty()) - await wait_say({"name": "Sylvie"}, "Hello !") + assert_true(parsed_script.get("labels", [""]).is_empty()) - assert_do_step() + assert_true(parsed_array[0][0] == "SAY") - await wait_say({}, "My name is Sylvie") + var result = parsed_array[0][1] - assert_do_step() + assert_eq(result.get_string("text"), "\"Hello, world !\"") + +func test_say_character(): + var rk_script = [ + "sy \"Hello !\"" + ] + + var parsed_script = parser.parse_script(rk_script) + + assert_false(parsed_script.is_empty()) + + var parsed_array = parsed_script["parse_array"] + + assert_false(parsed_array.is_empty()) - await wait_say({}, "I am 18") + assert_true(parsed_script.get("labels", [""]).is_empty()) + + assert_true(parsed_array[0][0] == "SAY") + + var result = parsed_array[0][1] + + assert_eq(result.get_string("character_tag"), "sy") - assert_do_step() + assert_eq(result.get_string("text"), "\"Hello !\"") - await wait_execute_script_finished(file_base_name) +func test_say_variable(): + var rk_script = [ + "\"My name is \"" + ] + + var parsed_script = parser.parse_script(rk_script) + + assert_false(parsed_script.is_empty()) + + var parsed_array = parsed_script["parse_array"] + + assert_false(parsed_array.is_empty()) + + assert_true(parsed_script.get("labels", [""]).is_empty()) + + assert_true(parsed_array[0][0] == "SAY") + + var result = parsed_array[0][1] + + assert_eq(result.get_string("text"), "\"My name is \"") \ No newline at end of file diff --git a/Test/TestParser/TestSay/TestSay.tscn b/Test/TestParser/TestSay/TestSay.tscn index 080bbfd..1dafedf 100644 --- a/Test/TestParser/TestSay/TestSay.tscn +++ b/Test/TestParser/TestSay/TestSay.tscn @@ -1,6 +1,6 @@ -[gd_scene load_steps=2 format=3 uid="uid://dt8lnvj37mvw0"] +[gd_scene load_steps=2 format=3 uid="uid://e4471uaguj8k"] -[ext_resource type="Script" path="res://Test/TestParser/TestSay/TestSay.gd" id="1"] +[ext_resource type="Script" path="res://Test/TestParser/TestSay/TestSay.gd" id="1_ux5ov"] [node name="TestSay" type="Node"] -script = ExtResource("1") +script = ExtResource("1_ux5ov") diff --git a/addons/Rakugo/lib/systems/Parser.gd b/addons/Rakugo/lib/systems/Parser.gd index 4411d70..dce7af4 100644 --- a/addons/Rakugo/lib/systems/Parser.gd +++ b/addons/Rakugo/lib/systems/Parser.gd @@ -143,116 +143,106 @@ func parse_script(lines:PackedStringArray) -> Dictionary: for i in lines.size(): var line = lines[i] - - if line.is_empty() or line.begins_with("#"): - continue - - # TODO handle indentation levels - indent_count = count_indent(line) - - #erase tabulations - line = line.lstrip(' ') - - if line.is_empty(): - continue + + line = line.strip_edges() + + var isEmptyLine = line.is_empty() or line.begins_with("#") - if state == State.Menu and indent_count == 0: - state = State.Normal + if state == State.Menu: + var result = regex_cache["CHOICE"].search(line) + + if isEmptyLine or !result: + if !menu_choices.is_empty(): + parse_array.push_back(["MENU", current_menu_result, menu_choices]) + state = State.Normal + else: +# prints("Parser", "parse_script", "CHOICE") +# +# for key in result.names: +# prints(" ", key, result.get_string(key)) + + menu_choices.push_back(result) -# prints("Parser", "parse_script", "mod Normal") + if i == lines.size() - 1: + parse_array.push_back(["MENU", current_menu_result, menu_choices]) + + continue - if !menu_choices.is_empty(): - parse_array.push_back(["MENU", current_menu_result, menu_choices]) + if isEmptyLine: + continue - match(state): - State.Normal: - var have_find_key := false - - for key in regex_cache: - var result = regex_cache[key].search(line) - - if result: - have_find_key = true + var have_find_key := false + + for key in regex_cache: + var result = regex_cache[key].search(line) + + if result: + have_find_key = true - match(key): - "MENU": - current_menu_result = result + match(key): + "MENU": + current_menu_result = result + + menu_choices = [] + + state = State.Menu + + var label = result.get_string("label") + + if !label.is_empty(): + labels[label] = parse_array.size() + + "DIALOGUE": + var dialogue_label = result.get_string("label") + + labels[dialogue_label] = parse_array.size() - menu_choices = [] - - state = State.Menu - - var label = result.get_string("label") - - if !label.is_empty(): - labels[label] = parse_array.size() - - "DIALOGUE": - var dialogue_label = result.get_string("label") - - labels[dialogue_label] = parse_array.size() - - "JUMP": - var str_expression:String = result.get_string("expression") + "JUMP": + var str_expression:String = result.get_string("expression") - if str_expression.is_empty(): - parse_array.push_back([key, result]) - break + if str_expression.is_empty(): + parse_array.push_back([key, result]) + break - var sub_results = other_cache["VARIABLE"].search_all(str_expression) + var sub_results = other_cache["VARIABLE"].search_all(str_expression) - var vars = [] + var vars = [] - # Expression does not like '.' - var vars_expression = [] + # Expression does not like '.' + var vars_expression = [] - for sub_result in sub_results: - var sub_result_str = sub_result.strings[0] - - if !vars.has(sub_result_str): - vars.push_back(sub_result_str) + for sub_result in sub_results: + var sub_result_str = sub_result.strings[0] + + if !vars.has(sub_result_str): + vars.push_back(sub_result_str) - var var_name_expr = sub_result.get_string("char_tag") + var var_name_expr = sub_result.get_string("char_tag") - if !var_name_expr.is_empty(): - var_name_expr += "_" + sub_result.get_string("var_name") + if !var_name_expr.is_empty(): + var_name_expr += "_" + sub_result.get_string("var_name") - str_expression = str_expression.replace(sub_result_str, var_name_expr) - else: - var_name_expr = sub_result.get_string("var_name") - - if !vars_expression.has(var_name_expr): - vars_expression.push_back(var_name_expr) + str_expression = str_expression.replace(sub_result_str, var_name_expr) + else: + var_name_expr = sub_result.get_string("var_name") + + if !vars_expression.has(var_name_expr): + vars_expression.push_back(var_name_expr) - var expression = Expression.new() + var expression = Expression.new() - if expression.parse(str_expression, vars_expression) != OK: - push_error("Parser: Error on line: " + str(i+1) + ", " + expression.get_error_text()) - return {} + if expression.parse(str_expression, vars_expression) != OK: + push_error("Parser: Error on line: " + str(i+1) + ", " + expression.get_error_text()) + return {} - parse_array.push_back([key, result, expression, vars]) + parse_array.push_back([key, result, expression, vars]) - _: - parse_array.push_back([key, result]) - break + _: + parse_array.push_back([key, result]) + break - if (not have_find_key): - push_error("Parser: Error on line: " + str(i+1) + ", can not parse it !") - return {} - State.Menu: - var result = regex_cache["CHOICE"].search(line) - if result: -# prints("Parser", "parse_script", "CHOICE") -# -# for key in result.names: -# prints(" ", key, result.get_string(key)) - - menu_choices.push_back(result) - - if i == lines.size() - 1: - parse_array.push_back(["MENU", current_menu_result, menu_choices]) - else: - push_error("Parser: Error on line: " + str(i+1) + ", it is not a choice !") - return {} + if (not have_find_key): + push_error("Parser: Error on line: " + str(i+1) + ", can not parse it !") + return {} return {"parse_array":parse_array, "labels":labels}