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
RevLine 
[15771]1using System;
2using System.Globalization;
3using System.Linq;
4using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
5
6namespace HeuristicLab.Problems.ProgramSynthesis {
[15032]7  /// <summary>
8  /// Stringifies and pushes the top INTEGER.,
9  /// </summary>
[14952]10  [StorableClass]
[15032]11  [PushExpression(
12    StackTypes.String,
13    "STRING.FROMINTEGER",
14    "Stringifies and pushes the top INTEGER.",
15    StackTypes.Integer)]
[14777]16  public class StringFromIntegerExpression : StatelessExpression {
[14952]17    public StringFromIntegerExpression() { }
18    [StorableConstructor]
19    protected StringFromIntegerExpression(bool deserializing) : base(deserializing) { }
[14777]20
[14952]21    public override bool IsNoop(IInternalPushInterpreter interpreter) {
22      return interpreter.IntegerStack.IsEmpty;
23    }
24
25    public override void Eval(IInternalPushInterpreter interpreter) {
[14777]26      var value = interpreter.IntegerStack.Pop();
27      interpreter.StringStack.Push(value.ToString());
28    }
29  }
30
[14952]31  [StorableClass]
[15032]32  [PushExpression(
33    StackTypes.String,
34    "STRING.FROMFLOAT",
35    "Stringifies and pushes the top FLOAT.",
36    StackTypes.Float)]
[14777]37  public class StringFromFloatExpression : StatelessExpression {
[14952]38    public StringFromFloatExpression() { }
39    [StorableConstructor]
40    protected StringFromFloatExpression(bool deserializing) : base(deserializing) { }
[14777]41
[14952]42    public override bool IsNoop(IInternalPushInterpreter interpreter) {
43      return interpreter.FloatStack.IsEmpty;
44    }
45
46    public override void Eval(IInternalPushInterpreter interpreter) {
[14777]47      var value = interpreter.FloatStack.Pop();
[15017]48      var str = value.ToString(interpreter.Configuration.FloatStringFormat, CultureInfo.InvariantCulture);
49
50      interpreter.StringStack.Push(str);
[14777]51    }
52  }
53
[15032]54  /// <summary>
55  /// Stringifies and pushes the top BOOLEAN.
56  /// </summary>
[14952]57  [StorableClass]
[15032]58  [PushExpression(
59    StackTypes.String,
60    "STRING.FROMBOOLEAN",
61    "Stringifies and pushes the top BOOLEAN.",
62    StackTypes.Boolean)]
[14777]63  public class StringFromBooleanExpression : StatelessExpression {
[14952]64    public StringFromBooleanExpression() { }
65    [StorableConstructor]
66    protected StringFromBooleanExpression(bool deserializing) : base(deserializing) { }
[14777]67
[14952]68    public override bool IsNoop(IInternalPushInterpreter interpreter) {
69      return interpreter.BooleanStack.IsEmpty;
70    }
71
72    public override void Eval(IInternalPushInterpreter interpreter) {
[14777]73      var value = interpreter.BooleanStack.Pop();
74      interpreter.StringStack.Push(value.ToString());
75    }
76  }
77
[15032]78  /// <summary>
79  /// Stringifies and pushes the top CHAR.
80  /// </summary>
[14952]81  [StorableClass]
[15032]82  [PushExpression(
83    StackTypes.String,
84    "STRING.FROMCHAR",
85    "Stringifies and pushes the top CHAR.",
86    StackTypes.Char)]
[14777]87  public class StringFromCharExpression : StatelessExpression {
[14952]88    public StringFromCharExpression() { }
89    [StorableConstructor]
90    protected StringFromCharExpression(bool deserializing) : base(deserializing) { }
[14777]91
[14952]92    public override bool IsNoop(IInternalPushInterpreter interpreter) {
93      return interpreter.CharStack.IsEmpty;
94    }
95
96    public override void Eval(IInternalPushInterpreter interpreter) {
[14777]97      var value = interpreter.CharStack.Pop();
98      interpreter.StringStack.Push(value.ToString());
99    }
100  }
101
[15032]102  /// <summary>
103  /// Concats the top 2 strings.
104  /// </summary>
[14952]105  [StorableClass]
[15032]106  [PushExpression(
107    StackTypes.String,
108    "STRING.CONCAT",
109    "Concats the top 2 strings.")]
[14777]110  public class StringConcatExpression : StatelessExpression {
[14952]111    public StringConcatExpression() { }
112    [StorableConstructor]
113    protected StringConcatExpression(bool deserializing) : base(deserializing) { }
[14777]114
[14952]115    public override bool IsNoop(IInternalPushInterpreter interpreter) {
116      return interpreter.StringStack.Count < 2 ||
[15334]117             interpreter.StringStack.Top.Length + interpreter.StringStack[1].Length > interpreter.Configuration.MaxStringLength;
[14952]118    }
119
120    public override void Eval(IInternalPushInterpreter interpreter) {
[14777]121      var str = interpreter.StringStack.Pop();
[15017]122      interpreter.StringStack.Top += str;
[14777]123    }
124  }
125
126  /// <summary>
127  /// Conj char onto string
128  /// </summary>
[14952]129  [StorableClass]
[15032]130  [PushExpression(
131    StackTypes.String,
132    "STRING.CONJCHAR",
133    "Conj top CHAR onto top STRING",
134    StackTypes.Char)]
[14777]135  public class StringConjCharExpression : StatelessExpression {
[14952]136    public StringConjCharExpression() { }
137    [StorableConstructor]
138    protected StringConjCharExpression(bool deserializing) : base(deserializing) { }
[14777]139
[14952]140    public override bool IsNoop(IInternalPushInterpreter interpreter) {
141      return interpreter.StringStack.IsEmpty ||
142             interpreter.CharStack.IsEmpty ||
[15334]143             interpreter.StringStack.Top.Length + 1 > interpreter.Configuration.MaxStringLength;
[14952]144    }
145
146    public override void Eval(IInternalPushInterpreter interpreter) {
[14777]147      var c = interpreter.CharStack.Pop();
[15017]148      interpreter.StringStack.Top += c;
[14777]149    }
150  }
151
[15032]152  /// <summary>
153  /// Same as substring 0-n, whereby n is taken from the INTEGER stack.
154  /// </summary>
[14952]155  [StorableClass]
[15032]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)]
[14777]161  public class StringTakeExpression : StatelessExpression {
[14952]162    public StringTakeExpression() { }
163    [StorableConstructor]
164    protected StringTakeExpression(bool deserializing) : base(deserializing) { }
[14777]165
[14952]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) {
[14777]172      var str = interpreter.StringStack.Top;
173
[14952]174      if (str.Length == 0)
175        return;
[14777]176
[15017]177      var endIndex = interpreter.IntegerStack.Pop().AsInt(str.Length);
178      interpreter.StringStack.Top = str.Substring(0, endIndex);
[14777]179    }
180  }
181
[15032]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>
[14952]185  [StorableClass]
[15032]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)]
[14777]191  public class StringSubstringExpression : StatelessExpression {
[14952]192    public StringSubstringExpression() { }
193    [StorableConstructor]
194    protected StringSubstringExpression(bool deserializing) : base(deserializing) { }
[14777]195
[14952]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) {
[14777]202      var str = interpreter.StringStack.Top;
[14875]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));
[14777]209      var length = second - first;
210
211      if (length > 0)
[15017]212        interpreter.StringStack.Top = str.Substring((int)first, (int)length);
[14777]213    }
214  }
215
[15032]216  /// <summary>
217  /// Pushes first char of top STRING.
218  /// </summary>
[14952]219  [StorableClass]
[15032]220  [PushExpression(
221    StackTypes.String,
222    "STRING.FIRST",
223    "Pushes first char of top STRING.")]
[14777]224  public class StringFirstExpression : StatelessExpression {
[14952]225    public StringFirstExpression() { }
226    [StorableConstructor]
227    protected StringFirstExpression(bool deserializing) : base(deserializing) { }
[14777]228
[14952]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) {
[15017]235      interpreter.StringStack.Top = interpreter.StringStack.Top[0].ToString();
[14777]236    }
237  }
238
[15032]239  /// <summary>
240  /// Pushes last char of top STRING.
241  /// </summary>
[14952]242  [StorableClass]
[15032]243  [PushExpression(
244    StackTypes.String,
245    "STRING.LAST",
246    "Pushes last char of top STRING.")]
[14777]247  public class StringLastExpression : StatelessExpression {
[14952]248    public StringLastExpression() { }
249    [StorableConstructor]
250    protected StringLastExpression(bool deserializing) : base(deserializing) { }
[14777]251
[14952]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) {
[14777]258      var str = interpreter.StringStack.Top;
259      var c = str[str.Length - 1].ToString();
[15017]260      interpreter.StringStack.Top = c;
[14777]261    }
262  }
263
[15032]264  /// <summary>
265  /// Pushes nth char of top STRING, whereby n is take from the INTEGER stack.
266  /// </summary>
[14952]267  [StorableClass]
[15032]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)]
[14777]273  public class StringNthExpression : StatelessExpression {
[14952]274    public StringNthExpression() { }
275    [StorableConstructor]
276    protected StringNthExpression(bool deserializing) : base(deserializing) { }
[14777]277
[14952]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) {
[14777]285      var str = interpreter.StringStack.Top;
[15017]286      var index = str.Length == 1 ? 0 : interpreter.IntegerStack.Pop().AsInt(str.Length);
[14777]287      var c = str[index].ToString();
[15017]288      interpreter.StringStack.Top = c;
[14777]289    }
290  }
291
[15032]292  /// <summary>
293  /// Removes first char of top STRING.
294  /// </summary>
[14952]295  [StorableClass]
[15032]296  [PushExpression(
297    StackTypes.String,
298    "STRING.REST",
299    "Removes first char of top STRING.")]
[14777]300  public class StringRestExpression : StatelessExpression {
[14952]301    public StringRestExpression() { }
302    [StorableConstructor]
303    protected StringRestExpression(bool deserializing) : base(deserializing) { }
[14777]304
[14952]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) {
[14777]311      var str = interpreter.StringStack.Top;
[15017]312      interpreter.StringStack.Top = str.Length == 1 ? string.Empty : str.Substring(1, str.Length - 1);
[14777]313    }
314  }
315
[15032]316  /// <summary>
317  /// Removes last char of top STRING.
318  /// </summary>
[14952]319  [StorableClass]
[15032]320  [PushExpression(
321    StackTypes.String,
322    "STRING.BUTLAST",
323    "Removes last char of top STRING.")]
[14777]324  public class StringButLastExpression : StatelessExpression {
[14952]325    public StringButLastExpression() { }
326    [StorableConstructor]
327    protected StringButLastExpression(bool deserializing) : base(deserializing) { }
[14777]328
[14952]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) {
[14777]335      var str = interpreter.StringStack.Top;
[15017]336      interpreter.StringStack.Top = str.Length == 1 ? string.Empty : str.Substring(0, str.Length - 1);
[14777]337    }
338  }
339
[15032]340  /// <summary>
341  /// Pushes length of top STRING onto the INTEGER stack.
342  /// </summary>
[14952]343  [StorableClass]
[15032]344  [PushExpression(
345    StackTypes.String,
346    "STRING.LENGTH",
347    "Pushes length of top STRING onto the INTEGER stack.",
348    StackTypes.Integer)]
[14777]349  public class StringLengthExpression : StatelessExpression {
[14952]350    public StringLengthExpression() { }
351    [StorableConstructor]
352    protected StringLengthExpression(bool deserializing) : base(deserializing) { }
[14777]353
[14952]354    public override bool IsNoop(IInternalPushInterpreter interpreter) {
355      return interpreter.StringStack.IsEmpty;
356    }
357
358    public override void Eval(IInternalPushInterpreter interpreter) {
[14777]359      var str = interpreter.StringStack.Pop();
360      interpreter.IntegerStack.Push(str.Length);
361    }
362  }
363
[15032]364  /// <summary>
365  /// Reverses the top STRING.
366  /// </summary>
[14952]367  [StorableClass]
[15032]368  [PushExpression(
369    StackTypes.String,
370    "STRING.REVERSE",
371    "Reverses the top STRING.")]
[14777]372  public class StringReverseExpression : StatelessExpression {
[14952]373    public StringReverseExpression() { }
374    [StorableConstructor]
375    protected StringReverseExpression(bool deserializing) : base(deserializing) { }
[14777]376
[14952]377    public override bool IsNoop(IInternalPushInterpreter interpreter) {
[15017]378      return interpreter.StringStack.IsEmpty || interpreter.StringStack.Top.Length <= 1;
[14952]379    }
380
381    public override void Eval(IInternalPushInterpreter interpreter) {
[15017]382      var chars = interpreter.StringStack.Top.ToArray();
383      Array.Reverse(chars);
384      interpreter.StringStack.Top = new string(chars);
[14777]385    }
386  }
387
[15032]388  /// <summary>
389  /// Maps every char of top STRING as separate string.
390  /// </summary>
[14952]391  [StorableClass]
[15032]392  [PushExpression(
393    StackTypes.String,
394    "STRING.PARSETOCHARS",
395    "Maps every char of top STRING as separate string.")]
[14777]396  public class StringParseToCharsExpression : StatelessExpression {
[14952]397    public StringParseToCharsExpression() { }
398    [StorableConstructor]
399    protected StringParseToCharsExpression(bool deserializing) : base(deserializing) { }
[14777]400
[14952]401    public override bool IsNoop(IInternalPushInterpreter interpreter) {
402      return interpreter.StringStack.IsEmpty;
403    }
404
405    public override void Eval(IInternalPushInterpreter interpreter) {
[14777]406      if (interpreter.StringStack.Top.Length == 0) {
407        interpreter.StringStack.Pop();
[14952]408        return;
[14777]409      }
410
411      var str = interpreter.StringStack.Top;
[15017]412      interpreter.StringStack.Top = str[0].ToString();
[14777]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
[15032]425  /// <summary>
426  /// Splits top STRING by whitespace chars.
427  /// </summary>
[14952]428  [StorableClass]
[15032]429  [PushExpression(
430    StackTypes.String,
431    "STRING.SPLIT",
432    "Splits top STRING by whitespace chars.")]
[14777]433  public class StringSplitExpression : StatelessExpression {
[14952]434    public StringSplitExpression() { }
435    [StorableConstructor]
436    protected StringSplitExpression(bool deserializing) : base(deserializing) { }
[14777]437
[14952]438    public override bool IsNoop(IInternalPushInterpreter interpreter) {
[15017]439      return interpreter.StringStack.IsEmpty;
[14952]440    }
441
442    public override void Eval(IInternalPushInterpreter interpreter) {
[15017]443      var words = interpreter.StringStack.Top
444        .Trim()
445        .Split()
446        .Where(x => !string.IsNullOrWhiteSpace(x))
447        .Reverse()
[15189]448        .ToList();
[14777]449
[15189]450      if (words.Count == 0) {
[15017]451        interpreter.StringStack.Pop();
452      } else {
453        interpreter.StringStack.Top = words[0];
454        interpreter.StringStack.Push(words, 1);
455      }
[14777]456    }
457  }
458
459  /// <summary>
[15032]460  /// True if top string is empty.
[14777]461  /// </summary>
[14952]462  [StorableClass]
[15032]463  [PushExpression(
464    StackTypes.String,
465    "STRING.EMPTYSTRING",
466    "True if top STRING is empty.",
467    StackTypes.Boolean)]
[14777]468  public class StringEmptyStringExpression : StatelessExpression {
[14952]469    public StringEmptyStringExpression() { }
470    [StorableConstructor]
471    protected StringEmptyStringExpression(bool deserializing) : base(deserializing) { }
[14777]472
[14952]473    public override bool IsNoop(IInternalPushInterpreter interpreter) {
474      return interpreter.StringStack.IsEmpty;
475    }
476
477    public override void Eval(IInternalPushInterpreter interpreter) {
[14777]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>
[14952]486  [StorableClass]
[15032]487  [PushExpression(
488    StackTypes.String,
489    "STRING.CONTAINS",
490    "True if top STRING is a substring of second STRING, false otherwise.",
491    StackTypes.Boolean)]
[14777]492  public class StringContainsExpression : StatelessExpression {
[14952]493    public StringContainsExpression() { }
494    [StorableConstructor]
495    protected StringContainsExpression(bool deserializing) : base(deserializing) { }
[14777]496
[14952]497    public override bool IsNoop(IInternalPushInterpreter interpreter) {
498      return interpreter.StringStack.Count < 2;
499    }
500
501    public override void Eval(IInternalPushInterpreter interpreter) {
[14875]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);
[14777]507    }
508  }
509
510  /// <summary>
511  /// True if the top char is in the top string
512  /// </summary>
[14952]513  [StorableClass]
[15032]514  [PushExpression(
515    StackTypes.String,
516    "STRING.CONTAINSCHAR",
517    "True if the top CHAR is in the top STRING.",
518    StackTypes.Boolean | StackTypes.Char)]
[14777]519  public class StringContainsCharExpression : StatelessExpression {
[14952]520    public StringContainsCharExpression() { }
521    [StorableConstructor]
522    protected StringContainsCharExpression(bool deserializing) : base(deserializing) { }
[14777]523
[14952]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) {
[14777]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>
[14952]540  [StorableClass]
[15032]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)]
[14777]546  public class StringIndexOfCharExpression : StatelessExpression {
[14952]547    public StringIndexOfCharExpression() { }
548    [StorableConstructor]
549    protected StringIndexOfCharExpression(bool deserializing) : base(deserializing) { }
[14777]550
[14952]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) {
[14777]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>
[14952]567  [StorableClass]
[15032]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)]
[14777]573  public class StringOccurrencesOfCharExpression : StatelessExpression {
[14952]574    public StringOccurrencesOfCharExpression() { }
575    [StorableConstructor]
576    protected StringOccurrencesOfCharExpression(bool deserializing) : base(deserializing) { }
[14777]577
[14952]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) {
[14777]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>
[15032]596  /// In third STRING, replaces second string with first string
[14777]597  /// </summary>
[14952]598  [StorableClass]
[15032]599  [PushExpression(
600    StackTypes.String,
601    "STRING.REPLACE",
602    "In third STRING, replaces second STRING with first STRING.")]
[14777]603  public class StringReplaceExpression : StatelessExpression {
[14952]604    public StringReplaceExpression() { }
605    [StorableConstructor]
606    protected StringReplaceExpression(bool deserializing) : base(deserializing) { }
[14777]607
[14952]608    public override bool IsNoop(IInternalPushInterpreter interpreter) {
609      return interpreter.StringStack.Count < 3;
610    }
611
612    public override void Eval(IInternalPushInterpreter interpreter) {
[15334]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) {
[15017]624      var third = interpreter.StringStack[2];
625      var second = interpreter.StringStack[1];
626      var first = interpreter.StringStack[0];
[14777]627
[15334]628      var result = third.Length == 0 || second.Length == 0
[15017]629        ? third
630        : third.Replace(second, first);
[15334]631
632      return result;
[14777]633    }
634  }
635
636  /// <summary>
[15032]637  /// In third STRING, replaces first occurrence of second string with first string
[14777]638  /// </summary>
[14952]639  [StorableClass]
[15032]640  [PushExpression(
641    StackTypes.String,
642    "STRING.REPLACEFIRST",
643    "In third STRING, replaces first occurrence of second STRING with first STRING")]
[15017]644  public class StringReplaceFirstExpression : StatelessExpression {
645    public StringReplaceFirstExpression() { }
[14952]646    [StorableConstructor]
[15017]647    protected StringReplaceFirstExpression(bool deserializing) : base(deserializing) { }
[14777]648
[14952]649    public override bool IsNoop(IInternalPushInterpreter interpreter) {
650      return interpreter.StringStack.Count < 3;
651    }
652
653    public override void Eval(IInternalPushInterpreter interpreter) {
[15334]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) {
[15017]665      var third = interpreter.StringStack[2];
666      var second = interpreter.StringStack[1];
[14875]667      var first = interpreter.StringStack[0];
[14777]668
[15334]669      var result = third.Length == 0 || second.Length == 0
[15017]670        ? third
671        : ReplaceFirst(third, second, first);
[15334]672      return result;
[14777]673    }
[14875]674
675    private static string ReplaceFirst(string text, string search, string replace) {
[15017]676      var pos = text.IndexOf(search, StringComparison.Ordinal);
677      return pos < 0 ? text : text.Substring(0, pos) + replace + text.Substring(pos + search.Length);
[14875]678    }
[14777]679  }
680
681  /// <summary>
[15032]682  /// In top STRING, replaces all occurrences of second char with first char
[14777]683  /// </summary>
[14952]684  [StorableClass]
[15032]685  [PushExpression(
686    StackTypes.String,
687    "STRING.REPLACECHAR",
688    "In top STRING, replaces all occurrences of second CHAR with first CHAR.",
689    StackTypes.Char)]
[14777]690  public class StringReplaceCharExpression : StatelessExpression {
[14952]691    public StringReplaceCharExpression() { }
692    [StorableConstructor]
693    protected StringReplaceCharExpression(bool deserializing) : base(deserializing) { }
[14777]694
[14952]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) {
[14875]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);
[15017]706      interpreter.StringStack.Top = result;
[14777]707    }
708  }
709
710  /// <summary>
[15032]711  /// In top STRING, replaces first occurrence of second char with first char
[14777]712  /// </summary>
[14952]713  [StorableClass]
[15032]714  [PushExpression(
715    StackTypes.String,
716    "STRING.REPLACEFIRSTCHAR",
717    "In top STRING, replaces first occurrence of second CHAR with first CHAR.",
718    StackTypes.Char)]
[15017]719  public class StringReplaceFirstCharExpression : StatelessExpression {
720    public StringReplaceFirstCharExpression() { }
[14952]721    [StorableConstructor]
[15017]722    protected StringReplaceFirstCharExpression(bool deserializing) : base(deserializing) { }
[14777]723
[14952]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) {
[14777]730      var str = interpreter.StringStack.Top;
[14875]731      var first = interpreter.CharStack[1];
732      var second = interpreter.CharStack.Top;
733      interpreter.CharStack.Remove(2);
[14777]734
[14875]735      var pos = str.IndexOf(first);
736
[14777]737      if (pos < 0)
[14952]738        return;
[14777]739
740      var result = str.Substring(0, pos) +
[14875]741                   second +
[15017]742                   str.Substring(Math.Min(pos + 1, str.Length - 1));
[14875]743
[15017]744      interpreter.StringStack.Top = result;
[14777]745    }
746  }
747
748  /// <summary>
[15032]749  /// In top STRING, remove all occurrences of char
[14777]750  /// </summary>
[14952]751  [StorableClass]
[15032]752  [PushExpression(
753    StackTypes.String,
754    "STRING.REMOVECHAR",
755    "In top STRING, remove all occurrences of top CHAR.",
756    StackTypes.Char)]
[14777]757  public class StringRemoveCharExpression : StatelessExpression {
[14952]758    public StringRemoveCharExpression() { }
759    [StorableConstructor]
760    protected StringRemoveCharExpression(bool deserializing) : base(deserializing) { }
[14777]761
[14952]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) {
[14777]768      var c = interpreter.CharStack.Pop();
769      var result = interpreter.StringStack.Top.Trim(c);
[15017]770      interpreter.StringStack.Top = result;
[14777]771    }
772  }
773
774  /// <summary>
[15017]775  /// Sets char at index in string
[14777]776  /// </summary>
[14952]777  [StorableClass]
[15032]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)]
[14777]783  public class StringSetCharExpression : StatelessExpression {
[14952]784    public StringSetCharExpression() { }
785    [StorableConstructor]
786    protected StringSetCharExpression(bool deserializing) : base(deserializing) { }
[14777]787
[14952]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) {
[14777]795      var str = interpreter.StringStack.Top;
796      var c = interpreter.CharStack.Pop();
[15017]797      var x = interpreter.IntegerStack.Pop();
[14777]798
[15017]799      if (str.Length == 0) return;
800      if (str.Length == 1) {
801        interpreter.StringStack.Top = c.ToString();
[14952]802        return;
[14777]803      }
804
[15017]805      var pos = x.AsInt(str.Length);
806      var result = str.Substring(0, pos) + c + str.Substring(Math.Min(pos + 1, str.Length - 1));
[14777]807
[15017]808      interpreter.StringStack.Top = result;
[14777]809    }
810  }
[15017]811
812  /// <summary>
813  /// Iterates over a string using the code on the exec stack.
814  /// </summary>
815  [StorableClass]
[15032]816  [PushExpression(
817    StackTypes.String,
818    "STRING.ITERATE",
819    "Iterates over the top STRING using the CODE on the EXEC stack.",
[15334]820    StackTypes.Exec | StackTypes.Char, requiredBlockCount: 1)]
[15017]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  }
[14777]851}
Note: See TracBrowser for help on using the repository browser.