namespace HeuristicLab.Problems.ProgramSynthesis.Push.Expressions { using System; using System.Globalization; using System.Linq; using Attributes; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Problems.ProgramSynthesis.Push.Extensions; using Interpreter; using Stack; /// /// Stringifies and pushes the top INTEGER., /// [StorableClass] [PushExpression( StackTypes.String, "STRING.FROMINTEGER", "Stringifies and pushes the top INTEGER.", StackTypes.Integer)] public class StringFromIntegerExpression : StatelessExpression { public StringFromIntegerExpression() { } [StorableConstructor] protected StringFromIntegerExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.IntegerStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var value = interpreter.IntegerStack.Pop(); interpreter.StringStack.Push(value.ToString()); } } [StorableClass] [PushExpression( StackTypes.String, "STRING.FROMFLOAT", "Stringifies and pushes the top FLOAT.", StackTypes.Float)] public class StringFromFloatExpression : StatelessExpression { public StringFromFloatExpression() { } [StorableConstructor] protected StringFromFloatExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.FloatStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var value = interpreter.FloatStack.Pop(); var str = value.ToString(interpreter.Configuration.FloatStringFormat, CultureInfo.InvariantCulture); interpreter.StringStack.Push(str); } } /// /// Stringifies and pushes the top BOOLEAN. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.FROMBOOLEAN", "Stringifies and pushes the top BOOLEAN.", StackTypes.Boolean)] public class StringFromBooleanExpression : StatelessExpression { public StringFromBooleanExpression() { } [StorableConstructor] protected StringFromBooleanExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.BooleanStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var value = interpreter.BooleanStack.Pop(); interpreter.StringStack.Push(value.ToString()); } } /// /// Stringifies and pushes the top CHAR. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.FROMCHAR", "Stringifies and pushes the top CHAR.", StackTypes.Char)] public class StringFromCharExpression : StatelessExpression { public StringFromCharExpression() { } [StorableConstructor] protected StringFromCharExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.CharStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var value = interpreter.CharStack.Pop(); interpreter.StringStack.Push(value.ToString()); } } /// /// Concats the top 2 strings. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.CONCAT", "Concats the top 2 strings.")] public class StringConcatExpression : StatelessExpression { public StringConcatExpression() { } [StorableConstructor] protected StringConcatExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.Count < 2 || interpreter.StringStack.Top.Length + interpreter.StringStack[1].Length > interpreter.Configuration.MaxStringLength; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Pop(); interpreter.StringStack.Top += str; } } /// /// Conj char onto string /// [StorableClass] [PushExpression( StackTypes.String, "STRING.CONJCHAR", "Conj top CHAR onto top STRING", StackTypes.Char)] public class StringConjCharExpression : StatelessExpression { public StringConjCharExpression() { } [StorableConstructor] protected StringConjCharExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.CharStack.IsEmpty || interpreter.StringStack.Top.Length + 1 > interpreter.Configuration.MaxStringLength; } public override void Eval(IInternalPushInterpreter interpreter) { var c = interpreter.CharStack.Pop(); interpreter.StringStack.Top += c; } } /// /// Same as substring 0-n, whereby n is taken from the INTEGER stack. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.TAKE", "Same as substring 0-n, whereby n is taken from the INTEGER stack.", StackTypes.Integer)] public class StringTakeExpression : StatelessExpression { public StringTakeExpression() { } [StorableConstructor] protected StringTakeExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.IntegerStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Top; if (str.Length == 0) return; var endIndex = interpreter.IntegerStack.Pop().AsInt(str.Length); interpreter.StringStack.Top = str.Substring(0, endIndex); } } /// /// Replaces top STRING with a substring from index A to B, whereby A and B are taken from the INTEGER STACK. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.SUBSTRING", "Replaces top STRING with a substring from index A to B, whereby A and B are taken from the INTEGER STACK.", StackTypes.Integer)] public class StringSubstringExpression : StatelessExpression { public StringSubstringExpression() { } [StorableConstructor] protected StringSubstringExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.IntegerStack.Count < 2; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Top; var firstValue = interpreter.IntegerStack[1]; var secondValue = interpreter.IntegerStack.Top; interpreter.IntegerStack.Remove(2); var first = Math.Min(str.Length - 1, Math.Max(firstValue, 0)); var second = Math.Min(str.Length - 1, Math.Max(secondValue, first)); var length = second - first; if (length > 0) interpreter.StringStack.Top = str.Substring((int)first, (int)length); } } /// /// Pushes first char of top STRING. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.FIRST", "Pushes first char of top STRING.")] public class StringFirstExpression : StatelessExpression { public StringFirstExpression() { } [StorableConstructor] protected StringFirstExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.StringStack.Top.Length == 0; } public override void Eval(IInternalPushInterpreter interpreter) { interpreter.StringStack.Top = interpreter.StringStack.Top[0].ToString(); } } /// /// Pushes last char of top STRING. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.LAST", "Pushes last char of top STRING.")] public class StringLastExpression : StatelessExpression { public StringLastExpression() { } [StorableConstructor] protected StringLastExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.StringStack.Top.Length == 0; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Top; var c = str[str.Length - 1].ToString(); interpreter.StringStack.Top = c; } } /// /// Pushes nth char of top STRING, whereby n is take from the INTEGER stack. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.NTH", "Pushes nth char of top STRING, whereby n is take from the INTEGER stack.", StackTypes.Integer)] public class StringNthExpression : StatelessExpression { public StringNthExpression() { } [StorableConstructor] protected StringNthExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.IntegerStack.IsEmpty || interpreter.StringStack.Top.Length == 0; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Top; var index = str.Length == 1 ? 0 : interpreter.IntegerStack.Pop().AsInt(str.Length); var c = str[index].ToString(); interpreter.StringStack.Top = c; } } /// /// Removes first char of top STRING. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.REST", "Removes first char of top STRING.")] public class StringRestExpression : StatelessExpression { public StringRestExpression() { } [StorableConstructor] protected StringRestExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.StringStack.Top.Length == 0; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Top; interpreter.StringStack.Top = str.Length == 1 ? string.Empty : str.Substring(1, str.Length - 1); } } /// /// Removes last char of top STRING. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.BUTLAST", "Removes last char of top STRING.")] public class StringButLastExpression : StatelessExpression { public StringButLastExpression() { } [StorableConstructor] protected StringButLastExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.StringStack.Top.Length == 0; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Top; interpreter.StringStack.Top = str.Length == 1 ? string.Empty : str.Substring(0, str.Length - 1); } } /// /// Pushes length of top STRING onto the INTEGER stack. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.LENGTH", "Pushes length of top STRING onto the INTEGER stack.", StackTypes.Integer)] public class StringLengthExpression : StatelessExpression { public StringLengthExpression() { } [StorableConstructor] protected StringLengthExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Pop(); interpreter.IntegerStack.Push(str.Length); } } /// /// Reverses the top STRING. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.REVERSE", "Reverses the top STRING.")] public class StringReverseExpression : StatelessExpression { public StringReverseExpression() { } [StorableConstructor] protected StringReverseExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.StringStack.Top.Length <= 1; } public override void Eval(IInternalPushInterpreter interpreter) { var chars = interpreter.StringStack.Top.ToArray(); Array.Reverse(chars); interpreter.StringStack.Top = new string(chars); } } /// /// Maps every char of top STRING as separate string. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.PARSETOCHARS", "Maps every char of top STRING as separate string.")] public class StringParseToCharsExpression : StatelessExpression { public StringParseToCharsExpression() { } [StorableConstructor] protected StringParseToCharsExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { if (interpreter.StringStack.Top.Length == 0) { interpreter.StringStack.Pop(); return; } var str = interpreter.StringStack.Top; interpreter.StringStack.Top = str[0].ToString(); if (str.Length > 1) { var chars = new string[str.Length - 1]; for (var i = 0; i < str.Length - 1; i++) { chars[i] = str[i + 1].ToString(); } interpreter.StringStack.Push(chars); } } } /// /// Splits top STRING by whitespace chars. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.SPLIT", "Splits top STRING by whitespace chars.")] public class StringSplitExpression : StatelessExpression { public StringSplitExpression() { } [StorableConstructor] protected StringSplitExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var words = interpreter.StringStack.Top .Trim() .Split() .Where(x => !string.IsNullOrWhiteSpace(x)) .Reverse() .ToList(); if (words.Count == 0) { interpreter.StringStack.Pop(); } else { interpreter.StringStack.Top = words[0]; interpreter.StringStack.Push(words, 1); } } } /// /// True if top string is empty. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.EMPTYSTRING", "True if top STRING is empty.", StackTypes.Boolean)] public class StringEmptyStringExpression : StatelessExpression { public StringEmptyStringExpression() { } [StorableConstructor] protected StringEmptyStringExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Pop(); interpreter.BooleanStack.Push(str.Length == 0); } } /// /// True if top string is a substring of second string; false otherwise /// [StorableClass] [PushExpression( StackTypes.String, "STRING.CONTAINS", "True if top STRING is a substring of second STRING, false otherwise.", StackTypes.Boolean)] public class StringContainsExpression : StatelessExpression { public StringContainsExpression() { } [StorableConstructor] protected StringContainsExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.Count < 2; } public override void Eval(IInternalPushInterpreter interpreter) { var first = interpreter.StringStack[1]; var second = interpreter.StringStack.Top; interpreter.StringStack.Remove(2); interpreter.BooleanStack.Push(first.IndexOf(second, StringComparison.Ordinal) >= 0); } } /// /// True if the top char is in the top string /// [StorableClass] [PushExpression( StackTypes.String, "STRING.CONTAINSCHAR", "True if the top CHAR is in the top STRING.", StackTypes.Boolean | StackTypes.Char)] public class StringContainsCharExpression : StatelessExpression { public StringContainsCharExpression() { } [StorableConstructor] protected StringContainsCharExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.CharStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Pop(); var c = interpreter.CharStack.Pop(); interpreter.BooleanStack.Push(str.IndexOf(c) >= 0); } } /// /// Puts on the integer stack the index of the top char in the top string /// [StorableClass] [PushExpression( StackTypes.String, "STRING.INDEXOFCHAR", "Puts on the INTEGER stack the index of the top CHAR in the top STRING.", StackTypes.Integer | StackTypes.Char)] public class StringIndexOfCharExpression : StatelessExpression { public StringIndexOfCharExpression() { } [StorableConstructor] protected StringIndexOfCharExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.CharStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Pop(); var c = interpreter.CharStack.Pop(); interpreter.IntegerStack.Push(str.IndexOf(c)); } } /// /// The number of times the top char is in the top string /// [StorableClass] [PushExpression( StackTypes.String, "STRING.OCCURRENCESOFCHAR", "The number of times the top CHAR is in the top STRING.", StackTypes.Integer | StackTypes.Char)] public class StringOccurrencesOfCharExpression : StatelessExpression { public StringOccurrencesOfCharExpression() { } [StorableConstructor] protected StringOccurrencesOfCharExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.CharStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Pop(); var c = interpreter.CharStack.Pop(); var count = 0; for (var i = 0; i < str.Length; i++) if (str[i] == c) count++; interpreter.IntegerStack.Push(count); } } /// /// In third STRING, replaces second string with first string /// [StorableClass] [PushExpression( StackTypes.String, "STRING.REPLACE", "In third STRING, replaces second STRING with first STRING.")] public class StringReplaceExpression : StatelessExpression { public StringReplaceExpression() { } [StorableConstructor] protected StringReplaceExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.Count < 3; } public override void Eval(IInternalPushInterpreter interpreter) { var result = GetResultString(interpreter); // Should be checked in isNoop but would require to calculate result twice which is an expensive operation if (result.Length > interpreter.Configuration.MaxStringLength) return; interpreter.StringStack.Remove(2); interpreter.StringStack.Top = result; } private static string GetResultString(IInternalPushInterpreter interpreter) { var third = interpreter.StringStack[2]; var second = interpreter.StringStack[1]; var first = interpreter.StringStack[0]; var result = third.Length == 0 || second.Length == 0 ? third : third.Replace(second, first); return result; } } /// /// In third STRING, replaces first occurrence of second string with first string /// [StorableClass] [PushExpression( StackTypes.String, "STRING.REPLACEFIRST", "In third STRING, replaces first occurrence of second STRING with first STRING")] public class StringReplaceFirstExpression : StatelessExpression { public StringReplaceFirstExpression() { } [StorableConstructor] protected StringReplaceFirstExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.Count < 3; } public override void Eval(IInternalPushInterpreter interpreter) { var result = GetResultString(interpreter); // Should be checked in isNoop but would require to calculate result twice which is an expensive operation if (result.Length > interpreter.Configuration.MaxStringLength) return; interpreter.StringStack.Remove(2); interpreter.StringStack.Top = result; } private static string GetResultString(IInternalPushInterpreter interpreter) { var third = interpreter.StringStack[2]; var second = interpreter.StringStack[1]; var first = interpreter.StringStack[0]; var result = third.Length == 0 || second.Length == 0 ? third : ReplaceFirst(third, second, first); return result; } private static string ReplaceFirst(string text, string search, string replace) { var pos = text.IndexOf(search, StringComparison.Ordinal); return pos < 0 ? text : text.Substring(0, pos) + replace + text.Substring(pos + search.Length); } } /// /// In top STRING, replaces all occurrences of second char with first char /// [StorableClass] [PushExpression( StackTypes.String, "STRING.REPLACECHAR", "In top STRING, replaces all occurrences of second CHAR with first CHAR.", StackTypes.Char)] public class StringReplaceCharExpression : StatelessExpression { public StringReplaceCharExpression() { } [StorableConstructor] protected StringReplaceCharExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.CharStack.Count < 2; } public override void Eval(IInternalPushInterpreter interpreter) { var first = interpreter.CharStack[1]; var second = interpreter.CharStack.Top; interpreter.CharStack.Remove(2); var result = interpreter.StringStack.Top.Replace(first, second); interpreter.StringStack.Top = result; } } /// /// In top STRING, replaces first occurrence of second char with first char /// [StorableClass] [PushExpression( StackTypes.String, "STRING.REPLACEFIRSTCHAR", "In top STRING, replaces first occurrence of second CHAR with first CHAR.", StackTypes.Char)] public class StringReplaceFirstCharExpression : StatelessExpression { public StringReplaceFirstCharExpression() { } [StorableConstructor] protected StringReplaceFirstCharExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.CharStack.Count < 2; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Top; var first = interpreter.CharStack[1]; var second = interpreter.CharStack.Top; interpreter.CharStack.Remove(2); var pos = str.IndexOf(first); if (pos < 0) return; var result = str.Substring(0, pos) + second + str.Substring(Math.Min(pos + 1, str.Length - 1)); interpreter.StringStack.Top = result; } } /// /// In top STRING, remove all occurrences of char /// [StorableClass] [PushExpression( StackTypes.String, "STRING.REMOVECHAR", "In top STRING, remove all occurrences of top CHAR.", StackTypes.Char)] public class StringRemoveCharExpression : StatelessExpression { public StringRemoveCharExpression() { } [StorableConstructor] protected StringRemoveCharExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.CharStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var c = interpreter.CharStack.Pop(); var result = interpreter.StringStack.Top.Trim(c); interpreter.StringStack.Top = result; } } /// /// Sets char at index in string /// [StorableClass] [PushExpression( StackTypes.String, "STRING.SETCHAR", "Sets top CHAR at index in top STRING, whereby the index is taken from the INTEGER stack.", StackTypes.Char | StackTypes.Integer)] public class StringSetCharExpression : StatelessExpression { public StringSetCharExpression() { } [StorableConstructor] protected StringSetCharExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.CharStack.IsEmpty || interpreter.IntegerStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Top; var c = interpreter.CharStack.Pop(); var x = interpreter.IntegerStack.Pop(); if (str.Length == 0) return; if (str.Length == 1) { interpreter.StringStack.Top = c.ToString(); return; } var pos = x.AsInt(str.Length); var result = str.Substring(0, pos) + c + str.Substring(Math.Min(pos + 1, str.Length - 1)); interpreter.StringStack.Top = result; } } /// /// Iterates over a string using the code on the exec stack. /// [StorableClass] [PushExpression( StackTypes.String, "STRING.ITERATE", "Iterates over the top STRING using the CODE on the EXEC stack.", StackTypes.Exec | StackTypes.Char, requiredBlockCount: 1)] public class StringIterateExpression : StatelessExpression { public StringIterateExpression() { } [StorableConstructor] protected StringIterateExpression(bool deserializing) : base(deserializing) { } public override bool IsNoop(IInternalPushInterpreter interpreter) { return interpreter.StringStack.IsEmpty || interpreter.ExecStack.IsEmpty; } public override void Eval(IInternalPushInterpreter interpreter) { var str = interpreter.StringStack.Pop(); if (str.Length == 0) { interpreter.ExecStack.Pop(); } // If the rest of the string is empty, we're done iterating. else if (str.Length == 1) { interpreter.CharStack.Push(str[0]); } else { var pool = interpreter.PoolContainer.GetStatefulExpressionPool(); interpreter.CharStack.Push(str[0]); interpreter.ExecStack.Push( this, StringPushExpression.Create(pool, str.Substring(1)), interpreter.ExecStack.Top); } } } }