this repo has no description
1using GDWeave.Godot;
2using GDWeave.Godot.Variants;
3using static GDWeave.Godot.TokenType;
4
5namespace Teemaw.Calico.Util;
6
7public static class TokenUtil
8{
9 public static IEnumerable<Token> ReplaceAssignmentsAsDeferred(IEnumerable<Token> tokens,
10 HashSet<string>? ignoredIdentifiers = null)
11 {
12 Token? lastToken = null;
13 var inAssignmentStatement = false;
14 var skipLine = false;
15 foreach (var t in tokens)
16 {
17 switch (t)
18 {
19 case { Type: Newline }:
20 skipLine = false;
21 break;
22 case { Type: PrVar }:
23 skipLine = true;
24 break;
25 default:
26 {
27 if (lastToken is IdentifierToken identifier &&
28 (ignoredIdentifiers == null || !ignoredIdentifiers.Contains(identifier.Name)) &&
29 t is { Type: OpAssign } && !skipLine)
30 {
31 inAssignmentStatement = true;
32 yield return new IdentifierToken("set_deferred");
33 yield return new Token(ParenthesisOpen);
34 yield return new ConstantToken(new StringVariant(identifier.Name));
35 yield return new Token(Comma);
36 // Don't return the last token or current token
37 lastToken = null;
38 continue;
39 }
40
41 break;
42 }
43 }
44
45 if (t.Type == Newline && inAssignmentStatement)
46 {
47 inAssignmentStatement = false;
48 if (lastToken != null)
49 yield return lastToken;
50 // Close out the set_deferred call...
51 yield return new Token(ParenthesisClose);
52 // ...before the Newline token.
53 yield return t;
54 }
55 else if (lastToken != null)
56 yield return lastToken;
57
58 lastToken = inAssignmentStatement && t is { Type: Identifier } ? StripAssociatedData(t) : t;
59 }
60
61 if (lastToken != null)
62 yield return lastToken;
63 }
64
65 public static Token ReplaceToken(Token cursor, Token target, Token replacement)
66 {
67 return TokenEquals(cursor, target) ? replacement : cursor;
68 }
69
70 public static IEnumerable<Token> ReplaceTokens(IEnumerable<Token> haystack, IEnumerable<Token> needle,
71 IEnumerable<Token> replacements)
72 {
73 var haystackList = haystack.ToList();
74 var needleList = needle.ToList();
75 var replacementsList = replacements.ToList();
76
77 if (needleList.Count == 0) return haystackList;
78
79 var result = new List<Token>();
80 var i = 0;
81
82 while (i < haystackList.Count)
83 {
84 if (IsMatch(haystackList, needleList, i))
85 {
86 result.AddRange(replacementsList);
87 i += needleList.Count;
88 }
89 else
90 {
91 result.Add(haystackList[i]);
92 i++;
93 }
94 }
95
96 return result;
97 }
98
99 private static bool IsMatch(List<Token> haystack, List<Token> needle, int startIndex)
100 {
101 if (startIndex + needle.Count > haystack.Count)
102 return false;
103
104 for (int i = 0; i < needle.Count; i++)
105 {
106 if (!TokenEquals(haystack[startIndex + i], needle[i]))
107 return false;
108 }
109
110 return true;
111 }
112
113 private static bool TokenEquals(Token token, Token token1)
114 {
115 if (token is IdentifierToken id && token1 is IdentifierToken id1)
116 {
117 return id.Name == id1.Name;
118 }
119 if (token is ConstantToken constant && token1 is ConstantToken constant1)
120 {
121 return constant.Value.Equals(constant1.Value);
122 }
123 return token.Type == token1.Type && token.AssociatedData == token1.AssociatedData;
124 }
125
126 private static Token StripAssociatedData(Token token)
127 {
128 token.AssociatedData = null;
129 return token;
130 }
131}