JPF.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. using System;
  2. using System.Collections.Generic;
  3. namespace OpenVIII.Fields.Scripts.Instructions
  4. {
  5. internal sealed class JPF : JsmInstruction, IJumpToOpcode, IFormattableScript
  6. {
  7. public Int32 Offset { get; set; }
  8. public IReadOnlyList<IJsmExpression> Conditions => _conditions;
  9. private readonly List<IJsmExpression> _conditions = new List<IJsmExpression>();
  10. public JPF(Int32 offset, IJsmExpression condition)
  11. {
  12. Offset = offset;
  13. _conditions.Add(condition);
  14. }
  15. public JPF(Int32 offset, IStack<IJsmExpression> stack)
  16. : this(offset,
  17. condition: stack.Pop())
  18. {
  19. }
  20. public void Inverse(JMP nextJmp)
  21. {
  22. if (_conditions.Count != 1)
  23. throw new NotSupportedException($"Conditional jump already merged with an other one: {this}");
  24. IJsmExpression expression = _conditions[0];
  25. if (!(expression is ILogicalExpression constExpression))
  26. _conditions[0] = new Jsm.Expression.CAL.LogNot(expression);
  27. else
  28. _conditions[0] = constExpression.LogicalInverse();
  29. Int32 jmpIndex = nextJmp.Index;
  30. Int32 jmpOffset = nextJmp.Offset;
  31. nextJmp.Index = Index;
  32. nextJmp.Offset = Offset;
  33. Index = jmpIndex;
  34. Offset = jmpOffset;
  35. }
  36. public void Union(JPF newJpf)
  37. {
  38. foreach (var cond in newJpf.Conditions)
  39. _conditions.Add(cond);
  40. }
  41. private Int32 _index = -1;
  42. public Int32 Index
  43. {
  44. get
  45. {
  46. if (_index == -1)
  47. throw new ArgumentException($"{nameof(JPF)} instruction isn't indexed yet.", nameof(Index));
  48. return _index;
  49. }
  50. set
  51. {
  52. //if (_index != -1)
  53. // throw new ArgumentException($"{nameof(JPF)} instruction has already been indexed: {_index}.", nameof(Index));
  54. _index = value;
  55. }
  56. }
  57. public override String ToString()
  58. {
  59. return _index < 0
  60. ? $"{nameof(JPF)}[{nameof(Offset)}: {Offset}, {nameof(Conditions)}: ( {String.Join(") && (", Conditions)} )]"
  61. : $"{nameof(JPF)}[{nameof(Index)}: {Index}, {nameof(Conditions)}: ( {String.Join(") && (", Conditions)} )]";
  62. }
  63. public override void Format(ScriptWriter sw, IScriptFormatterContext formatterContext, IServices services)
  64. {
  65. ScriptWriter.State state = sw.RememberState();
  66. Boolean isTrue = true;
  67. foreach (IJsmExpression expression in _conditions)
  68. {
  69. if (expression is IConstExpression number)
  70. {
  71. if (number.Value == 0)
  72. {
  73. // We can ignore the other conditions if one of them is always false
  74. state.Cancel();
  75. sw.Append("false");
  76. return;
  77. }
  78. // We don't need to add a condition that is always true
  79. }
  80. else
  81. {
  82. isTrue = false;
  83. if (state.IsChanged)
  84. sw.Append(" && ");
  85. expression.Format(sw, formatterContext, services);
  86. }
  87. }
  88. if (isTrue)
  89. {
  90. // We can ignore conditions if all of them is always true
  91. state.Cancel();
  92. sw.Append("true");
  93. }
  94. }
  95. }
  96. }