| summaryrefslogtreecommitdiff | 
diff options
Diffstat (limited to 'src/core')
10 files changed, 831 insertions, 52 deletions
| diff --git a/src/core/src/tonkadur/fate/v1/lang/World.java b/src/core/src/tonkadur/fate/v1/lang/World.java index eb87c45..930d84d 100644 --- a/src/core/src/tonkadur/fate/v1/lang/World.java +++ b/src/core/src/tonkadur/fate/v1/lang/World.java @@ -17,6 +17,7 @@ import tonkadur.parser.Origin;  import tonkadur.fate.v1.error.UnknownSequenceException;  import tonkadur.fate.v1.lang.meta.DeclarationCollection; +import tonkadur.fate.v1.lang.meta.InstructionNode;  import tonkadur.fate.v1.lang.type.Type; @@ -37,6 +38,8 @@ public class World     protected final DeclarationCollection<Type> type_collection;     protected final DeclarationCollection<Variable> variable_collection; +   protected final List<InstructionNode> global_instructions; +     /***************************************************************************/     /**** PUBLIC ***************************************************************/     /***************************************************************************/ @@ -61,6 +64,8 @@ public class World           new DeclarationCollection<Variable>(Variable.value_on_missing());        add_base_types(); + +      global_instructions = new ArrayList<InstructionNode>();     }     /**** Accessors ************************************************************/ @@ -139,8 +144,17 @@ public class World        return variable_collection;     } -   /**** Misc. ****************************************************************/ +   public void add_global_instruction (final InstructionNode instruction) +   { +      global_instructions.add(instruction); +   } +   public List<InstructionNode> get_global_instructions () +   { +      return global_instructions; +   } + +   /**** Misc. ****************************************************************/     public boolean assert_sanity ()     throws UnknownSequenceException     { diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/Assert.java b/src/core/src/tonkadur/fate/v1/lang/instruction/Assert.java new file mode 100644 index 0000000..f876f0c --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/Assert.java @@ -0,0 +1,85 @@ +package tonkadur.fate.v1.lang.instruction; + +import java.util.Collections; + +import tonkadur.error.ErrorManager; + +import tonkadur.parser.Origin; + +import tonkadur.fate.v1.error.InvalidTypeException; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.meta.InstructionNode; +import tonkadur.fate.v1.lang.meta.ValueNode; + +public class Assert extends InstructionNode +{ +   /***************************************************************************/ +   /**** MEMBERS **************************************************************/ +   /***************************************************************************/ +   protected final ValueNode condition; + +   /***************************************************************************/ +   /**** PROTECTED ************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   protected Assert +   ( +      final Origin origin, +      final ValueNode condition +   ) +   { +      super(origin); + +      this.condition = condition; +   } + +   /***************************************************************************/ +   /**** PUBLIC ***************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   public static Assert build +   ( +      final Origin origin, +      final ValueNode condition +   ) +   throws InvalidTypeException +   { +      if (condition.get_type().get_base_type().equals(Type.BOOLEAN)) +      { +         ErrorManager.handle +         ( +            new InvalidTypeException +            ( +               condition.get_origin(), +               condition.get_type(), +               Collections.singleton(Type.BOOLEAN) +            ) +         ); +      } + +      return new Assert(origin, condition); +   } + +   /**** Accessors ************************************************************/ +   public ValueNode get_condition () +   { +      return condition; +   } + +   /**** Misc. ****************************************************************/ +   @Override +   public String toString () +   { +      final StringBuilder sb = new StringBuilder(); + +      sb.append("(Assert"); +      sb.append(System.lineSeparator()); +      sb.append(condition.toString()); + +      sb.append(")"); + +      return sb.toString(); +   } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/Clear.java b/src/core/src/tonkadur/fate/v1/lang/instruction/Clear.java index 25b85c8..0a3a151 100644 --- a/src/core/src/tonkadur/fate/v1/lang/instruction/Clear.java +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/Clear.java @@ -65,6 +65,10 @@ public class Clear extends InstructionNode     }     /**** Accessors ************************************************************/ +   public ValueNode get_collection () +   { +      return collection; +   }     /**** Misc. ****************************************************************/     @Override @@ -72,13 +76,7 @@ public class Clear extends InstructionNode     {        final StringBuilder sb = new StringBuilder(); -      sb.append(origin.toString()); -      sb.append("(Clear"); -      sb.append(System.lineSeparator()); -      sb.append(System.lineSeparator()); - -      sb.append("collection:"); -      sb.append(System.lineSeparator()); +      sb.append("(Clear ");        sb.append(collection.toString());        sb.append(")"); diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/CondInstruction.java b/src/core/src/tonkadur/fate/v1/lang/instruction/CondInstruction.java new file mode 100644 index 0000000..71a6a69 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/CondInstruction.java @@ -0,0 +1,101 @@ +package tonkadur.fate.v1.lang.instruction; + +import java.util.Collections; +import java.util.List; + +import tonkadur.error.ErrorManager; + +import tonkadur.functional.Cons; + +import tonkadur.parser.Origin; + +import tonkadur.fate.v1.error.InvalidTypeException; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.meta.InstructionNode; +import tonkadur.fate.v1.lang.meta.ValueNode; + +public class CondInstruction extends InstructionNode +{ +   /***************************************************************************/ +   /**** MEMBERS **************************************************************/ +   /***************************************************************************/ +   protected final List<Cons<ValueNode, InstructionNode>> branches; + +   /***************************************************************************/ +   /**** PROTECTED ************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   protected CondInstruction +   ( +      final Origin origin, +      final List<Cons<ValueNode, InstructionNode>> branches +   ) +   { +      super(origin); + +      this.branches = branches; +   } + +   /***************************************************************************/ +   /**** PUBLIC ***************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   public static CondInstruction build +   ( +      final Origin origin, +      final List<Cons<ValueNode, InstructionNode>> branches +   ) +   throws InvalidTypeException +   { +      for (final Cons<ValueNode, InstructionNode> branch: branches) +      { +         if (branch.get_car().get_type().get_base_type().equals(Type.BOOLEAN)) +         { +            ErrorManager.handle +            ( +               new InvalidTypeException +               ( +                  branch.get_car().get_origin(), +                  branch.get_car().get_type(), +                  Collections.singleton(Type.BOOLEAN) +               ) +            ); +         } +      } + +      return new CondInstruction(origin, branches); +   } + +   /**** Accessors ************************************************************/ +   public List<Cons<ValueNode, InstructionNode>> get_branches () +   { +      return branches; +   } + +   /**** Misc. ****************************************************************/ +   @Override +   public String toString () +   { +      final StringBuilder sb = new StringBuilder(); + +      sb.append("(CondInstruction"); +      sb.append(System.lineSeparator()); + +      for (final Cons<ValueNode, InstructionNode> branch: branches) +      { +         sb.append(System.lineSeparator()); +         sb.append("if:"); +         sb.append(branch.get_car().toString()); + +         sb.append(System.lineSeparator()); +         sb.append("then:"); +         sb.append(branch.get_cdr().toString()); +      } + +      sb.append(")"); + +      return sb.toString(); +   } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/Display.java b/src/core/src/tonkadur/fate/v1/lang/instruction/Display.java new file mode 100644 index 0000000..25f4226 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/Display.java @@ -0,0 +1,61 @@ +package tonkadur.fate.v1.lang.instruction; + +import java.util.Collections; + +import tonkadur.error.ErrorManager; + +import tonkadur.parser.Origin; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.meta.InstructionNode; +import tonkadur.fate.v1.lang.meta.TextNode; + +public class Display extends InstructionNode +{ +   /***************************************************************************/ +   /**** MEMBERS **************************************************************/ +   /***************************************************************************/ +   protected final TextNode content; + +   /***************************************************************************/ +   /**** PROTECTED ************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   public Display +   ( +      final Origin origin, +      final TextNode content +   ) +   { +      super(origin); + +      this.content = content; +   } + +   /***************************************************************************/ +   /**** PUBLIC ***************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ + +   /**** Accessors ************************************************************/ +   public TextNode get_content () +   { +      return content; +   } + +   /**** Misc. ****************************************************************/ +   @Override +   public String toString () +   { +      final StringBuilder sb = new StringBuilder(); + +      sb.append("(Display"); +      sb.append(System.lineSeparator()); +      sb.append(content.toString()); + +      sb.append(")"); + +      return sb.toString(); +   } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/IfElseInstruction.java b/src/core/src/tonkadur/fate/v1/lang/instruction/IfElseInstruction.java new file mode 100644 index 0000000..1bedbe0 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/IfElseInstruction.java @@ -0,0 +1,111 @@ +package tonkadur.fate.v1.lang.instruction; + +import java.util.Collections; + +import tonkadur.error.ErrorManager; + +import tonkadur.parser.Origin; + +import tonkadur.fate.v1.error.InvalidTypeException; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.meta.InstructionNode; +import tonkadur.fate.v1.lang.meta.ValueNode; + +public class IfElseInstruction extends InstructionNode +{ +   /***************************************************************************/ +   /**** MEMBERS **************************************************************/ +   /***************************************************************************/ +   protected final ValueNode condition; +   protected final InstructionNode if_true; +   protected final InstructionNode if_false; + +   /***************************************************************************/ +   /**** PROTECTED ************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   protected IfElseInstruction +   ( +      final Origin origin, +      final ValueNode condition, +      final InstructionNode if_true, +      final InstructionNode if_false +   ) +   { +      super(origin); + +      this.condition = condition; +      this.if_true = if_true; +      this.if_false = if_false; +   } + +   /***************************************************************************/ +   /**** PUBLIC ***************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   public static IfElseInstruction build +   ( +      final Origin origin, +      final ValueNode condition, +      final InstructionNode if_true, +      final InstructionNode if_false +   ) +   throws InvalidTypeException +   { +      if (condition.get_type().get_base_type().equals(Type.BOOLEAN)) +      { +         ErrorManager.handle +         ( +            new InvalidTypeException +            ( +               condition.get_origin(), +               condition.get_type(), +               Collections.singleton(Type.BOOLEAN) +            ) +         ); +      } + +      return new IfElseInstruction(origin, condition, if_true, if_false); +   } + +   /**** Accessors ************************************************************/ +   public ValueNode get_condition () +   { +      return condition; +   } + +   public InstructionNode get_if_true () +   { +      return if_true; +   } + +   public InstructionNode get_if_false () +   { +      return if_false; +   } + +   /**** Misc. ****************************************************************/ +   @Override +   public String toString () +   { +      final StringBuilder sb = new StringBuilder(); + +      sb.append("(IfElseInstruction"); +      sb.append(System.lineSeparator()); +      sb.append(condition.toString()); +      sb.append(System.lineSeparator()); +      sb.append("If true:"); +      sb.append(System.lineSeparator()); +      sb.append(if_true.toString()); +      sb.append(System.lineSeparator()); +      sb.append("If false:"); +      sb.append(System.lineSeparator()); +      sb.append(if_false.toString()); + +      sb.append(")"); + +      return sb.toString(); +   } +} diff --git a/src/core/src/tonkadur/fate/v1/lang/instruction/IfInstruction.java b/src/core/src/tonkadur/fate/v1/lang/instruction/IfInstruction.java new file mode 100644 index 0000000..a6c4a81 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/IfInstruction.java @@ -0,0 +1,96 @@ +package tonkadur.fate.v1.lang.instruction; + +import java.util.Collections; + +import tonkadur.error.ErrorManager; + +import tonkadur.parser.Origin; + +import tonkadur.fate.v1.error.InvalidTypeException; + +import tonkadur.fate.v1.lang.type.Type; + +import tonkadur.fate.v1.lang.meta.InstructionNode; +import tonkadur.fate.v1.lang.meta.ValueNode; + +public class IfInstruction extends InstructionNode +{ +   /***************************************************************************/ +   /**** MEMBERS **************************************************************/ +   /***************************************************************************/ +   protected final ValueNode condition; +   protected final InstructionNode if_true; + +   /***************************************************************************/ +   /**** PROTECTED ************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   protected IfInstruction +   ( +      final Origin origin, +      final ValueNode condition, +      final InstructionNode if_true +   ) +   { +      super(origin); + +      this.condition = condition; +      this.if_true = if_true; +   } + +   /***************************************************************************/ +   /**** PUBLIC ***************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   public static IfInstruction build +   ( +      final Origin origin, +      final ValueNode condition, +      final InstructionNode if_true +   ) +   throws InvalidTypeException +   { +      if (condition.get_type().get_base_type().equals(Type.BOOLEAN)) +      { +         ErrorManager.handle +         ( +            new InvalidTypeException +            ( +               condition.get_origin(), +               condition.get_type(), +               Collections.singleton(Type.BOOLEAN) +            ) +         ); +      } + +      return new IfInstruction(origin, condition, if_true); +   } + +   /**** Accessors ************************************************************/ +   public ValueNode get_condition () +   { +      return condition; +   } + +   public InstructionNode get_if_true () +   { +      return if_true; +   } + +   /**** Misc. ****************************************************************/ +   @Override +   public String toString () +   { +      final StringBuilder sb = new StringBuilder(); + +      sb.append("(IfInstruction"); +      sb.append(System.lineSeparator()); +      sb.append(condition.toString()); +      sb.append(System.lineSeparator()); +      sb.append(if_true.toString()); + +      sb.append(")"); + +      return sb.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 new file mode 100644 index 0000000..3f55e48 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoice.java @@ -0,0 +1,69 @@ +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.InstructionNode; +import tonkadur.fate.v1.lang.meta.TextNode; + +public class PlayerChoice extends InstructionNode +{ +   /***************************************************************************/ +   /**** MEMBERS **************************************************************/ +   /***************************************************************************/ +   protected final TextNode text; +   protected final List<InstructionNode> effects; + +   /***************************************************************************/ +   /**** PUBLIC ***************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   public PlayerChoice +   ( +      final Origin origin, +      final TextNode text, +      final List<InstructionNode> effects +   ) +   { +      super(origin); + +      this.text = text; +      this.effects = effects; +   } + + +   /**** Accessors ************************************************************/ +   public TextNode get_text () +   { +      return text; +   } + +   public List<InstructionNode> get_effects () +   { +      return effects; +   } + +   /**** Misc. ****************************************************************/ +   @Override +   public String toString () +   { +      final StringBuilder sb = new StringBuilder(); + +      sb.append("(PlayerChoice"); +      sb.append(System.lineSeparator()); +      sb.append(text.toString()); + +      for (final InstructionNode 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/PlayerChoiceList.java b/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoiceList.java new file mode 100644 index 0000000..cac2e07 --- /dev/null +++ b/src/core/src/tonkadur/fate/v1/lang/instruction/PlayerChoiceList.java @@ -0,0 +1,57 @@ +package tonkadur.fate.v1.lang.instruction; + +import java.util.List; + +import tonkadur.parser.Origin; + +import tonkadur.fate.v1.lang.meta.InstructionNode; + +public class PlayerChoiceList extends InstructionNode +{ +   /***************************************************************************/ +   /**** MEMBERS **************************************************************/ +   /***************************************************************************/ +   protected final List<InstructionNode> choices; + +   /***************************************************************************/ +   /**** PUBLIC ***************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   public PlayerChoiceList +   ( +      final Origin origin, +      final List<InstructionNode> choices +   ) +   { +      super(origin); + +      this.choices = choices; +   } + +   /**** Accessors ************************************************************/ +   public List<InstructionNode> get_choices () +   { +      return choices; +   } + +   /**** Misc. ****************************************************************/ +   @Override +   public String toString () +   { +      final StringBuilder sb = new StringBuilder(); + +      sb.append("(PlayerChoiceList "); + +      sb.append(System.lineSeparator()); + +      for (final InstructionNode choice: choices) +      { +         sb.append(choice.toString()); +         sb.append(System.lineSeparator()); +      } + +      sb.append(")"); + +      return sb.toString(); +   } +} diff --git a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 index e5c2733..4778cc3 100644 --- a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 +++ b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 @@ -53,10 +53,16 @@ fate_file [Context context, World world]     :     WS* FATE_VERSION_KW WS+ WORD WS* R_PAREN WS*     ( -      (first_level_fate_instr|general_fate_instr) -      { -         /* TODO */ -      } +      ( +         first_level_fate_instr +         | +         ( +            general_fate_instr +            { +               WORLD.add_global_instruction(($general_fate_instr.result)); +            } +         ) +      )        WS*     )*     EOF @@ -74,7 +80,7 @@ returns [List<InstructionNode> result]     (WS*        general_fate_instr        { -         $result.add($general_fate_instr.result); +         $result.add(($general_fate_instr.result));        }     WS*)*     { @@ -573,41 +579,79 @@ returns [InstructionNode result]     | ASSERT_KW WS+ value WS* R_PAREN     { -      /* TODO */ - -      $result = null; +      $result = +         Assert.build +         ( +            CONTEXT.get_origin_at +            ( +               ($ASSERT_KW.getLine()), +               ($ASSERT_KW.getCharPositionInLine()) +            ), +            ($value.result) +         );     }     | IF_KW WS+ value WS* general_fate_instr WS* R_PAREN     { -      /* TODO */ - -      $result = null; +      $result = +         IfInstruction.build +         ( +            CONTEXT.get_origin_at +            ( +               ($IF_KW.getLine()), +               ($IF_KW.getCharPositionInLine()) +            ), +            ($value.result), +            ($general_fate_instr.result) +         );     }     | IF_ELSE_KW           WS+ value -         WS+ general_fate_instr -         WS+ general_fate_instr +         WS+ if_true=general_fate_instr +         WS+ if_false=general_fate_instr        WS* R_PAREN     { -      /* TODO */ - -      $result = null; +      $result = +         IfElseInstruction.build +         ( +            CONTEXT.get_origin_at +            ( +               ($IF_ELSE_KW.getLine()), +               ($IF_ELSE_KW.getCharPositionInLine()) +            ), +            ($value.result), +            ($if_true.result), +            ($if_false.result) +         );     }     | COND_KW WS+ instr_cond_list WS* R_PAREN     { -      /* TODO */ - -      $result = null; +      $result = +         CondInstruction.build +         ( +            CONTEXT.get_origin_at +            ( +               ($COND_KW.getLine()), +               ($COND_KW.getCharPositionInLine()) +            ), +            ($instr_cond_list.result) +         );     } -   | PLAYER_CHOICE_KW WS+ (player_choice WS*)+ R_PAREN +   | PLAYER_CHOICE_KW WS+ player_choice_list WS* R_PAREN     { -      /* TODO */ - -      $result = null; +      $result = +         new PlayerChoiceList +         ( +            CONTEXT.get_origin_at +            ( +               ($PLAYER_CHOICE_KW.getLine()), +               ($PLAYER_CHOICE_KW.getCharPositionInLine()) +            ), +            ($player_choice_list.result) +         );     }     | EXTENSION_INSTRUCTION_KW WORD WS+ general_fate_sequence WS* R_PAREN @@ -621,9 +665,12 @@ returns [InstructionNode result]     | paragraph     { -      /* TODO */ - -      $result = null; +      $result = +         new Display +         ( +            ($paragraph.result.get_origin()), +            ($paragraph.result) +         );     }  ;  catch [final Throwable e] @@ -632,10 +679,10 @@ catch [final Throwable e]  }  instr_cond_list -returns [List<Cons<ValueNode,InstructionNode>> result] +returns [List<Cons<ValueNode, InstructionNode>> result]  @init  { -   $result = new ArrayList<Cons<ValueNode,InstructionNode>>(); +   $result = new ArrayList<Cons<ValueNode, InstructionNode>>();  }  :     ( @@ -649,37 +696,119 @@ returns [List<Cons<ValueNode,InstructionNode>> result]     }  ; -player_choice: -   L_PAREN WS* -      L_PAREN WS* text+ WS* R_PAREN WS+ +player_choice_list +returns [List<InstructionNode> result] +@init +{ +   $result = new ArrayList<InstructionNode>(); +} +: +   (WS* +      player_choice +      { +         $result.add(($player_choice.result)); +      } +   WS*)* +   { +   } +; + +player_choice +returns [InstructionNode result] +: +   start_p=L_PAREN WS* +      L_PAREN WS* paragraph WS* R_PAREN WS+        general_fate_sequence WS*     R_PAREN     { -      /* TODO */ +      $result = +         new PlayerChoice +         ( +            CONTEXT.get_origin_at +            ( +               ($start_p.getLine()), +               ($start_p.getCharPositionInLine()) +            ), +            ($paragraph.result), +            ($general_fate_sequence.result) +         );     }     | IF_KW WS+ value WS+ player_choice WS* R_PAREN     { -      /* TODO */ +      $result = +         IfInstruction.build +         ( +            CONTEXT.get_origin_at +            ( +               ($IF_KW.getLine()), +               ($IF_KW.getCharPositionInLine()) +            ), +            ($value.result), +            ($player_choice.result) +         );     } -   | IF_ELSE_KW WS+ value WS+ player_choice WS+ player_choice WS* R_PAREN +   | IF_ELSE_KW WS+ +      value WS+ +      if_true=player_choice WS+ +      if_false=player_choice WS* +   R_PAREN     { -      /* TODO */ +      $result = +         IfElseInstruction.build +         ( +            CONTEXT.get_origin_at +            ( +               ($IF_ELSE_KW.getLine()), +               ($IF_ELSE_KW.getCharPositionInLine()) +            ), +            ($value.result), +            ($if_true.result), +            ($if_false.result) +         );     }     | COND_KW WS+ player_choice_cond_list WS* R_PAREN     { -      /* TODO */ +      $result = +         CondInstruction.build +         ( +            CONTEXT.get_origin_at +            ( +               ($COND_KW.getLine()), +               ($COND_KW.getCharPositionInLine()) +            ), +            ($player_choice_cond_list.result) +         );     }  ; +catch [final Throwable e] +{ +   throw new ParseCancellationException(e); +} -player_choice_cond_list: -   (L_PAREN WS* value WS+ player_choice WS* R_PAREN WS*)+ +player_choice_cond_list +returns [List<Cons<ValueNode, InstructionNode>> result] +@init +{ +   $result = new ArrayList<Cons<ValueNode, InstructionNode>>(); +} +: +   ( +      L_PAREN WS* value WS+ player_choice WS* R_PAREN +      { +         $result.add(new Cons(($value.result), ($player_choice.result))); +      } +      WS* +   )+     { -      /* TODO */     }  ; +catch [final Throwable e] +{ +   throw new ParseCancellationException(e); +}  paragraph  returns [TextNode result] @@ -1323,13 +1452,35 @@ returns [ValueNode result]     | L_PAREN WS+ paragraph WS* R_PAREN     { -      /* TODO */ -      $result = null; +      $result = ($paragraph.result);     }     | ENABLE_TEXT_EFFECT_KW WS+ WORD WS+ paragraph WS* R_PAREN     { -      /* TODO */ +      final TextEffect effect; + +      effect = +         WORLD.text_effects().get +         ( +            CONTEXT.get_origin_at +            ( +               ($WORD.getLine()), +               ($WORD.getCharPositionInLine()) +            ), +            ($WORD.text) +         ); + +      $result = +         new TextWithEffect +         ( +            CONTEXT.get_origin_at +            ( +               ($WORD.getLine()), +               ($WORD.getCharPositionInLine()) +            ), +            effect, +            ($paragraph.result) +         );     }     | ENABLE_TEXT_EFFECT_KW WS+ @@ -1340,12 +1491,44 @@ returns [ValueNode result]        paragraph WS*        R_PAREN     { -      /* TODO */ +      final TextEffect effect; + +      effect = +         WORLD.text_effects().get +         ( +            CONTEXT.get_origin_at +            ( +               ($WORD.getLine()), +               ($WORD.getCharPositionInLine()) +            ), +            ($WORD.text) +         ); + +      $result = +         TextWithEffect.build +         ( +            CONTEXT.get_origin_at +            ( +               ($ENABLE_TEXT_EFFECT_KW.getLine()), +               ($ENABLE_TEXT_EFFECT_KW.getCharPositionInLine()) +            ), +            effect, +            ($value_list.result), +            ($paragraph.result) +         );     }     | NEWLINE_KW     { -      /* TODO */ +      $result = +         new Newline +         ( +            CONTEXT.get_origin_at +            ( +               ($NEWLINE_KW.getLine()), +               ($NEWLINE_KW.getCharPositionInLine()) +            ) +         );     }     | non_text_value @@ -1353,6 +1536,10 @@ returns [ValueNode result]        $result = ($non_text_value.result);     }  ; +catch [final Throwable e] +{ +   throw new ParseCancellationException(e); +}  non_text_value  returns [ValueNode result] | 


