diff options
| -rw-r--r-- | Scenes/Game.tscn | 6 | ||||
| -rw-r--r-- | Scripts/Command.cs | 22 | ||||
| -rw-r--r-- | Scripts/CommandParser.cs | 27 | ||||
| -rw-r--r-- | Scripts/Commands/LookCommand.cs | 57 | ||||
| -rw-r--r-- | Scripts/OutputRow.cs | 8 | ||||
| -rw-r--r-- | Tests/ComponentTests/ParserTests/CommandParserTestBase.gd | 29 | ||||
| -rw-r--r-- | Tests/ComponentTests/ParserTests/test_CommandParser.gd | 9 | ||||
| -rw-r--r-- | Tests/ComponentTests/ParserTests/test_LookCommand.gd | 55 | ||||
| -rw-r--r-- | Texty.csproj | 12 | ||||
| -rw-r--r-- | project.godot | 6 |
10 files changed, 209 insertions, 22 deletions
diff --git a/Scenes/Game.tscn b/Scenes/Game.tscn index 5c24cf2..5988f7d 100644 --- a/Scenes/Game.tscn +++ b/Scenes/Game.tscn @@ -1,9 +1,10 @@ -[gd_scene load_steps=5 format=2] +[gd_scene load_steps=6 format=2] [ext_resource path="res://Scenes/InputContainer.tscn" type="PackedScene" id=1] [ext_resource path="res://Scripts/Game.cs" type="Script" id=2] [ext_resource path="res://Scenes/OutputContainer.tscn" type="PackedScene" id=3] [ext_resource path="res://Scenes/OutputRow.tscn" type="PackedScene" id=4] +[ext_resource path="res://Scripts/CommandParser.cs" type="Script" id=5] [node name="Game" type="MarginContainer"] anchor_right = 1.0 @@ -18,6 +19,9 @@ __meta__ = { } OutputRowScene = ExtResource( 4 ) +[node name="CommandParser" type="Node" parent="."] +script = ExtResource( 5 ) + [node name="LayoutContainer" type="VBoxContainer" parent="."] margin_right = 1008.0 margin_bottom = 584.0 diff --git a/Scripts/Command.cs b/Scripts/Command.cs index 4a7ce58..e784576 100644 --- a/Scripts/Command.cs +++ b/Scripts/Command.cs @@ -1,7 +1,25 @@ +using Godot; + namespace Texty.Scripts { - public class Command + public enum CommandType { - + Look + } + + public class Command : Object + { + public Command() + { + } + + public Command(CommandType type, string[] arguments) + { + RawArguments = arguments; + Type = type; + } + + public string[] RawArguments { get; } + public CommandType Type { get; } } }
\ No newline at end of file diff --git a/Scripts/CommandParser.cs b/Scripts/CommandParser.cs index 1394a5e..97d8025 100644 --- a/Scripts/CommandParser.cs +++ b/Scripts/CommandParser.cs @@ -1,14 +1,23 @@ +using System.Linq; using Godot; +using Texty.Scripts.Commands; namespace Texty.Scripts { - public class CommandParser : Node - { - - public override void _Ready() - { - } - - } -} + public class CommandParser : Node + { + public override void _Ready() + { + } + public Command TryParse(string text) + { + var components = text.Split(' '); + return components[0].ToLower() switch + { + "look" => new LookCommand(components.Skip(1).ToArray()), + _ => null + }; + } + } +}
\ No newline at end of file diff --git a/Scripts/Commands/LookCommand.cs b/Scripts/Commands/LookCommand.cs new file mode 100644 index 0000000..08783a9 --- /dev/null +++ b/Scripts/Commands/LookCommand.cs @@ -0,0 +1,57 @@ +using System.Linq; + +namespace Texty.Scripts.Commands +{ + public enum LookModifier + { + At, + Around + } + + public class LookCommand : Command + { + public LookCommand() + { + } + + public LookCommand(string[] arguments) : base(CommandType.Look, arguments) + { + (Modifier, arguments) = TryParseModifier(arguments); + Target = string.Join(" ", arguments); + } + + public string Target { get; } + public LookModifier? Modifier { get; } + + /// <summary> + /// Access this <c>LookCommand</c>'s modifier as a string. + /// </summary> + /// <remarks> + /// This function is provided as a means for testing the modifier parsing from GDScript. + /// </remarks> + private string ModifierAsString => Modifier?.ToString(); + + public override string ToString() + { + return $"look {ModifierAsString?.ToLower()} {string.Join(" ", Target)}"; + } + + /// <summary> + /// Try to parse this <c>LookCommand</c>'s modifier from the given arguments. + /// </summary> + /// <param name="arguments">The arguments given to this look commands</param> + /// <returns>A pair consisting of the parse modifier and the remaining arguments</returns> + private static (LookModifier?, string[]) TryParseModifier(string[] arguments) + { + if (arguments.Length == 0) + return (null, arguments); + + return arguments[0].ToLower() switch + { + "at" => (LookModifier.At, arguments.Skip(1).ToArray()), + "around" => (LookModifier.Around, new string[] { }), + _ => (null, arguments) + }; + } + } +}
\ No newline at end of file diff --git a/Scripts/OutputRow.cs b/Scripts/OutputRow.cs index 15a6454..13d9293 100644 --- a/Scripts/OutputRow.cs +++ b/Scripts/OutputRow.cs @@ -11,12 +11,12 @@ namespace Texty.Scripts [Signal] public delegate void OutputTextChanged(string newText); - public Label Input; - public Label Output; - private string _inputText = ""; private string _outputText = ""; + public Label Input; + public Label Output; + [Export] public string InputText { @@ -69,4 +69,4 @@ namespace Texty.Scripts Output } } -}
\ No newline at end of file +}
\ No newline at end of file diff --git a/Tests/ComponentTests/ParserTests/CommandParserTestBase.gd b/Tests/ComponentTests/ParserTests/CommandParserTestBase.gd new file mode 100644 index 0000000..6e452cb --- /dev/null +++ b/Tests/ComponentTests/ParserTests/CommandParserTestBase.gd @@ -0,0 +1,29 @@ +extends GutTest + +class_name CommandParserTestBase + +const CommandParser = preload("res://Scripts/CommandParser.cs") + +var _instance: CommandParser + +func _to_bits(number: int, bits: int) -> Array: + var result = [] + for bit in bits: + result.append(number & 1) + number = number >> 1 + return result + +func before_each(): + _instance = autofree(CommandParser.new()) + +func generate_capitalization_permutations(text: String) -> Array: + var result = [] + + for permutation in pow(2, text.length()): + var mask = _to_bits(permutation, text.length()) + var copy = String(text) + for index in len(mask): + if mask[index] == 1: + copy[index] = copy[index].to_upper() + result.append(copy) + return result; diff --git a/Tests/ComponentTests/ParserTests/test_CommandParser.gd b/Tests/ComponentTests/ParserTests/test_CommandParser.gd new file mode 100644 index 0000000..bdb14a6 --- /dev/null +++ b/Tests/ComponentTests/ParserTests/test_CommandParser.gd @@ -0,0 +1,9 @@ +extends CommandParserTestBase + +const Command = preload("res://Scripts/Command.cs") + +func parse(input: String) -> Command: + return autofree(_instance.TryParse(input)) + +func test_parsing_the_empty_string_returns_null(): + assert_null(parse('')) diff --git a/Tests/ComponentTests/ParserTests/test_LookCommand.gd b/Tests/ComponentTests/ParserTests/test_LookCommand.gd new file mode 100644 index 0000000..32268b0 --- /dev/null +++ b/Tests/ComponentTests/ParserTests/test_LookCommand.gd @@ -0,0 +1,55 @@ +extends CommandParserTestBase + +const LookCommand = preload("res://Scripts/Commands/LookCommand.cs") + +var _around_permutations = generate_capitalization_permutations('around') +var _at_permutations = generate_capitalization_permutations('at') +var _look_permutations = generate_capitalization_permutations('look') + +func parse(input: String) -> LookCommand: + return autofree(_instance.TryParse(input)) + +func test_parsing_look_command_without_an_argument_returns_non_null(): + assert_not_null(parse('look')) + +func test_parsing_look_command_is_case_insensitive(permutation=use_parameters(_look_permutations)): + assert_not_null(parse(permutation)) + +func test_parsing_look_command_without_an_argument_returns_look_command_with_an_emtpy_target(): + assert_eq('', parse('look').Target) + +func test_parsing_look_at_command_is_case_insensitive(permutation=use_parameters(_at_permutations)): + assert_not_null(parse('look ' + permutation)) + +func test_parsing_look_at_command_without_further_arguments_returns_look_command_with_an_emtpy_target(): + assert_eq('', parse('look at').Target) + +func test_parsing_look_at_command_without_further_arguments_returns_look_command_with_non_null_modifier(): + assert_not_null(parse('look at').Modifier) + +func test_parsing_look_at_command_without_further_arguments_returns_look_command_with_at_modifier(): + assert_eq('At', parse('look at').ModifierAsString) + +func test_parsing_look_at_command_with_more_arguments_returns_look_command_with_non_empty_target(): + assert_ne('', parse('look at door on the left').Target) + +func test_parsing_look_at_command_with_an_additional_argument_returns_look_command_with_the_additional_argument_as_the_target(): + assert_eq('window', parse('look at window').Target) + +func test_parsing_look_at_command_with_multiple_additional_arguments_returns_look_command_with_the_additional_arguments_as_the_target(): + assert_eq('table near the door', parse('look at table near the door').Target) + +func test_parsing_look_around_command_is_case_insensitive(permutation=use_parameters(_around_permutations)): + assert_not_null(parse('look ' + permutation)) + +func test_parsing_look_around_command_without_further_arguments_returns_look_command_with_an_empty_target(): + assert_eq('', parse('look around').Target) + +func test_parsing_look_around_command_without_further_arguments_returns_look_command_with_non_null_modifier(): + assert_not_null(parse('look around').Modifier) + +func test_parsing_look_around_command_without_further_arguments_returns_look_command_with_around_modifier(): + assert_eq('Around', parse('look around').ModifierAsString) + +func test_parsing_look_around_command_ignores_all_additional_arguments(): + assert_eq('', parse('look around the room').Target) diff --git a/Texty.csproj b/Texty.csproj index 066bb51..fa11591 100644 --- a/Texty.csproj +++ b/Texty.csproj @@ -4,13 +4,13 @@ <LangVersion>8</LangVersion> </PropertyGroup> <ItemGroup> - <Compile Remove="ScriptTemplates\**"/> - <Compile Remove="Scenes\**"/> - <Compile Remove="Tests\**"/> + <Compile Remove="ScriptTemplates\**" /> + <Compile Remove="Scenes\**" /> + <Compile Remove="Tests\**" /> </ItemGroup> <ItemGroup> - <EmbeddedResource Remove="ScriptTemplates\**"/> - <EmbeddedResource Remove="Scenes\**"/> - <EmbeddedResource Remove="Tests\**"/> + <EmbeddedResource Remove="ScriptTemplates\**" /> + <EmbeddedResource Remove="Scenes\**" /> + <EmbeddedResource Remove="Tests\**" /> </ItemGroup> </Project>
\ No newline at end of file diff --git a/project.godot b/project.godot index 789ed61..239d5ea 100644 --- a/project.godot +++ b/project.godot @@ -9,6 +9,11 @@ config_version=4 _global_script_classes=[ { +"base": "GutTest", +"class": "CommandParserTestBase", +"language": "GDScript", +"path": "res://Tests/ComponentTests/ParserTests/CommandParserTestBase.gd" +}, { "base": "Reference", "class": "GutHookScript", "language": "GDScript", @@ -20,6 +25,7 @@ _global_script_classes=[ { "path": "res://addons/gut/test.gd" } ] _global_script_class_icons={ +"CommandParserTestBase": "", "GutHookScript": "", "GutTest": "" } |
