Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2895_PushGP_GenealogyAnalysis/HeuristicLab.Problems.ProgramSynthesis/Push/Expressions/StringExpressions.cs @ 17189

Last change on this file since 17189 was 15771, checked in by bburlacu, 7 years ago

#2895: Add solution skeleton for PushGP with genealogy analysis.

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