Free cookie consent management tool by TermsFeed Policy Generator

source: addons/HeuristicLab.PushGP/HeuristicLab.Problems.ProgramSynthesis/Push/Expressions/StringExpressions.cs @ 16958

Last change on this file since 16958 was 15334, checked in by pkimmesw, 7 years ago

#2665 Testet Problems, Testet error functions, Small fixes, Created HL files

File size: 28.7 KB
Line 
1namespace HeuristicLab.Problems.ProgramSynthesis.Push.Expressions {
2  using System;
3  using System.Globalization;
4  using System.Linq;
5
6  using Attributes;
7
8  using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
9  using HeuristicLab.Problems.ProgramSynthesis.Push.Extensions;
10
11  using Interpreter;
12  using Stack;
13
14  /// <summary>
15  /// Stringifies and pushes the top INTEGER.,
16  /// </summary>
17  [StorableClass]
18  [PushExpression(
19    StackTypes.String,
20    "STRING.FROMINTEGER",
21    "Stringifies and pushes the top INTEGER.",
22    StackTypes.Integer)]
23  public class StringFromIntegerExpression : StatelessExpression {
24    public StringFromIntegerExpression() { }
25    [StorableConstructor]
26    protected StringFromIntegerExpression(bool deserializing) : base(deserializing) { }
27
28    public override bool IsNoop(IInternalPushInterpreter interpreter) {
29      return interpreter.IntegerStack.IsEmpty;
30    }
31
32    public override void Eval(IInternalPushInterpreter interpreter) {
33      var value = interpreter.IntegerStack.Pop();
34      interpreter.StringStack.Push(value.ToString());
35    }
36  }
37
38  [StorableClass]
39  [PushExpression(
40    StackTypes.String,
41    "STRING.FROMFLOAT",
42    "Stringifies and pushes the top FLOAT.",
43    StackTypes.Float)]
44  public class StringFromFloatExpression : StatelessExpression {
45    public StringFromFloatExpression() { }
46    [StorableConstructor]
47    protected StringFromFloatExpression(bool deserializing) : base(deserializing) { }
48
49    public override bool IsNoop(IInternalPushInterpreter interpreter) {
50      return interpreter.FloatStack.IsEmpty;
51    }
52
53    public override void Eval(IInternalPushInterpreter interpreter) {
54      var value = interpreter.FloatStack.Pop();
55      var str = value.ToString(interpreter.Configuration.FloatStringFormat, CultureInfo.InvariantCulture);
56
57      interpreter.StringStack.Push(str);
58    }
59  }
60
61  /// <summary>
62  /// Stringifies and pushes the top BOOLEAN.
63  /// </summary>
64  [StorableClass]
65  [PushExpression(
66    StackTypes.String,
67    "STRING.FROMBOOLEAN",
68    "Stringifies and pushes the top BOOLEAN.",
69    StackTypes.Boolean)]
70  public class StringFromBooleanExpression : StatelessExpression {
71    public StringFromBooleanExpression() { }
72    [StorableConstructor]
73    protected StringFromBooleanExpression(bool deserializing) : base(deserializing) { }
74
75    public override bool IsNoop(IInternalPushInterpreter interpreter) {
76      return interpreter.BooleanStack.IsEmpty;
77    }
78
79    public override void Eval(IInternalPushInterpreter interpreter) {
80      var value = interpreter.BooleanStack.Pop();
81      interpreter.StringStack.Push(value.ToString());
82    }
83  }
84
85  /// <summary>
86  /// Stringifies and pushes the top CHAR.
87  /// </summary>
88  [StorableClass]
89  [PushExpression(
90    StackTypes.String,
91    "STRING.FROMCHAR",
92    "Stringifies and pushes the top CHAR.",
93    StackTypes.Char)]
94  public class StringFromCharExpression : StatelessExpression {
95    public StringFromCharExpression() { }
96    [StorableConstructor]
97    protected StringFromCharExpression(bool deserializing) : base(deserializing) { }
98
99    public override bool IsNoop(IInternalPushInterpreter interpreter) {
100      return interpreter.CharStack.IsEmpty;
101    }
102
103    public override void Eval(IInternalPushInterpreter interpreter) {
104      var value = interpreter.CharStack.Pop();
105      interpreter.StringStack.Push(value.ToString());
106    }
107  }
108
109  /// <summary>
110  /// Concats the top 2 strings.
111  /// </summary>
112  [StorableClass]
113  [PushExpression(
114    StackTypes.String,
115    "STRING.CONCAT",
116    "Concats the top 2 strings.")]
117  public class StringConcatExpression : StatelessExpression {
118    public StringConcatExpression() { }
119    [StorableConstructor]
120    protected StringConcatExpression(bool deserializing) : base(deserializing) { }
121
122    public override bool IsNoop(IInternalPushInterpreter interpreter) {
123      return interpreter.StringStack.Count < 2 ||
124             interpreter.StringStack.Top.Length + interpreter.StringStack[1].Length > interpreter.Configuration.MaxStringLength;
125    }
126
127    public override void Eval(IInternalPushInterpreter interpreter) {
128      var str = interpreter.StringStack.Pop();
129      interpreter.StringStack.Top += str;
130    }
131  }
132
133  /// <summary>
134  /// Conj char onto string
135  /// </summary>
136  [StorableClass]
137  [PushExpression(
138    StackTypes.String,
139    "STRING.CONJCHAR",
140    "Conj top CHAR onto top STRING",
141    StackTypes.Char)]
142  public class StringConjCharExpression : StatelessExpression {
143    public StringConjCharExpression() { }
144    [StorableConstructor]
145    protected StringConjCharExpression(bool deserializing) : base(deserializing) { }
146
147    public override bool IsNoop(IInternalPushInterpreter interpreter) {
148      return interpreter.StringStack.IsEmpty ||
149             interpreter.CharStack.IsEmpty ||
150             interpreter.StringStack.Top.Length + 1 > interpreter.Configuration.MaxStringLength;
151    }
152
153    public override void Eval(IInternalPushInterpreter interpreter) {
154      var c = interpreter.CharStack.Pop();
155      interpreter.StringStack.Top += c;
156    }
157  }
158
159  /// <summary>
160  /// Same as substring 0-n, whereby n is taken from the INTEGER stack.
161  /// </summary>
162  [StorableClass]
163  [PushExpression(
164    StackTypes.String,
165    "STRING.TAKE",
166    "Same as substring 0-n, whereby n is taken from the INTEGER stack.",
167    StackTypes.Integer)]
168  public class StringTakeExpression : StatelessExpression {
169    public StringTakeExpression() { }
170    [StorableConstructor]
171    protected StringTakeExpression(bool deserializing) : base(deserializing) { }
172
173    public override bool IsNoop(IInternalPushInterpreter interpreter) {
174      return interpreter.StringStack.IsEmpty ||
175             interpreter.IntegerStack.IsEmpty;
176    }
177
178    public override void Eval(IInternalPushInterpreter interpreter) {
179      var str = interpreter.StringStack.Top;
180
181      if (str.Length == 0)
182        return;
183
184      var endIndex = interpreter.IntegerStack.Pop().AsInt(str.Length);
185      interpreter.StringStack.Top = str.Substring(0, endIndex);
186    }
187  }
188
189  /// <summary>
190  /// Replaces top STRING with a substring from index A to B, whereby A and B are taken from the INTEGER STACK.
191  /// </summary>
192  [StorableClass]
193  [PushExpression(
194    StackTypes.String,
195    "STRING.SUBSTRING",
196    "Replaces top STRING with a substring from index A to B, whereby A and B are taken from the INTEGER STACK.",
197    StackTypes.Integer)]
198  public class StringSubstringExpression : StatelessExpression {
199    public StringSubstringExpression() { }
200    [StorableConstructor]
201    protected StringSubstringExpression(bool deserializing) : base(deserializing) { }
202
203    public override bool IsNoop(IInternalPushInterpreter interpreter) {
204      return interpreter.StringStack.IsEmpty ||
205             interpreter.IntegerStack.Count < 2;
206    }
207
208    public override void Eval(IInternalPushInterpreter interpreter) {
209      var str = interpreter.StringStack.Top;
210      var firstValue = interpreter.IntegerStack[1];
211      var secondValue = interpreter.IntegerStack.Top;
212      interpreter.IntegerStack.Remove(2);
213
214      var first = Math.Min(str.Length - 1, Math.Max(firstValue, 0));
215      var second = Math.Min(str.Length - 1, Math.Max(secondValue, first));
216      var length = second - first;
217
218      if (length > 0)
219        interpreter.StringStack.Top = str.Substring((int)first, (int)length);
220    }
221  }
222
223  /// <summary>
224  /// Pushes first char of top STRING.
225  /// </summary>
226  [StorableClass]
227  [PushExpression(
228    StackTypes.String,
229    "STRING.FIRST",
230    "Pushes first char of top STRING.")]
231  public class StringFirstExpression : StatelessExpression {
232    public StringFirstExpression() { }
233    [StorableConstructor]
234    protected StringFirstExpression(bool deserializing) : base(deserializing) { }
235
236    public override bool IsNoop(IInternalPushInterpreter interpreter) {
237      return interpreter.StringStack.IsEmpty ||
238             interpreter.StringStack.Top.Length == 0;
239    }
240
241    public override void Eval(IInternalPushInterpreter interpreter) {
242      interpreter.StringStack.Top = interpreter.StringStack.Top[0].ToString();
243    }
244  }
245
246  /// <summary>
247  /// Pushes last char of top STRING.
248  /// </summary>
249  [StorableClass]
250  [PushExpression(
251    StackTypes.String,
252    "STRING.LAST",
253    "Pushes last char of top STRING.")]
254  public class StringLastExpression : StatelessExpression {
255    public StringLastExpression() { }
256    [StorableConstructor]
257    protected StringLastExpression(bool deserializing) : base(deserializing) { }
258
259    public override bool IsNoop(IInternalPushInterpreter interpreter) {
260      return interpreter.StringStack.IsEmpty ||
261             interpreter.StringStack.Top.Length == 0;
262    }
263
264    public override void Eval(IInternalPushInterpreter interpreter) {
265      var str = interpreter.StringStack.Top;
266      var c = str[str.Length - 1].ToString();
267      interpreter.StringStack.Top = c;
268    }
269  }
270
271  /// <summary>
272  /// Pushes nth char of top STRING, whereby n is take from the INTEGER stack.
273  /// </summary>
274  [StorableClass]
275  [PushExpression(
276    StackTypes.String,
277    "STRING.NTH",
278    "Pushes nth char of top STRING, whereby n is take from the INTEGER stack.",
279    StackTypes.Integer)]
280  public class StringNthExpression : StatelessExpression {
281    public StringNthExpression() { }
282    [StorableConstructor]
283    protected StringNthExpression(bool deserializing) : base(deserializing) { }
284
285    public override bool IsNoop(IInternalPushInterpreter interpreter) {
286      return interpreter.StringStack.IsEmpty ||
287             interpreter.IntegerStack.IsEmpty ||
288             interpreter.StringStack.Top.Length == 0;
289    }
290
291    public override void Eval(IInternalPushInterpreter interpreter) {
292      var str = interpreter.StringStack.Top;
293      var index = str.Length == 1 ? 0 : interpreter.IntegerStack.Pop().AsInt(str.Length);
294      var c = str[index].ToString();
295      interpreter.StringStack.Top = c;
296    }
297  }
298
299  /// <summary>
300  /// Removes first char of top STRING.
301  /// </summary>
302  [StorableClass]
303  [PushExpression(
304    StackTypes.String,
305    "STRING.REST",
306    "Removes first char of top STRING.")]
307  public class StringRestExpression : StatelessExpression {
308    public StringRestExpression() { }
309    [StorableConstructor]
310    protected StringRestExpression(bool deserializing) : base(deserializing) { }
311
312    public override bool IsNoop(IInternalPushInterpreter interpreter) {
313      return interpreter.StringStack.IsEmpty ||
314             interpreter.StringStack.Top.Length == 0;
315    }
316
317    public override void Eval(IInternalPushInterpreter interpreter) {
318      var str = interpreter.StringStack.Top;
319      interpreter.StringStack.Top = str.Length == 1 ? string.Empty : str.Substring(1, str.Length - 1);
320    }
321  }
322
323  /// <summary>
324  /// Removes last char of top STRING.
325  /// </summary>
326  [StorableClass]
327  [PushExpression(
328    StackTypes.String,
329    "STRING.BUTLAST",
330    "Removes last char of top STRING.")]
331  public class StringButLastExpression : StatelessExpression {
332    public StringButLastExpression() { }
333    [StorableConstructor]
334    protected StringButLastExpression(bool deserializing) : base(deserializing) { }
335
336    public override bool IsNoop(IInternalPushInterpreter interpreter) {
337      return interpreter.StringStack.IsEmpty ||
338             interpreter.StringStack.Top.Length == 0;
339    }
340
341    public override void Eval(IInternalPushInterpreter interpreter) {
342      var str = interpreter.StringStack.Top;
343      interpreter.StringStack.Top = str.Length == 1 ? string.Empty : str.Substring(0, str.Length - 1);
344    }
345  }
346
347  /// <summary>
348  /// Pushes length of top STRING onto the INTEGER stack.
349  /// </summary>
350  [StorableClass]
351  [PushExpression(
352    StackTypes.String,
353    "STRING.LENGTH",
354    "Pushes length of top STRING onto the INTEGER stack.",
355    StackTypes.Integer)]
356  public class StringLengthExpression : StatelessExpression {
357    public StringLengthExpression() { }
358    [StorableConstructor]
359    protected StringLengthExpression(bool deserializing) : base(deserializing) { }
360
361    public override bool IsNoop(IInternalPushInterpreter interpreter) {
362      return interpreter.StringStack.IsEmpty;
363    }
364
365    public override void Eval(IInternalPushInterpreter interpreter) {
366      var str = interpreter.StringStack.Pop();
367      interpreter.IntegerStack.Push(str.Length);
368    }
369  }
370
371  /// <summary>
372  /// Reverses the top STRING.
373  /// </summary>
374  [StorableClass]
375  [PushExpression(
376    StackTypes.String,
377    "STRING.REVERSE",
378    "Reverses the top STRING.")]
379  public class StringReverseExpression : StatelessExpression {
380    public StringReverseExpression() { }
381    [StorableConstructor]
382    protected StringReverseExpression(bool deserializing) : base(deserializing) { }
383
384    public override bool IsNoop(IInternalPushInterpreter interpreter) {
385      return interpreter.StringStack.IsEmpty || interpreter.StringStack.Top.Length <= 1;
386    }
387
388    public override void Eval(IInternalPushInterpreter interpreter) {
389      var chars = interpreter.StringStack.Top.ToArray();
390      Array.Reverse(chars);
391      interpreter.StringStack.Top = new string(chars);
392    }
393  }
394
395  /// <summary>
396  /// Maps every char of top STRING as separate string.
397  /// </summary>
398  [StorableClass]
399  [PushExpression(
400    StackTypes.String,
401    "STRING.PARSETOCHARS",
402    "Maps every char of top STRING as separate string.")]
403  public class StringParseToCharsExpression : StatelessExpression {
404    public StringParseToCharsExpression() { }
405    [StorableConstructor]
406    protected StringParseToCharsExpression(bool deserializing) : base(deserializing) { }
407
408    public override bool IsNoop(IInternalPushInterpreter interpreter) {
409      return interpreter.StringStack.IsEmpty;
410    }
411
412    public override void Eval(IInternalPushInterpreter interpreter) {
413      if (interpreter.StringStack.Top.Length == 0) {
414        interpreter.StringStack.Pop();
415        return;
416      }
417
418      var str = interpreter.StringStack.Top;
419      interpreter.StringStack.Top = str[0].ToString();
420
421      if (str.Length > 1) {
422        var chars = new string[str.Length - 1];
423        for (var i = 0; i < str.Length - 1; i++) {
424          chars[i] = str[i + 1].ToString();
425        }
426
427        interpreter.StringStack.Push(chars);
428      }
429    }
430  }
431
432  /// <summary>
433  /// Splits top STRING by whitespace chars.
434  /// </summary>
435  [StorableClass]
436  [PushExpression(
437    StackTypes.String,
438    "STRING.SPLIT",
439    "Splits top STRING by whitespace chars.")]
440  public class StringSplitExpression : StatelessExpression {
441    public StringSplitExpression() { }
442    [StorableConstructor]
443    protected StringSplitExpression(bool deserializing) : base(deserializing) { }
444
445    public override bool IsNoop(IInternalPushInterpreter interpreter) {
446      return interpreter.StringStack.IsEmpty;
447    }
448
449    public override void Eval(IInternalPushInterpreter interpreter) {
450      var words = interpreter.StringStack.Top
451        .Trim()
452        .Split()
453        .Where(x => !string.IsNullOrWhiteSpace(x))
454        .Reverse()
455        .ToList();
456
457      if (words.Count == 0) {
458        interpreter.StringStack.Pop();
459      } else {
460        interpreter.StringStack.Top = words[0];
461        interpreter.StringStack.Push(words, 1);
462      }
463    }
464  }
465
466  /// <summary>
467  /// True if top string is empty.
468  /// </summary>
469  [StorableClass]
470  [PushExpression(
471    StackTypes.String,
472    "STRING.EMPTYSTRING",
473    "True if top STRING is empty.",
474    StackTypes.Boolean)]
475  public class StringEmptyStringExpression : StatelessExpression {
476    public StringEmptyStringExpression() { }
477    [StorableConstructor]
478    protected StringEmptyStringExpression(bool deserializing) : base(deserializing) { }
479
480    public override bool IsNoop(IInternalPushInterpreter interpreter) {
481      return interpreter.StringStack.IsEmpty;
482    }
483
484    public override void Eval(IInternalPushInterpreter interpreter) {
485      var str = interpreter.StringStack.Pop();
486      interpreter.BooleanStack.Push(str.Length == 0);
487    }
488  }
489
490  /// <summary>
491  /// True if top string is a substring of second string; false otherwise
492  /// </summary>
493  [StorableClass]
494  [PushExpression(
495    StackTypes.String,
496    "STRING.CONTAINS",
497    "True if top STRING is a substring of second STRING, false otherwise.",
498    StackTypes.Boolean)]
499  public class StringContainsExpression : StatelessExpression {
500    public StringContainsExpression() { }
501    [StorableConstructor]
502    protected StringContainsExpression(bool deserializing) : base(deserializing) { }
503
504    public override bool IsNoop(IInternalPushInterpreter interpreter) {
505      return interpreter.StringStack.Count < 2;
506    }
507
508    public override void Eval(IInternalPushInterpreter interpreter) {
509      var first = interpreter.StringStack[1];
510      var second = interpreter.StringStack.Top;
511      interpreter.StringStack.Remove(2);
512
513      interpreter.BooleanStack.Push(first.IndexOf(second, StringComparison.Ordinal) >= 0);
514    }
515  }
516
517  /// <summary>
518  /// True if the top char is in the top string
519  /// </summary>
520  [StorableClass]
521  [PushExpression(
522    StackTypes.String,
523    "STRING.CONTAINSCHAR",
524    "True if the top CHAR is in the top STRING.",
525    StackTypes.Boolean | StackTypes.Char)]
526  public class StringContainsCharExpression : StatelessExpression {
527    public StringContainsCharExpression() { }
528    [StorableConstructor]
529    protected StringContainsCharExpression(bool deserializing) : base(deserializing) { }
530
531    public override bool IsNoop(IInternalPushInterpreter interpreter) {
532      return interpreter.StringStack.IsEmpty ||
533             interpreter.CharStack.IsEmpty;
534    }
535
536    public override void Eval(IInternalPushInterpreter interpreter) {
537      var str = interpreter.StringStack.Pop();
538      var c = interpreter.CharStack.Pop();
539
540      interpreter.BooleanStack.Push(str.IndexOf(c) >= 0);
541    }
542  }
543
544  /// <summary>
545  /// Puts on the integer stack the index of the top char in the top string
546  /// </summary>
547  [StorableClass]
548  [PushExpression(
549    StackTypes.String,
550    "STRING.INDEXOFCHAR",
551    "Puts on the INTEGER stack the index of the top CHAR in the top STRING.",
552    StackTypes.Integer | StackTypes.Char)]
553  public class StringIndexOfCharExpression : StatelessExpression {
554    public StringIndexOfCharExpression() { }
555    [StorableConstructor]
556    protected StringIndexOfCharExpression(bool deserializing) : base(deserializing) { }
557
558    public override bool IsNoop(IInternalPushInterpreter interpreter) {
559      return interpreter.StringStack.IsEmpty ||
560             interpreter.CharStack.IsEmpty;
561    }
562
563    public override void Eval(IInternalPushInterpreter interpreter) {
564      var str = interpreter.StringStack.Pop();
565      var c = interpreter.CharStack.Pop();
566
567      interpreter.IntegerStack.Push(str.IndexOf(c));
568    }
569  }
570
571  /// <summary>
572  /// The number of times the top char is in the top string
573  /// </summary>
574  [StorableClass]
575  [PushExpression(
576    StackTypes.String,
577    "STRING.OCCURRENCESOFCHAR",
578    "The number of times the top CHAR is in the top STRING.",
579    StackTypes.Integer | StackTypes.Char)]
580  public class StringOccurrencesOfCharExpression : StatelessExpression {
581    public StringOccurrencesOfCharExpression() { }
582    [StorableConstructor]
583    protected StringOccurrencesOfCharExpression(bool deserializing) : base(deserializing) { }
584
585    public override bool IsNoop(IInternalPushInterpreter interpreter) {
586      return interpreter.StringStack.IsEmpty ||
587             interpreter.CharStack.IsEmpty;
588    }
589
590    public override void Eval(IInternalPushInterpreter interpreter) {
591      var str = interpreter.StringStack.Pop();
592      var c = interpreter.CharStack.Pop();
593
594      var count = 0;
595      for (var i = 0; i < str.Length; i++)
596        if (str[i] == c) count++;
597
598      interpreter.IntegerStack.Push(count);
599    }
600  }
601
602  /// <summary>
603  /// In third STRING, replaces second string with first string
604  /// </summary>
605  [StorableClass]
606  [PushExpression(
607    StackTypes.String,
608    "STRING.REPLACE",
609    "In third STRING, replaces second STRING with first STRING.")]
610  public class StringReplaceExpression : StatelessExpression {
611    public StringReplaceExpression() { }
612    [StorableConstructor]
613    protected StringReplaceExpression(bool deserializing) : base(deserializing) { }
614
615    public override bool IsNoop(IInternalPushInterpreter interpreter) {
616      return interpreter.StringStack.Count < 3;
617    }
618
619    public override void Eval(IInternalPushInterpreter interpreter) {
620      var result = GetResultString(interpreter);
621
622      // Should be checked in isNoop but would require to calculate result twice which is an expensive operation
623      if (result.Length > interpreter.Configuration.MaxStringLength)
624        return;
625
626      interpreter.StringStack.Remove(2);
627      interpreter.StringStack.Top = result;
628    }
629
630    private static string GetResultString(IInternalPushInterpreter interpreter) {
631      var third = interpreter.StringStack[2];
632      var second = interpreter.StringStack[1];
633      var first = interpreter.StringStack[0];
634
635      var result = third.Length == 0 || second.Length == 0
636        ? third
637        : third.Replace(second, first);
638
639      return result;
640    }
641  }
642
643  /// <summary>
644  /// In third STRING, replaces first occurrence of second string with first string
645  /// </summary>
646  [StorableClass]
647  [PushExpression(
648    StackTypes.String,
649    "STRING.REPLACEFIRST",
650    "In third STRING, replaces first occurrence of second STRING with first STRING")]
651  public class StringReplaceFirstExpression : StatelessExpression {
652    public StringReplaceFirstExpression() { }
653    [StorableConstructor]
654    protected StringReplaceFirstExpression(bool deserializing) : base(deserializing) { }
655
656    public override bool IsNoop(IInternalPushInterpreter interpreter) {
657      return interpreter.StringStack.Count < 3;
658    }
659
660    public override void Eval(IInternalPushInterpreter interpreter) {
661      var result = GetResultString(interpreter);
662
663      // Should be checked in isNoop but would require to calculate result twice which is an expensive operation
664      if (result.Length > interpreter.Configuration.MaxStringLength)
665        return;
666
667      interpreter.StringStack.Remove(2);
668      interpreter.StringStack.Top = result;
669    }
670
671    private static string GetResultString(IInternalPushInterpreter interpreter) {
672      var third = interpreter.StringStack[2];
673      var second = interpreter.StringStack[1];
674      var first = interpreter.StringStack[0];
675
676      var result = third.Length == 0 || second.Length == 0
677        ? third
678        : ReplaceFirst(third, second, first);
679      return result;
680    }
681
682    private static string ReplaceFirst(string text, string search, string replace) {
683      var pos = text.IndexOf(search, StringComparison.Ordinal);
684      return pos < 0 ? text : text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
685    }
686  }
687
688  /// <summary>
689  /// In top STRING, replaces all occurrences of second char with first char
690  /// </summary>
691  [StorableClass]
692  [PushExpression(
693    StackTypes.String,
694    "STRING.REPLACECHAR",
695    "In top STRING, replaces all occurrences of second CHAR with first CHAR.",
696    StackTypes.Char)]
697  public class StringReplaceCharExpression : StatelessExpression {
698    public StringReplaceCharExpression() { }
699    [StorableConstructor]
700    protected StringReplaceCharExpression(bool deserializing) : base(deserializing) { }
701
702    public override bool IsNoop(IInternalPushInterpreter interpreter) {
703      return interpreter.StringStack.IsEmpty ||
704             interpreter.CharStack.Count < 2;
705    }
706
707    public override void Eval(IInternalPushInterpreter interpreter) {
708      var first = interpreter.CharStack[1];
709      var second = interpreter.CharStack.Top;
710      interpreter.CharStack.Remove(2);
711
712      var result = interpreter.StringStack.Top.Replace(first, second);
713      interpreter.StringStack.Top = result;
714    }
715  }
716
717  /// <summary>
718  /// In top STRING, replaces first occurrence of second char with first char
719  /// </summary>
720  [StorableClass]
721  [PushExpression(
722    StackTypes.String,
723    "STRING.REPLACEFIRSTCHAR",
724    "In top STRING, replaces first occurrence of second CHAR with first CHAR.",
725    StackTypes.Char)]
726  public class StringReplaceFirstCharExpression : StatelessExpression {
727    public StringReplaceFirstCharExpression() { }
728    [StorableConstructor]
729    protected StringReplaceFirstCharExpression(bool deserializing) : base(deserializing) { }
730
731    public override bool IsNoop(IInternalPushInterpreter interpreter) {
732      return interpreter.StringStack.IsEmpty ||
733             interpreter.CharStack.Count < 2;
734    }
735
736    public override void Eval(IInternalPushInterpreter interpreter) {
737      var str = interpreter.StringStack.Top;
738      var first = interpreter.CharStack[1];
739      var second = interpreter.CharStack.Top;
740      interpreter.CharStack.Remove(2);
741
742      var pos = str.IndexOf(first);
743
744      if (pos < 0)
745        return;
746
747      var result = str.Substring(0, pos) +
748                   second +
749                   str.Substring(Math.Min(pos + 1, str.Length - 1));
750
751      interpreter.StringStack.Top = result;
752    }
753  }
754
755  /// <summary>
756  /// In top STRING, remove all occurrences of char
757  /// </summary>
758  [StorableClass]
759  [PushExpression(
760    StackTypes.String,
761    "STRING.REMOVECHAR",
762    "In top STRING, remove all occurrences of top CHAR.",
763    StackTypes.Char)]
764  public class StringRemoveCharExpression : StatelessExpression {
765    public StringRemoveCharExpression() { }
766    [StorableConstructor]
767    protected StringRemoveCharExpression(bool deserializing) : base(deserializing) { }
768
769    public override bool IsNoop(IInternalPushInterpreter interpreter) {
770      return interpreter.StringStack.IsEmpty ||
771             interpreter.CharStack.IsEmpty;
772    }
773
774    public override void Eval(IInternalPushInterpreter interpreter) {
775      var c = interpreter.CharStack.Pop();
776      var result = interpreter.StringStack.Top.Trim(c);
777      interpreter.StringStack.Top = result;
778    }
779  }
780
781  /// <summary>
782  /// Sets char at index in string
783  /// </summary>
784  [StorableClass]
785  [PushExpression(
786    StackTypes.String,
787    "STRING.SETCHAR",
788    "Sets top CHAR at index in top STRING, whereby the index is taken from the INTEGER stack.",
789    StackTypes.Char | StackTypes.Integer)]
790  public class StringSetCharExpression : StatelessExpression {
791    public StringSetCharExpression() { }
792    [StorableConstructor]
793    protected StringSetCharExpression(bool deserializing) : base(deserializing) { }
794
795    public override bool IsNoop(IInternalPushInterpreter interpreter) {
796      return interpreter.StringStack.IsEmpty ||
797             interpreter.CharStack.IsEmpty ||
798             interpreter.IntegerStack.IsEmpty;
799    }
800
801    public override void Eval(IInternalPushInterpreter interpreter) {
802      var str = interpreter.StringStack.Top;
803      var c = interpreter.CharStack.Pop();
804      var x = interpreter.IntegerStack.Pop();
805
806      if (str.Length == 0) return;
807      if (str.Length == 1) {
808        interpreter.StringStack.Top = c.ToString();
809        return;
810      }
811
812      var pos = x.AsInt(str.Length);
813      var result = str.Substring(0, pos) + c + str.Substring(Math.Min(pos + 1, str.Length - 1));
814
815      interpreter.StringStack.Top = result;
816    }
817  }
818
819  /// <summary>
820  /// Iterates over a string using the code on the exec stack.
821  /// </summary>
822  [StorableClass]
823  [PushExpression(
824    StackTypes.String,
825    "STRING.ITERATE",
826    "Iterates over the top STRING using the CODE on the EXEC stack.",
827    StackTypes.Exec | StackTypes.Char, requiredBlockCount: 1)]
828  public class StringIterateExpression : StatelessExpression {
829    public StringIterateExpression() { }
830    [StorableConstructor]
831    protected StringIterateExpression(bool deserializing) : base(deserializing) { }
832
833    public override bool IsNoop(IInternalPushInterpreter interpreter) {
834      return interpreter.StringStack.IsEmpty ||
835             interpreter.ExecStack.IsEmpty;
836    }
837
838    public override void Eval(IInternalPushInterpreter interpreter) {
839      var str = interpreter.StringStack.Pop();
840
841      if (str.Length == 0) {
842        interpreter.ExecStack.Pop();
843      }
844      // If the rest of the string is empty, we're done iterating.
845      else if (str.Length == 1) {
846        interpreter.CharStack.Push(str[0]);
847      } else {
848        var pool = interpreter.PoolContainer.GetStatefulExpressionPool<StringPushExpression>();
849
850        interpreter.CharStack.Push(str[0]);
851        interpreter.ExecStack.Push(
852          this,
853          StringPushExpression.Create(pool, str.Substring(1)),
854          interpreter.ExecStack.Top);
855      }
856    }
857  }
858}
Note: See TracBrowser for help on using the repository browser.