Jsm.LabelBuilder.cs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. using OpenVIII.Fields.Scripts.Instructions;
  2. using System;
  3. using System.Collections.Generic;
  4. namespace OpenVIII.Fields.Scripts
  5. {
  6. public static partial class Jsm
  7. {
  8. #region Classes
  9. public sealed class LabelBuilder
  10. {
  11. #region Fields
  12. private readonly ushort _opcodeCount;
  13. private readonly Dictionary<int, List<IJumpToOpcode>> _targets = new Dictionary<int, List<IJumpToOpcode>>();
  14. private Dictionary<int, IndexedInstruction> _candidates = new Dictionary<int, IndexedInstruction>();
  15. #endregion Fields
  16. #region Constructors
  17. public LabelBuilder(ushort opcodeCount) => _opcodeCount = opcodeCount;
  18. #endregion Constructors
  19. #region Methods
  20. public HashSet<int> Commit()
  21. {
  22. var result = new HashSet<int>();
  23. foreach (var pair in _targets)
  24. {
  25. var offset = pair.Key;
  26. if (!_candidates.TryGetValue(offset, out var target))
  27. throw new InvalidProgramException($"Invalid jump target: {pair.Key}");
  28. foreach (var jump in pair.Value)
  29. jump.Index = target.Index;
  30. result.Add(target.Index);
  31. }
  32. return result;
  33. }
  34. public void TraceInstruction(int position, int label, IndexedInstruction instruction)
  35. {
  36. _candidates.Add(label, instruction);
  37. if (!(instruction.Instruction is IJumpToOpcode jump))
  38. return;
  39. var target = position + jump.Offset;
  40. if (target < 0)
  41. throw new InvalidProgramException($"Trying to jump out of script ({position} -> {target}). The field \"test3.jsm\" isn't supported.");
  42. if (target >= _opcodeCount)
  43. {
  44. if (target == 74) // escouse1.jsm (Lunar Gate - Concourse)
  45. target = _opcodeCount - 1;
  46. else
  47. throw new InvalidProgramException($"Trying to jump out of script ({position} -> {target}).");
  48. }
  49. if (!_targets.TryGetValue(target, out var list))
  50. {
  51. list = new List<IJumpToOpcode>();
  52. _targets.Add(target, list);
  53. }
  54. list.Add(jump);
  55. }
  56. #endregion Methods
  57. }
  58. #endregion Classes
  59. }
  60. }