From cab99a7f9be5a5a08cf66f1226a384a180098c69 Mon Sep 17 00:00:00 2001 From: Nathanael Sensfelder Date: Sun, 1 Nov 2020 01:08:13 +0100 Subject: First shot at option+event player inputs. --- data/examples/blackjack/main.fate | 4 +- data/examples/blackjack/play.fate | 14 +- src/core/src/tonkadur/fate/v1/lang/InputEvent.java | 181 ++++++++++++++++++ src/core/src/tonkadur/fate/v1/lang/World.java | 15 ++ .../fate/v1/lang/instruction/PlayerChoice.java | 30 +-- .../fate/v1/lang/instruction/PlayerChoiceList.java | 65 ------- .../fate/v1/lang/instruction/PlayerInput.java | 134 ++++++++++++++ .../fate/v1/lang/instruction/PlayerOption.java | 78 ++++++++ .../fate/v1/lang/meta/InstructionVisitor.java | 5 +- src/core/src/tonkadur/fate/v1/parser/FateLexer.g4 | 3 + src/core/src/tonkadur/fate/v1/parser/FateParser.g4 | 129 ++++++++++++- .../v1/compiler/fate/v1/ComputationCompiler.java | 6 +- .../v1/compiler/fate/v1/InstructionCompiler.java | 174 +++++++++++++++++- .../wyrd/v1/compiler/util/BinarySearch.java | 203 +++++++++++++++++++++ .../tonkadur/wyrd/v1/compiler/util/PopElement.java | 11 +- .../src/tonkadur/wyrd/v1/compiler/util/Sort.java | 46 +++++ .../wyrd/v1/lang/instruction/AddEventInput.java | 66 +++++++ .../wyrd/v1/lang/meta/InstructionVisitor.java | 3 + .../tonkadur/jsonexport/InstructionCompiler.java | 25 +++ 19 files changed, 1081 insertions(+), 111 deletions(-) create mode 100644 src/core/src/tonkadur/fate/v1/lang/InputEvent.java delete mode 100644 src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoiceList.java create mode 100644 src/core/src/tonkadur/fate/v1/lang/instruction/PlayerInput.java create mode 100644 src/core/src/tonkadur/fate/v1/lang/instruction/PlayerOption.java create mode 100644 src/core/src/tonkadur/wyrd/v1/compiler/util/Sort.java create mode 100644 src/core/src/tonkadur/wyrd/v1/lang/instruction/AddEventInput.java diff --git a/data/examples/blackjack/main.fate b/data/examples/blackjack/main.fate index acfee7e..342a663 100644 --- a/data/examples/blackjack/main.fate +++ b/data/examples/blackjack/main.fate @@ -24,7 +24,7 @@ Just between you and me, someone left those laying around, they aren't mine. Now, you're all set to go... unless you don't know how to play? (player_choice - ( + (option ( As it happens, I do not. ) (visit rules_of_blackjack) (text_effect action_description @@ -32,7 +32,7 @@ Now, you're all set to go... unless you don't know how to play? ) (visit play_a_game) ) - ( + (option ( I am familiar with BlackJack. ) (text_effect action_description You leave the counter and approach one of the tables. diff --git a/data/examples/blackjack/play.fate b/data/examples/blackjack/play.fate index 2cf2407..81c7c58 100644 --- a/data/examples/blackjack/play.fate +++ b/data/examples/blackjack/play.fate @@ -83,13 +83,13 @@ Interesting. Would you like to go again? (player_choice - ( + (option ( Yes, please. ) Very well. (newline) (jump_to play_a_game) ) - ( + (option ( No, thank you. ) It was a pleasure to play with you. Farewell. (newline) @@ -153,17 +153,17 @@ ) (player_choice - ( + (option ( Another card, please. ) (set has_doubled (false)) (jump_to acquire_card) ) - ( + (option ( I will stand. ) (jump_to resolve_dealer) ) (if (and (>= player_score 9) (<= player_score 11)) - ( + (option ( Double my bet, I'll only take one card. ) (set bet (* bet 2)) (set has_doubled (true)) @@ -215,11 +215,11 @@ ) (player_choice - ( + (option ( Another card, please. ) (jump_to acquire_card) ) - ( + (option ( This will do. I stand. ) (jump_to resolve_dealer) ) diff --git a/src/core/src/tonkadur/fate/v1/lang/InputEvent.java b/src/core/src/tonkadur/fate/v1/lang/InputEvent.java new file mode 100644 index 0000000..17d6a48 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/InputEvent.java @@ -0,0 +1,181 @@ +package tonkadur.fate.v1.lang; + +import java.util.ArrayList; +import java.util.List; + +import tonkadur.functional.Merge; + +import tonkadur.parser.Context; +import tonkadur.parser.Location; +import tonkadur.parser.Origin; + +import tonkadur.fate.v1.lang.meta.DeclaredEntity; + +import tonkadur.fate.v1.lang.type.Type; + +public class InputEvent extends DeclaredEntity +{ + protected static final InputEvent ANY; + + static + { + ANY = + new InputEvent + ( + Origin.BASE_LANGUAGE, + new ArrayList(), + /* + * Use of a space necessary to avoid conflicting with a user created + * type. + */ + "undetermined input event" + ); + } + + public static InputEvent value_on_missing () + { + return ANY; + } + + @Override + public /* static */ String get_type_name () + { + return "InputEvent"; + } + + + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final List signature; + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + + /**** Constructors *********************************************************/ + public InputEvent + ( + final Origin origin, + final List signature, + final String name + ) + { + super(origin, name); + + this.signature = signature; + } + + /**** Accessors ************************************************************/ + public List get_signature () + { + return signature; + } + + @Override + public DeclaredEntity generate_comparable_to (final DeclaredEntity de) + { + final List new_signature; + final InputEvent e; + + if (!(de instanceof InputEvent)) + { + return ANY; + } + + e = (InputEvent) de; + + if (signature.size() != e.signature.size()) + { + return ANY; + } + + new_signature = + new Merge() + { + @Override + protected Type lambda (final Type a, final Type b) + { + return (Type) a.generate_comparable_to(b); + } + }.merge(signature, e.signature); + + return new InputEvent(origin, new_signature, name); + } + + /**** Misc. ****************************************************************/ + @Override + public boolean is_incompatible_with_declaration (final DeclaredEntity de) + { + if (de instanceof InputEvent) + { + final InputEvent e; + + e = (InputEvent) de; + + if (signature.size() == e.signature.size()) + { + final List compatibility_result; + + /* + * Basically, the events are compatible if, and only if, the old + * signature is as least as restrictive as the new one. + */ + compatibility_result = + ( + new Merge() + { + @Override + protected Boolean lambda (final Type a, final Type b) + { + return + new Boolean(a.can_be_used_as(b)); + } + }.merge(signature, e.signature) + ); + + return compatibility_result.contains(Boolean.TRUE); + } + } + + return true; + } + + @Override + public String toString () + { + final StringBuilder sb = new StringBuilder(); + + sb.append("("); + sb.append(get_type_name()); + sb.append(" "); + sb.append(name); + + if (!signature.isEmpty()) + { + boolean first_argument; + + sb.append(": "); + + first_argument = true; + + for (final Type type: signature) + { + if (first_argument) + { + first_argument = false; + } + else + { + sb.append(" -> "); + } + + sb.append(type.get_name()); + } + } + + sb.append(")"); + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/World.java b/src/core/src/tonkadur/fate/v1/lang/World.java index 047f1d5..c813312 100644 --- a/src/core/src/tonkadur/fate/v1/lang/World.java +++ b/src/core/src/tonkadur/fate/v1/lang/World.java @@ -42,6 +42,7 @@ public class World extension_first_level_instructions; protected final DeclarationCollection event_collection; + protected final DeclarationCollection input_event_collection; protected final DeclarationCollection sequence_collection; protected final DeclarationCollection text_effect_collection; protected final DeclarationCollection type_collection; @@ -69,6 +70,8 @@ public class World event_collection = new DeclarationCollection(Event.value_on_missing()); + input_event_collection = + new DeclarationCollection(InputEvent.value_on_missing()); sequence_collection = new DeclarationCollection(null); text_effect_collection = @@ -162,6 +165,11 @@ public class World return event_collection; } + public DeclarationCollection input_events () + { + return input_event_collection; + } + public DeclarationCollection sequences () { return sequence_collection; @@ -241,6 +249,13 @@ public class World sb.append(System.lineSeparator()); sb.append(System.lineSeparator()); + sb.append(System.lineSeparator()); + sb.append("Input Events: "); + sb.append(System.lineSeparator()); + sb.append(input_event_collection.toString()); + sb.append(System.lineSeparator()); + sb.append(System.lineSeparator()); + sb.append("Text Effects: "); sb.append(System.lineSeparator()); sb.append(text_effect_collection.toString()); diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoice.java b/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoice.java index 1f40c8a..738fe71 100644 --- a/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoice.java +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoice.java @@ -4,19 +4,15 @@ import java.util.List; import tonkadur.parser.Origin; -import tonkadur.fate.v1.lang.type.Type; - import tonkadur.fate.v1.lang.meta.InstructionVisitor; import tonkadur.fate.v1.lang.meta.Instruction; -import tonkadur.fate.v1.lang.meta.RichTextNode; public class PlayerChoice extends Instruction { /***************************************************************************/ /**** MEMBERS **************************************************************/ /***************************************************************************/ - protected final RichTextNode text; - protected final List effects; + protected final List entries; /***************************************************************************/ /**** PUBLIC ***************************************************************/ @@ -25,17 +21,14 @@ public class PlayerChoice extends Instruction public PlayerChoice ( final Origin origin, - final RichTextNode text, - final List effects + final List entries ) { super(origin); - this.text = text; - this.effects = effects; + this.entries = entries; } - /**** Accessors ************************************************************/ @Override public void get_visited_by (final InstructionVisitor iv) @@ -44,14 +37,9 @@ public class PlayerChoice extends Instruction iv.visit_player_choice(this); } - public RichTextNode get_text () - { - return text; - } - - public List get_effects () + public List get_entries () { - return effects; + return entries; } /**** Misc. ****************************************************************/ @@ -60,14 +48,14 @@ public class PlayerChoice extends Instruction { final StringBuilder sb = new StringBuilder(); - sb.append("(PlayerChoice"); + sb.append("(PlayerChoice "); + sb.append(System.lineSeparator()); - sb.append(text.toString()); - for (final Instruction effect: effects) + for (final Instruction entry: entries) { + sb.append(entry.toString()); sb.append(System.lineSeparator()); - sb.append(effect.toString()); } sb.append(")"); diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoiceList.java b/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoiceList.java deleted file mode 100644 index 79a2570..0000000 --- a/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoiceList.java +++ /dev/null @@ -1,65 +0,0 @@ -package tonkadur.fate.v1.lang.instruction; - -import java.util.List; - -import tonkadur.parser.Origin; - -import tonkadur.fate.v1.lang.meta.InstructionVisitor; -import tonkadur.fate.v1.lang.meta.Instruction; - -public class PlayerChoiceList extends Instruction -{ - /***************************************************************************/ - /**** MEMBERS **************************************************************/ - /***************************************************************************/ - protected final List choices; - - /***************************************************************************/ - /**** PUBLIC ***************************************************************/ - /***************************************************************************/ - /**** Constructors *********************************************************/ - public PlayerChoiceList - ( - final Origin origin, - final List choices - ) - { - super(origin); - - this.choices = choices; - } - - /**** Accessors ************************************************************/ - @Override - public void get_visited_by (final InstructionVisitor iv) - throws Throwable - { - iv.visit_player_choice_list(this); - } - - public List get_choices () - { - return choices; - } - - /**** Misc. ****************************************************************/ - @Override - public String toString () - { - final StringBuilder sb = new StringBuilder(); - - sb.append("(PlayerChoiceList "); - - sb.append(System.lineSeparator()); - - for (final Instruction choice: choices) - { - sb.append(choice.toString()); - sb.append(System.lineSeparator()); - } - - sb.append(")"); - - return sb.toString(); - } -} diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerInput.java b/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerInput.java new file mode 100644 index 0000000..a1efed4 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerInput.java @@ -0,0 +1,134 @@ +package tonkadur.fate.v1.lang.instruction; + +import java.util.ArrayList; +import java.util.List; + +import tonkadur.parser.Origin; +import tonkadur.parser.ParsingError; + +import tonkadur.fate.v1.lang.InputEvent; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.meta.InstructionVisitor; +import tonkadur.fate.v1.lang.meta.Instruction; +import tonkadur.fate.v1.lang.meta.Computation; +import tonkadur.fate.v1.lang.meta.RecurrentChecks; + +public class PlayerInput extends Instruction +{ + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final InputEvent input_event; + protected final List params; + protected final List effects; + + /***************************************************************************/ + /**** PROTECTED ************************************************************/ + /***************************************************************************/ + /**** Constructors *********************************************************/ + protected PlayerInput + ( + final Origin origin, + final InputEvent input_event, + final List params, + final List effects + ) + { + super(origin); + + this.input_event = input_event; + this.params = params; + this.effects = effects; + } + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + /**** Constructors *********************************************************/ + public PlayerInput + ( + final Origin origin, + final InputEvent input_event, + final List effects + ) + { + super(origin); + + this.input_event = input_event; + this.params = new ArrayList(); + this.effects = effects; + } + + public static PlayerInput build + ( + final Origin origin, + final InputEvent event, + final List parameters, + final List effects + ) + throws ParsingError + { + RecurrentChecks.assert_computations_matches_signature + ( + origin, + parameters, + event.get_signature() + ); + + return new PlayerInput(origin, event, parameters, effects); + } + + /**** Accessors ************************************************************/ + @Override + public void get_visited_by (final InstructionVisitor iv) + throws Throwable + { + iv.visit_player_input(this); + } + + public InputEvent get_input_event () + { + return input_event; + } + + public List get_parameters () + { + return params; + } + + public List get_effects () + { + return effects; + } + + /**** Misc. ****************************************************************/ + @Override + public String toString () + { + final StringBuilder sb = new StringBuilder(); + + sb.append("(PlayerInput ("); + sb.append(System.lineSeparator()); + sb.append(input_event.toString()); + + for (final Computation param: params) + { + sb.append(" "); + sb.append(param.toString()); + } + + sb.append(")"); + + for (final Instruction effect: effects) + { + sb.append(System.lineSeparator()); + sb.append(effect.toString()); + } + + sb.append(")"); + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerOption.java b/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerOption.java new file mode 100644 index 0000000..d6db1e4 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerOption.java @@ -0,0 +1,78 @@ +package tonkadur.fate.v1.lang.instruction; + +import java.util.List; + +import tonkadur.parser.Origin; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.meta.InstructionVisitor; +import tonkadur.fate.v1.lang.meta.Instruction; +import tonkadur.fate.v1.lang.meta.RichTextNode; + +public class PlayerOption extends Instruction +{ + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final RichTextNode text; + protected final List effects; + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + /**** Constructors *********************************************************/ + public PlayerOption + ( + final Origin origin, + final RichTextNode text, + final List effects + ) + { + super(origin); + + this.text = text; + this.effects = effects; + } + + + /**** Accessors ************************************************************/ + @Override + public void get_visited_by (final InstructionVisitor iv) + throws Throwable + { + iv.visit_player_option(this); + } + + public RichTextNode get_text () + { + return text; + } + + public List get_effects () + { + return effects; + } + + /**** Misc. ****************************************************************/ + @Override + public String toString () + { + final StringBuilder sb = new StringBuilder(); + + sb.append("(PlayerOption ("); + sb.append(System.lineSeparator()); + sb.append(text.toString()); + sb.append(")"); + + for (final Instruction effect: effects) + { + sb.append(System.lineSeparator()); + sb.append(effect.toString()); + } + + sb.append(")"); + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/meta/InstructionVisitor.java b/src/core/src/tonkadur/fate/v1/lang/meta/InstructionVisitor.java index a3038ac..a672f3c 100644 --- a/src/core/src/tonkadur/fate/v1/lang/meta/InstructionVisitor.java +++ b/src/core/src/tonkadur/fate/v1/lang/meta/InstructionVisitor.java @@ -122,7 +122,10 @@ public interface InstructionVisitor public void visit_player_choice (final PlayerChoice n) throws Throwable; - public void visit_player_choice_list (final PlayerChoiceList n) + public void visit_player_option (final PlayerOption n) + throws Throwable; + + public void visit_player_input (final PlayerInput n) throws Throwable; public void visit_remove_all_of_element (final RemoveAllOfElement n) diff --git a/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4 b/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4 index c5f073d..b1dbd75 100644 --- a/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4 +++ b/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4 @@ -38,6 +38,7 @@ DECLARE_ALIAS_TYPE_KW: DECLARE_DICT_TYPE_KW: L_PAREN ('declare'|'define'|'def')US('dict'|('struct''ure'?))(US'type')? SEP+; DECLARE_EVENT_TYPE_KW: L_PAREN ('declare'|'define'|'def')US'event'(US'type')? SEP+; +DECLARE_INPUT_EVENT_TYPE_KW: L_PAREN ('declare'|'define'|'def')US'input'US'event'(US'type')? SEP+; DECLARE_TEXT_EFFECT_KW: L_PAREN ('declare'|'define'|'def')US'text'US'effect' SEP+; DECLARE_VARIABLE_KW: L_PAREN 'global' SEP+; LOCAL_KW: L_PAREN 'local' SEP+; @@ -113,6 +114,8 @@ IMP_PUSH_LEFT_KW: L_PAREN 'push'US'left!' SEP+; PUSH_RIGHT_KW: L_PAREN 'push'US'right' SEP+; IMP_PUSH_RIGHT_KW: L_PAREN 'push'US'right!' SEP+; PLAYER_CHOICE_KW: L_PAREN ('choice'|'user'US'choice'|'player'US'choice') SEP+; +PLAYER_OPTION_KW: L_PAREN ('option'|'user'US'option'|'player'US'option') SEP+; +PLAYER_EVENT_KW: L_PAREN ('event'|'user'US'event'|'player'US'event') SEP+; PLUS_KW: L_PAREN ('plus'|'+') SEP+; POWER_KW: L_PAREN ('power'|'^'|'**'|'pow') SEP+; RANGE_KW: L_PAREN 'range' SEP+; diff --git a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 index d4798a0..4859c85 100644 --- a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 +++ b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 @@ -367,6 +367,52 @@ first_level_fate_instr: WORLD.events().add(new_event); } + | DECLARE_INPUT_EVENT_TYPE_KW new_reference_name WS* R_PAREN + { + final Origin start_origin; + final InputEvent new_event; + + start_origin = + CONTEXT.get_origin_at + ( + ($DECLARE_INPUT_EVENT_TYPE_KW.getLine()), + ($DECLARE_INPUT_EVENT_TYPE_KW.getCharPositionInLine()) + ); + + new_event = + new InputEvent + ( + start_origin, + new ArrayList(), + ($new_reference_name.result) + ); + + WORLD.input_events().add(new_event); + } + + | DECLARE_INPUT_EVENT_TYPE_KW new_reference_name WS+ type_list WS* R_PAREN + { + final Origin start_origin; + final InputEvent new_event; + + start_origin = + CONTEXT.get_origin_at + ( + ($DECLARE_INPUT_EVENT_TYPE_KW.getLine()), + ($DECLARE_INPUT_EVENT_TYPE_KW.getCharPositionInLine()) + ); + + new_event = + new InputEvent + ( + start_origin, + ($type_list.result), + ($new_reference_name.result) + ); + + WORLD.input_events().add(new_event); + } + | REQUIRE_KW WORD WS* R_PAREN { @@ -1762,7 +1808,7 @@ returns [Instruction result] | PLAYER_CHOICE_KW player_choice_list WS* R_PAREN { $result = - new PlayerChoiceList + new PlayerChoice ( CONTEXT.get_origin_at ( @@ -1953,7 +1999,7 @@ returns [List result] player_choice returns [Instruction result] : - start_p=L_PAREN WS* + PLAYER_OPTION_KW L_PAREN WS* paragraph WS* R_PAREN WS+ { HIERARCHICAL_VARIABLES.push(new ArrayList()); @@ -1969,18 +2015,91 @@ returns [Instruction result] R_PAREN { $result = - new PlayerChoice + new PlayerOption ( CONTEXT.get_origin_at ( - ($start_p.getLine()), - ($start_p.getCharPositionInLine()) + ($PLAYER_OPTION_KW.getLine()), + ($PLAYER_OPTION_KW.getCharPositionInLine()) ), ($paragraph.result), ($general_fate_sequence.result) ); } + | PLAYER_EVENT_KW + L_PAREN WS* WORD WS* R_PAREN WS+ + { + HIERARCHICAL_VARIABLES.push(new ArrayList()); + } + general_fate_sequence + { + for (final String s: HIERARCHICAL_VARIABLES.pop()) + { + LOCAL_VARIABLES.peekFirst().remove(s); + } + } + WS* + R_PAREN + { + final Origin origin; + final InputEvent event; + + origin = + CONTEXT.get_origin_at + ( + ($PLAYER_EVENT_KW.getLine()), + ($PLAYER_EVENT_KW.getCharPositionInLine()) + ); + + event = WORLD.input_events().get(origin, ($WORD.text)); + + $result = + new PlayerInput + ( + origin, + event, + ($general_fate_sequence.result) + ); + } + + | PLAYER_EVENT_KW + L_PAREN WS* WORD WS+ value_list WS* R_PAREN WS+ + { + HIERARCHICAL_VARIABLES.push(new ArrayList()); + } + general_fate_sequence + { + for (final String s: HIERARCHICAL_VARIABLES.pop()) + { + LOCAL_VARIABLES.peekFirst().remove(s); + } + } + WS* + R_PAREN + { + final Origin origin; + final InputEvent event; + + origin = + CONTEXT.get_origin_at + ( + ($PLAYER_EVENT_KW.getLine()), + ($PLAYER_EVENT_KW.getCharPositionInLine()) + ); + + event = WORLD.input_events().get(origin, ($WORD.text)); + + $result = + PlayerInput.build + ( + origin, + event, + ($value_list.result), + ($general_fate_sequence.result) + ); + } + | IF_KW non_text_value WS+ player_choice_list WS* diff --git a/src/core/src/tonkadur/wyrd/v1/compiler/fate/v1/ComputationCompiler.java b/src/core/src/tonkadur/wyrd/v1/compiler/fate/v1/ComputationCompiler.java index 25f48e8..fa4ae49 100644 --- a/src/core/src/tonkadur/wyrd/v1/compiler/fate/v1/ComputationCompiler.java +++ b/src/core/src/tonkadur/wyrd/v1/compiler/fate/v1/ComputationCompiler.java @@ -831,7 +831,11 @@ implements tonkadur.fate.v1.lang.meta.ComputationVisitor result_as_address, new IfElseComputation ( - Operation.less_than(result_as_computation, operand), + Operation.less_than + ( + result_as_computation, + operand + ), result_as_computation, operand ) diff --git a/src/core/src/tonkadur/wyrd/v1/compiler/fate/v1/InstructionCompiler.java b/src/core/src/tonkadur/wyrd/v1/compiler/fate/v1/InstructionCompiler.java index ada630b..d27f865 100644 --- a/src/core/src/tonkadur/wyrd/v1/compiler/fate/v1/InstructionCompiler.java +++ b/src/core/src/tonkadur/wyrd/v1/compiler/fate/v1/InstructionCompiler.java @@ -29,6 +29,7 @@ import tonkadur.wyrd.v1.lang.computation.GetLastChoiceIndex; import tonkadur.wyrd.v1.lang.computation.ValueOf; import tonkadur.wyrd.v1.lang.instruction.AddChoice; +import tonkadur.wyrd.v1.lang.instruction.AddEventInput; import tonkadur.wyrd.v1.lang.instruction.Assert; import tonkadur.wyrd.v1.lang.instruction.Display; import tonkadur.wyrd.v1.lang.instruction.End; @@ -2325,9 +2326,9 @@ implements tonkadur.fate.v1.lang.meta.InstructionVisitor } @Override - public void visit_player_choice + public void visit_player_option ( - final tonkadur.fate.v1.lang.instruction.PlayerChoice n + final tonkadur.fate.v1.lang.instruction.PlayerOption n ) throws Throwable { @@ -2466,9 +2467,172 @@ implements tonkadur.fate.v1.lang.meta.InstructionVisitor } @Override - public void visit_player_choice_list + public void visit_player_input ( - final tonkadur.fate.v1.lang.instruction.PlayerChoiceList n + final tonkadur.fate.v1.lang.instruction.PlayerInput n + ) + throws Throwable + { + /* + * Fate: (player_choice label i0) + * + * Wyrd (add_choice label i0) + */ + final List to_next, labels_only; + final List params_cc; + final List params; + final String start_of_effect, end_of_effect; + + to_next = new ArrayList(); + labels_only = new ArrayList(); + params = new ArrayList(); + params_cc = new ArrayList(); + + start_of_effect = compiler.assembler().generate_label(""); + end_of_effect = compiler.assembler().generate_label(""); + + for + ( + final tonkadur.fate.v1.lang.meta.Computation param: n.get_parameters() + ) + { + final ComputationCompiler cc; + + cc = new ComputationCompiler(compiler); + + param.get_visited_by(cc); + + if (cc.has_init()) + { + result.add(cc.get_init()); + } + + params.add(cc.get_computation()); + } + + labels_only.add + ( + new AddEventInput(n.get_input_event().get_name(), params) + ); + + for (final ComputationCompiler cc: params_cc) + { + cc.release_registers(labels_only); + } + + labels_only.add + ( + new SetPC(compiler.assembler().get_label_constant(end_of_effect)) + ); + + result.add + ( + If.generate + ( + compiler.registers(), + compiler.assembler(), + Operation.equals + ( + compiler.registers().get_choice_number_holder().get_value(), + new Constant(Type.INT, "-2") + ), + compiler.assembler().merge(labels_only) + ) + ); + + + to_next.add + ( + new SetValue + ( + compiler.registers().get_choice_number_holder().get_address(), + Operation.plus + ( + compiler.registers().get_choice_number_holder().get_value(), + Constant.ONE + ) + ) + ); + + to_next.add + ( + new SetPC(compiler.assembler().get_label_constant(end_of_effect)) + ); + + result.add + ( + compiler.assembler().mark_after + ( + If.generate + ( + compiler.registers(), + compiler.assembler(), + Operation.not + ( + Operation.equals + ( + compiler.registers().get_choice_number_holder().get_value(), + new GetLastChoiceIndex() + ) + ), + compiler.assembler().merge(to_next) + ), + start_of_effect + ) + ); + + result.add + ( + new SetValue + ( + compiler.registers().get_rand_mode_holder().get_address(), + new Constant(Type.INT, "0") + ) + ); + + result.add + ( + Clear.generate + ( + compiler.registers(), + compiler.assembler(), + new Size + ( + compiler.registers().get_rand_value_holder().get_address() + ), + compiler.registers().get_rand_value_holder().get_address() + ) + ); + + compiler.registers().push_hierarchical_instruction_level(); + for + ( + final tonkadur.fate.v1.lang.meta.Instruction fate_instruction: + n.get_effects() + ) + { + fate_instruction.get_visited_by(this); + } + compiler.registers().pop_hierarchical_instruction_level(result); + + result.add + ( + compiler.assembler().mark_after + ( + new SetPC + ( + compiler.assembler().get_context_label_constant("choices") + ), + end_of_effect + ) + ); + } + + + @Override + public void visit_player_choice + ( + final tonkadur.fate.v1.lang.instruction.PlayerChoice n ) throws Throwable { @@ -2516,7 +2680,7 @@ implements tonkadur.fate.v1.lang.meta.InstructionVisitor for ( final tonkadur.fate.v1.lang.meta.Instruction fate_instruction: - n.get_choices() + n.get_entries() ) { fate_instruction.get_visited_by(this); diff --git a/src/core/src/tonkadur/wyrd/v1/compiler/util/BinarySearch.java b/src/core/src/tonkadur/wyrd/v1/compiler/util/BinarySearch.java index 44106bf..a8efd31 100644 --- a/src/core/src/tonkadur/wyrd/v1/compiler/util/BinarySearch.java +++ b/src/core/src/tonkadur/wyrd/v1/compiler/util/BinarySearch.java @@ -263,4 +263,207 @@ public class BinarySearch return assembler.merge(result); } + + public static Instruction generate + ( + final RegisterManager registers, + final InstructionManager assembler, + final Computation sort_fun, + final Computation target, + final Computation collection_size, + final Address collection, + final Address result_was_found, + final Address result_index, + final List sort_fun_extra_params + ) + { + final List result, while_body; + final Register bot, top, midval, cmp; + final Type element_type; + final Computation value_of_result_index; + + result = new ArrayList(); + while_body = new ArrayList(); + + element_type = target.get_type(); + + bot = registers.reserve(Type.INT, result); + top = registers.reserve(Type.INT, result); + midval = registers.reserve(element_type, result); + cmp = registers.reserve(Type.INT, result); + + value_of_result_index = new ValueOf(result_index); + + result.add(new SetValue(result_index, Constant.ZERO)); + result.add(new SetValue(result_was_found, Constant.FALSE)); + result.add(new SetValue(bot.get_address(), Constant.ZERO)); + result.add + ( + new SetValue + ( + top.get_address(), + Operation.minus(collection_size, Constant.ONE) + ) + ); + + /* + * (set result_index + * (+ + * (var .bot) + * (cast int + * (/ + * (cast float + * (- (var .top) (var .bot)) + * ) + * 2.0 + * ) + * ) + * ) + * ) + */ + while_body.add + ( + new SetValue + ( + result_index, + Operation.plus + ( + bot.get_value(), + new Cast + ( + Operation.divide + ( + new Cast + ( + Operation.minus(top.get_value(), bot.get_value()), + Type.FLOAT + ), + new Constant(Type.FLOAT, "2.0") + ), + Type.INT + ) + ) + ) + ); + + /* (set .midval (var collection[.result_index])) */ + while_body.add + ( + new SetValue + ( + midval.get_address(), + new ValueOf + ( + new RelativeAddress + ( + collection, + new Cast(value_of_result_index, Type.STRING), + element_type + ) + ) + ) + ); + + while_body.add + ( + LambdaEvaluation.generate + ( + registers, + assembler, + sort_fun, + cmp.get_address(), + sort_fun_extra_params + ) + ); + + /* + * (var .midval) element) + * + * (set .top (- (var result_index) 1)) + * + * (set result_found true) + * > + * > + */ + while_body.add + ( + IfElse.generate + ( + registers, + assembler, + Operation.less_than(cmp.get_value(), Constant.ZERO), + new SetValue + ( + bot.get_address(), + Operation.plus(value_of_result_index, Constant.ONE) + ), + IfElse.generate + ( + registers, + assembler, + Operation.greater_than(cmp.get_value(), Constant.ZERO), + new SetValue + ( + top.get_address(), + Operation.minus(value_of_result_index, Constant.ONE) + ), + new SetValue(result_was_found, Constant.TRUE) + ) + ) + ); + + result.add + ( + While.generate + ( + registers, + assembler, + Operation.and + ( + Operation.not(new ValueOf(result_was_found)), + Operation.less_equal_than(bot.get_value(), top.get_value()) + ), + assembler.merge(while_body) + ) + ); + + /* Without this, you'll replace the value and move it to the right, + * regardless of where you 'target' stands in relation to it. + */ + result.add + ( + If.generate + ( + registers, + assembler, + Operation.and + ( + Operation.and + ( + Operation.not(new ValueOf(result_was_found)), + Operation.greater_than(target, midval.get_value()) + ), + Operation.greater_than(collection_size, Constant.ZERO) + ), + new SetValue + ( + result_index, + Operation.plus(value_of_result_index, Constant.ONE) + ) + ) + ); + + registers.release(bot, result); + registers.release(top, result); + registers.release(midval, result); + registers.release(cmp, result); + + return assembler.merge(result); + } } diff --git a/src/core/src/tonkadur/wyrd/v1/compiler/util/PopElement.java b/src/core/src/tonkadur/wyrd/v1/compiler/util/PopElement.java index 3da9a89..6a436a6 100644 --- a/src/core/src/tonkadur/wyrd/v1/compiler/util/PopElement.java +++ b/src/core/src/tonkadur/wyrd/v1/compiler/util/PopElement.java @@ -68,11 +68,14 @@ public class PopElement new SetValue ( element_holder, - new RelativeAddress + new ValueOf ( - collection, - new Cast(target_index, Type.STRING), - ((PointerType) element_holder.get_type()).get_target_type() + new RelativeAddress + ( + collection, + new Cast(target_index, Type.STRING), + ((PointerType) element_holder.get_type()).get_target_type() + ) ) ) ); diff --git a/src/core/src/tonkadur/wyrd/v1/compiler/util/Sort.java b/src/core/src/tonkadur/wyrd/v1/compiler/util/Sort.java new file mode 100644 index 0000000..200f7ef --- /dev/null +++ b/src/core/src/tonkadur/wyrd/v1/compiler/util/Sort.java @@ -0,0 +1,46 @@ +package tonkadur.wyrd.v1.compiler.util; + +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; + +import tonkadur.wyrd.v1.lang.Register; + +import tonkadur.wyrd.v1.lang.type.Type; +import tonkadur.wyrd.v1.lang.type.MapType; + +import tonkadur.wyrd.v1.lang.meta.Instruction; +import tonkadur.wyrd.v1.lang.meta.Computation; + +import tonkadur.wyrd.v1.lang.computation.Address; +import tonkadur.wyrd.v1.lang.computation.Cast; +import tonkadur.wyrd.v1.lang.computation.Constant; +import tonkadur.wyrd.v1.lang.computation.Operation; +import tonkadur.wyrd.v1.lang.computation.RelativeAddress; +import tonkadur.wyrd.v1.lang.computation.Size; +import tonkadur.wyrd.v1.lang.computation.ValueOf; + +import tonkadur.wyrd.v1.lang.instruction.SetValue; +import tonkadur.wyrd.v1.lang.instruction.Remove; + +import tonkadur.wyrd.v1.compiler.util.registers.RegisterManager; + +public class Sort +{ + /* Utility Class */ + private Sort () {} + + public static Instruction generate + ( + final RegisterManager registers, + final InstructionManager assembler, + final Computation lambda_fun, + final Address collection, + final Type collection_type, + final List extra_params + ) + { + /* TODO: Quicksort implementation in Wyrd. */ + return null; + } +} diff --git a/src/core/src/tonkadur/wyrd/v1/lang/instruction/AddEventInput.java b/src/core/src/tonkadur/wyrd/v1/lang/instruction/AddEventInput.java new file mode 100644 index 0000000..5d476a5 --- /dev/null +++ b/src/core/src/tonkadur/wyrd/v1/lang/instruction/AddEventInput.java @@ -0,0 +1,66 @@ +package tonkadur.wyrd.v1.lang.instruction; + +import java.util.List; + +import tonkadur.wyrd.v1.lang.meta.Computation; +import tonkadur.wyrd.v1.lang.meta.Instruction; +import tonkadur.wyrd.v1.lang.meta.InstructionVisitor; + +public class AddEventInput extends Instruction +{ + /***************************************************************************/ + /**** MEMBERS **************************************************************/ + /***************************************************************************/ + protected final String name; + protected final List parameters; + + /***************************************************************************/ + /**** PUBLIC ***************************************************************/ + /***************************************************************************/ + /**** Constructors *********************************************************/ + public AddEventInput (final String name, final List parameters) + { + this.name = name; + this.parameters = parameters; + } + + /**** Accessors ************************************************************/ + public String get_name () + { + return name; + } + + public List get_parameters () + { + return parameters; + } + + @Override + public void get_visited_by (final InstructionVisitor iv) + throws Throwable + { + iv.visit_add_event_input(this); + } + + /**** Misc. ****************************************************************/ + @Override + public String toString () + { + final StringBuilder sb; + + sb = new StringBuilder(); + + sb.append("(AddEventInput "); + sb.append(name); + + for (final Computation param: parameters) + { + sb.append(" "); + sb.append(param.toString()); + } + + sb.append(")"); + + return sb.toString(); + } +} diff --git a/src/core/src/tonkadur/wyrd/v1/lang/meta/InstructionVisitor.java b/src/core/src/tonkadur/wyrd/v1/lang/meta/InstructionVisitor.java index 72a4cd4..2d79298 100644 --- a/src/core/src/tonkadur/wyrd/v1/lang/meta/InstructionVisitor.java +++ b/src/core/src/tonkadur/wyrd/v1/lang/meta/InstructionVisitor.java @@ -7,6 +7,9 @@ public interface InstructionVisitor public void visit_add_choice (final AddChoice n) throws Throwable; + public void visit_add_event_input (final AddEventInput n) + throws Throwable; + public void visit_assert (final Assert n) throws Throwable; diff --git a/src/json-export/src/tonkadur/jsonexport/InstructionCompiler.java b/src/json-export/src/tonkadur/jsonexport/InstructionCompiler.java index 22c2fca..86b2a56 100644 --- a/src/json-export/src/tonkadur/jsonexport/InstructionCompiler.java +++ b/src/json-export/src/tonkadur/jsonexport/InstructionCompiler.java @@ -27,6 +27,31 @@ public class InstructionCompiler implements InstructionVisitor result.put("label", label_cc.get_result()); } + public void visit_add_event_input (final AddEventInput n) + throws Throwable + { + final JSONArray params; + + params = new JSONArray(); + + for (final Computation c: n.get_parameters()) + { + final ComputationCompiler cc; + + cc = new ComputationCompiler(); + + c.get_visited_by(cc); + + params.add(cc.get_result()); + } + + result = new JSONObject(); + + result.put("category", "add_event_input"); + result.put("event", n.get_name()); + result.put("parameters", params); + } + public void visit_assert (final Assert n) throws Throwable { -- cgit v1.2.3-70-g09d2