Jsm.Segment.Builder.cs 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  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. public partial class Segment
  9. {
  10. public static class Builder
  11. {
  12. public static ExecutableSegment Build(List<JsmInstruction> instructions, IReadOnlyList<IJsmControl> controls)
  13. {
  14. Dictionary<Int32, List<Segment>> dic = new Dictionary<Int32, List<Segment>>();
  15. foreach (var control in controls)
  16. {
  17. foreach (var seg in control.EnumerateSegments())
  18. {
  19. if (!dic.TryGetValue(seg.From, out var list))
  20. {
  21. list = new List<Segment>();
  22. dic.Add(seg.From, list);
  23. }
  24. list.Add(seg);
  25. }
  26. }
  27. ExecutableSegment rootSegment = new ExecutableSegment(0, instructions.Count);
  28. dic.Add(0, new List<Segment> {rootSegment});
  29. Stack<Segment> segments = new Stack<Segment>();
  30. Segment segment = rootSegment;
  31. Int32 instructionsCount = instructions.Count;
  32. for (Int32 i = 0; i < instructionsCount; i++)
  33. {
  34. while (segment.To <= i)
  35. segment = segments.Pop();
  36. if (i > 0 && dic.TryGetValue(i, out var nestedSegments))
  37. {
  38. foreach (var seg in nestedSegments)
  39. {
  40. segments.Push(segment);
  41. if (seg is ExecutableSegment executable)
  42. segment.Add(executable);
  43. segment = seg;
  44. if (!(instructions[i] is IJumpToInstruction))
  45. segment.Add(instructions[i]);
  46. }
  47. }
  48. else
  49. {
  50. segment.Add(instructions[i]);
  51. }
  52. }
  53. if (segments.Count != 0)
  54. throw new InvalidProgramException("Failed to join code segments.");
  55. return rootSegment;
  56. }
  57. }
  58. }
  59. }
  60. }