| summaryrefslogtreecommitdiff | 
diff options
9 files changed, 343 insertions, 10 deletions
| diff --git a/data/tests/player_choices.fate b/data/tests/player_choices.fate new file mode 100644 index 0000000..2148863 --- /dev/null +++ b/data/tests/player_choices.fate @@ -0,0 +1,98 @@ +(fate_version 1) + +(global int i) + +(player_choice +   ( +      ( Wrong Choice 0 ) +      (set i 1) +      (assert (false) FAILED: Player Choice A) +   ) +   ( +      ( Right Choice ) +      Took the right choice. +      (set i 2) +   ) +   ( +      ( Wrong Choice 1 ) +      (set i 1) +      (assert (false) FAILED: Player Choice B) +   ) +) + +(assert (= (var i) 2) FAILED: Player Choice C, i: (var i)) + +(player_choice +   (if (false) +      ( +         ( Wrong Choice 0 ) +         (set i 1) +      ) +   ) +   (ifelse (false) +      ( +         ( Wrong Choice 1 ) +         (set i 3) +      ) +      (if (true) +         ( +            ( Right Choice ) +            (set i 6) +         ) +      ) +   ) +) + +(assert (= (var i) 6) FAILED: Player Choice D, i: (var i)) + +(global (set int) test_set) + +(while (>= (var i) 0) +   (add (var i) test_set) +   (set i (- (var i) 1)) +) + +(foreach test_set e +   (var e) +) + +(player_choice +   (if (false) +      ( +         ( Wrong Choice -1 ) +         (set i 1) +      ) +   ) +   (foreach test_set e +      (ifelse (= (var e) 3) +         ( +            ( Correct Choice (var e) ) +            ( +               Chosen var e: (var e) +               (set i 653) +            ) +         ) +         ( +            ( Wrong Choice (var e) ) +            ( +               Chosen var e: (var e) +               (set i (var e)) +            ) +         ) +      ) +   ) +   (ifelse (false) +      ( +         ( Wrong Choice 1 ) +         (set i 3) +      ) +      ( +         ( Wrong Choice Other ) +         (set i 6) +      ) +   ) +) + +(assert (= (var i) 653) FAILED: Player Choice E, i: (var i)) + +(end) diff --git a/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4 b/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4 index 7077127..1525d42 100644 --- a/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4 +++ b/src/core/src/tonkadur/fate/v1/parser/FateLexer.g4 @@ -82,10 +82,9 @@ REF_KW: L_PAREN (((('ref'('erence'?))|'ptr'|'pointer')(US'to')?)|('address'(US'o  REMOVE_ALL_KW: L_PAREN 'remove'US'all' SEP+;  REVERSE_KW: L_PAREN 'reverse'(US'list')? SEP+;  REMOVE_ONE_KW: L_PAREN 'remove'US'one' SEP+; -REMOVE_AT_KW: L_PAREN ('remove'US('elem'('ent')?US)?'at'|'rm'|'del'|'delete') SEP+; +REMOVE_AT_KW: L_PAREN ('remove'US('elem'('ent')?US)?'at') SEP+;  REQUIRE_EXTENSION_KW: L_PAREN 'require'US'extension' SEP+;  REQUIRE_KW: L_PAREN 'require' SEP+; -SEQUENCE_KW: L_PAREN 'seq'('uence')? SEP+;  SET_FIELDS_KW: L_PAREN 'set'US'fields' SEP+;  SET_KW: L_PAREN 'set'(US(('val''ue'?)|('var''iable'?)))? SEP+;  LIST_KW: L_PAREN 'list' SEP+; @@ -94,7 +93,6 @@ SWITCH_KW: L_PAREN 'switch' SEP+;  TIMES_KW: L_PAREN ('times'|'*') SEP+;  TRUE_KW: L_PAREN 'true)';  DONE_KW: L_PAREN 'done)'; -VAL_KW: L_PAREN ('val'|'value') SEP+;  VARIABLE_KW: L_PAREN ('variable'|'var') SEP+;  VISIT_KW: L_PAREN ('call'|'visit')(US(('seq'('uence'?))|('proc'('edure'?))))? SEP+;  CONTINUE_AS_KW: L_PAREN (('continue'US('as'|'to'|'with'))|('jump'(US'to')?)|('go'US'to')|'exec')(US(('seq'('uence'?))|('proc'('edure'?))))? SEP+; diff --git a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 index f122a9a..2c6aeca 100644 --- a/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 +++ b/src/core/src/tonkadur/fate/v1/parser/FateParser.g4 @@ -1351,6 +1351,105 @@ returns [Instruction result]              ($player_choice.result)           );     } + +   | FOR_EACH_KW +      value_reference WS+ new_reference_name +      { +         final Map<String, Variable> variable_map; +         final Variable new_variable; +         final Type collection_type; +         Type elem_type; + +         elem_type = Type.ANY; + +         collection_type = ($value_reference.result).get_type(); + +         if (collection_type instanceof CollectionType) +         { +            elem_type = ((CollectionType) collection_type).get_content_type(); +         } +         else +         { +            ErrorManager.handle +            ( +               new InvalidTypeException +               ( +                  CONTEXT.get_origin_at +                  ( +                     ($FOR_EACH_KW.getLine()), +                     ($FOR_EACH_KW.getCharPositionInLine()) +                  ), +                  elem_type, +                  Type.COLLECTION_TYPES +               ) +            ); + +            elem_type = Type.ANY; +         } + + +         new_variable = +            new Variable +            ( +               CONTEXT.get_origin_at +               ( +                  ($FOR_EACH_KW.getLine()), +                  ($FOR_EACH_KW.getCharPositionInLine()) +               ), +               elem_type, +               ($new_reference_name.result) +            ); + +         variable_map = LOCAL_VARIABLES.peekFirst(); + +         if (variable_map.containsKey(($new_reference_name.result))) +         { +            ErrorManager.handle +            ( +               new DuplicateLocalVariableException +               ( +                  variable_map.get(($new_reference_name.result)), +                  new_variable +               ) +            ); +         } +         else +         { +            variable_map.put(($new_reference_name.result), new_variable); +         } +      } +      WS+ +      { +         BREAKABLE_LEVELS++; +         HIERARCHICAL_VARIABLES.push(new ArrayList()); +      } +      player_choice_list +      { +         BREAKABLE_LEVELS--; + +         for (final String s: HIERARCHICAL_VARIABLES.pop()) +         { +            LOCAL_VARIABLES.peekFirst().remove(s); +         } +      } +      WS* +   R_PAREN +   { +      $result = +         new ForEach +         ( +            CONTEXT.get_origin_at +            ( +               ($FOR_EACH_KW.getLine()), +               ($FOR_EACH_KW.getCharPositionInLine()) +            ), +            ($value_reference.result), +            ($new_reference_name.result), +            ($player_choice_list.result) +         ); + +      variable_map.remove(($new_reference_name.result)); +   }  ;  catch [final Throwable e]  { @@ -2757,7 +2856,7 @@ returns [Reference result]           );     } -   | FIELD_KW value_reference WORD R_PAREN +   | FIELD_KW value_reference WS+ WORD WS* R_PAREN     {        $result =           FieldReference.build 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 2c163e7..42df895 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 @@ -24,6 +24,7 @@ import tonkadur.wyrd.v1.lang.computation.Operation;  import tonkadur.wyrd.v1.lang.computation.Address;  import tonkadur.wyrd.v1.lang.computation.RelativeAddress;  import tonkadur.wyrd.v1.lang.computation.Size; +import tonkadur.wyrd.v1.lang.computation.GetLastChoiceIndex;  import tonkadur.wyrd.v1.lang.computation.ValueOf;  import tonkadur.wyrd.v1.lang.instruction.AddChoice; @@ -1291,9 +1292,12 @@ implements tonkadur.fate.v1.lang.meta.InstructionVisitor         *         * Wyrd (add_choice label i0)         */ +      final List<Instruction> to_next, labels_only;        final ComputationCompiler cc;        final String start_of_effect, end_of_effect; +      to_next = new ArrayList<Instruction>(); +      labels_only = new ArrayList<Instruction>();        cc = new ComputationCompiler(compiler);        start_of_effect = compiler.assembler().generate_label("<choice#start>"); @@ -1306,7 +1310,7 @@ implements tonkadur.fate.v1.lang.meta.InstructionVisitor           result.add(cc.get_init());        } -      result.add +      labels_only.add        (           new AddChoice           ( @@ -1314,13 +1318,62 @@ implements tonkadur.fate.v1.lang.meta.InstructionVisitor              compiler.assembler().get_label_constant(start_of_effect)           )        ); + +      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           ( -            new SetPC +            If.generate              ( -               compiler.assembler().get_label_constant(end_of_effect) +               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           ) @@ -1359,13 +1412,29 @@ implements tonkadur.fate.v1.lang.meta.InstructionVisitor     )     throws Throwable     { -      final String end_of_choices_label; +      final String start_of_choices_label, end_of_choices_label; + +      start_of_choices_label = +         compiler.assembler().generate_label("<ChoicesDefinition>");        end_of_choices_label =           compiler.assembler().generate_label("<ChoicesResolved>");        compiler.assembler().push_context_label("choices", end_of_choices_label); +      result.add +      ( +         compiler.assembler().mark_after +         ( +            new SetValue +            ( +               compiler.registers().get_choice_number_holder().get_address(), +               new Constant(Type.INT, "-2") +            ), +            start_of_choices_label +         ) +      ); +        /*         * Fate: (player_choice_list i0 ... in)         * @@ -1386,11 +1455,25 @@ implements tonkadur.fate.v1.lang.meta.InstructionVisitor        compiler.assembler().pop_context_label("choices"); +      result.add(new ResolveChoices()); + +      result.add +      ( +         new SetValue +         ( +            compiler.registers().get_choice_number_holder().get_address(), +            new Constant(Type.INT, "0") +         ) +      ); +        result.add        (           compiler.assembler().mark_after           ( -            new ResolveChoices(), +            new SetPC +            ( +               compiler.assembler().get_label_constant(start_of_choices_label) +            ),              end_of_choices_label           )        ); diff --git a/src/core/src/tonkadur/wyrd/v1/compiler/util/registers/RegisterContext.java b/src/core/src/tonkadur/wyrd/v1/compiler/util/registers/RegisterContext.java index 08c71f2..090f596 100644 --- a/src/core/src/tonkadur/wyrd/v1/compiler/util/registers/RegisterContext.java +++ b/src/core/src/tonkadur/wyrd/v1/compiler/util/registers/RegisterContext.java @@ -146,6 +146,7 @@ class RegisterContext     public void unbind (final String name)     { +      release(aliased_registers.get(name));        aliased_registers.remove(name);     } diff --git a/src/core/src/tonkadur/wyrd/v1/compiler/util/registers/RegisterManager.java b/src/core/src/tonkadur/wyrd/v1/compiler/util/registers/RegisterManager.java index 2fbad42..8af7754 100644 --- a/src/core/src/tonkadur/wyrd/v1/compiler/util/registers/RegisterManager.java +++ b/src/core/src/tonkadur/wyrd/v1/compiler/util/registers/RegisterManager.java @@ -37,7 +37,7 @@ public class RegisterManager     protected final Map<String, StackableRegisterContext> context_by_name;     protected final Deque<RegisterContext> context;     protected final RegisterContext base_context, parameter_context; -   protected final Register next_pc, pc_stack; +   protected final Register next_pc, pc_stack, choice_number;     protected int created_contexts;     public RegisterManager () @@ -45,6 +45,7 @@ public class RegisterManager        base_context = new RegisterContext("base context");        parameter_context = new RegisterContext("parameter context", ".param.");        next_pc = base_context.reserve(Type.INT); +      choice_number = base_context.reserve(Type.INT);        pc_stack = base_context.reserve(new MapType(Type.INT));        context_by_name = new HashMap<String, StackableRegisterContext>(); @@ -69,6 +70,11 @@ public class RegisterManager        return context_name_prefix + (created_contexts++);     } +   public Register get_choice_number_holder () +   { +      return choice_number; +   } +     public void create_stackable_context (final String context_name)     {        final StackableRegisterContext result; diff --git a/src/core/src/tonkadur/wyrd/v1/lang/computation/GetLastChoiceIndex.java b/src/core/src/tonkadur/wyrd/v1/lang/computation/GetLastChoiceIndex.java new file mode 100644 index 0000000..8f70687 --- /dev/null +++ b/src/core/src/tonkadur/wyrd/v1/lang/computation/GetLastChoiceIndex.java @@ -0,0 +1,37 @@ +package tonkadur.wyrd.v1.lang.computation; + +import tonkadur.wyrd.v1.lang.type.Type; + +import tonkadur.wyrd.v1.lang.meta.Computation; +import tonkadur.wyrd.v1.lang.meta.ComputationVisitor; + +public class GetLastChoiceIndex extends Computation +{ +   /***************************************************************************/ +   /**** MEMBERS **************************************************************/ +   /***************************************************************************/ + +   /***************************************************************************/ +   /**** PUBLIC ***************************************************************/ +   /***************************************************************************/ +   /**** Constructors *********************************************************/ +   public GetLastChoiceIndex () +   { +      super(Type.INT); +   } + +   /**** Accessors ************************************************************/ +   @Override +   public void get_visited_by (final ComputationVisitor cv) +   throws Throwable +   { +      cv.visit_get_last_choice_index(this); +   } + +   /**** Misc. ****************************************************************/ +   @Override +   public String toString () +   { +      return "(GetLastChoiceIndex)"; +   } +} diff --git a/src/core/src/tonkadur/wyrd/v1/lang/meta/ComputationVisitor.java b/src/core/src/tonkadur/wyrd/v1/lang/meta/ComputationVisitor.java index fdfdc1b..1d9b2be 100644 --- a/src/core/src/tonkadur/wyrd/v1/lang/meta/ComputationVisitor.java +++ b/src/core/src/tonkadur/wyrd/v1/lang/meta/ComputationVisitor.java @@ -31,6 +31,9 @@ public interface ComputationVisitor     public void visit_relative_address (final RelativeAddress n)     throws Throwable; +   public void visit_get_last_choice_index (final GetLastChoiceIndex n) +   throws Throwable; +     public void visit_rich_text (final RichText n)     throws Throwable; diff --git a/src/json-export/src/tonkadur/jsonexport/ComputationCompiler.java b/src/json-export/src/tonkadur/jsonexport/ComputationCompiler.java index 3210f73..132e658 100644 --- a/src/json-export/src/tonkadur/jsonexport/ComputationCompiler.java +++ b/src/json-export/src/tonkadur/jsonexport/ComputationCompiler.java @@ -116,6 +116,14 @@ public class ComputationCompiler implements ComputationVisitor        result.put("category", "newline");     } +   public void visit_get_last_choice_index (final GetLastChoiceIndex n) +   throws Throwable +   { +      result = new JSONObject(); + +      result.put("category", "last_choice_index"); +   } +     public void visit_operation (final Operation n)     throws Throwable     { | 


