Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PushGP/HeuristicLab.Algorithms.PushGP/HeuristicLab.Algorithms.PushGP/Expressions/CodeExpressions.cs @ 14513

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

#2665 Added Problem.ProgramSynthesis Project, Fixed Expression Issues, Fixed Code Generation

File size: 30.9 KB
Line 
1/// <summary>
2/// For explicit code manipulation and execution. May also be used as a general list data type.
3/// This type must always be present, as the top level interpreter will push any code to be executed on the
4/// CODE stack prior to execution. However, one may turn off all CODE instructions if code manipulation is not needed.
5/// </summary>
6
7namespace HeuristicLab.Algorithms.PushGP.Expressions {
8  using System;
9  using System.Collections.Generic;
10  using System.Linq;
11
12  using HeuristicLab.Algorithms.PushGP.Interpreter;
13
14  /// <summary>
15  ///     Recursively invokes the interpreter on the program on top of the CODE stack. After evaluation the
16  ///     CODE stack is popped; normally this pops the program that was just executed, but if the expression itself
17  ///     manipulates the stack then this final pop may end up popping something else.
18  /// </summary>
19  public class CodeDoExpression : StatelessExpression {
20    protected override string InitStringRepresentation() {
21      return "CODE.DO";
22    }
23
24    public override void Eval(IPushGpInterpreter interpreter) {
25      // not enough arguments on stack
26      if (interpreter.CodeStack.Count == 0) return;
27
28      interpreter.ExecStack.Push(new CodePopExpression(), interpreter.CodeStack.Top);
29    }
30  }
31
32  /// <summary>
33  ///     Like CODE.DO but pops the stack before, rather than after, the recursive execution
34  /// </summary>
35  public class CodeDoXExpression : StatelessExpression {
36    protected override string InitStringRepresentation() {
37      return "CODE.DO*";
38    }
39
40    public override void Eval(IPushGpInterpreter interpreter) {
41      // not enough arguments on stack
42      if (interpreter.CodeStack.Count == 0) return;
43
44      var expression = interpreter.CodeStack.Pop();
45      interpreter.ExecStack.Push(expression);
46    }
47  }
48
49  /// <summary>
50  ///     Does nothing.
51  /// </summary>
52  public class CodeNoopExpression : StatelessExpression {
53    protected override string InitStringRepresentation() {
54      return "CODE.NOOP";
55    }
56
57    public override void Eval(IPushGpInterpreter interpreter) {
58      // nothing to do
59    }
60  }
61
62  /// <summary>
63  ///     Specifies that the next expression submitted for execution will instead be pushed literally onto the CODE stack.
64  ///     This can be implemented by moving the top item on the EXEC stack onto the CODE stack.
65  /// </summary>
66  public class CodeQuoteExpression : StatelessExpression {
67    protected override string InitStringRepresentation() {
68      return "CODE.QUOTE";
69    }
70
71    public override void Eval(IPushGpInterpreter interpreter) {
72      // not enough arguments on stack
73      if (interpreter.ExecStack.Count == 0) return;
74
75      var expression = interpreter.ExecStack.Pop();
76      interpreter.CodeStack.Push(expression);
77    }
78  }
79
80  /// <summary>
81  ///     If the top item of the BOOLEAN stack is TRUE this recursively executes the second item of the CODE stack;
82  ///     otherwise it recursively executes the first item of the CODE stack. Either way both elements of the CODE stack
83  ///     (and the BOOLEAN value upon which the decision was made) are popped.
84  /// </summary>
85  public class CodeIfExpression : StatelessExpression {
86    protected override string InitStringRepresentation() {
87      return "CODE.IF";
88    }
89
90    public override void Eval(IPushGpInterpreter interpreter) {
91      // not enough arguments on stack
92      if ((interpreter.BooleanStack.Count == 0) || (interpreter.CodeStack.Count < 2)) return;
93
94      var condition = interpreter.BooleanStack.Pop();
95      var items = interpreter.CodeStack.Pop(2);
96
97      interpreter.ExecStack.Push(condition ? items[0] : items[1]);
98    }
99  }
100
101  /// <summary>
102  ///     Pushes the result of appending the top two pieces of code. If one of the pieces of code is a single instruction or
103  ///     literal (that is, something not surrounded by parentheses) then it is surrounded by parentheses first.
104  /// </summary>
105  public class CodeAppendExpression : StatelessExpression {
106    protected override string InitStringRepresentation() {
107      return "CODE.APPEND";
108    }
109
110    public override void Eval(IPushGpInterpreter interpreter) {
111      if (interpreter.CodeStack.Count < 2) return;
112
113      var first = interpreter.CodeStack.Pop();
114      var second = interpreter.CodeStack.Top;
115
116      var isFirstList = first.GetType() == typeof(ExecExpandExpression);
117      var isSecondList = second.GetType() == typeof(ExecExpandExpression);
118
119      Expression[] result = null;
120
121      if (isFirstList) {
122        var expand1 = first as ExecExpandExpression;
123
124        if (isSecondList) {
125          var expand2 = second as ExecExpandExpression;
126          var size = expand2.Expressions.Count + expand1.Expressions.Count;
127
128          // if size > maxPointsInProgram this expressions results in a NOOP
129          if (size > interpreter.Configuration.MaxPointsInProgram) return;
130
131          result = new Expression[size];
132
133          Array.Copy(expand2.Expressions as Expression[], result, expand2.Expressions.Count);
134          Array.Copy(
135            expand1.Expressions as Expression[],
136            0,
137            result,
138            expand2.Expressions.Count,
139            expand1.Expressions.Count);
140        } else {
141          var size = expand1.Expressions.Count + 1;
142
143          // if size > maxPointsInProgram this expressions results in a NOOP
144          if (size > interpreter.Configuration.MaxPointsInProgram) return;
145
146          result = new Expression[size];
147          result[0] = second;
148
149          Array.Copy(expand1.Expressions as Expression[], 0, result, 1, expand1.Expressions.Count);
150        }
151      } else if (isSecondList) {
152        var expand2 = second as ExecExpandExpression;
153
154        var size = expand2.Expressions.Count + 1;
155
156        // if size > maxPointsInProgram this expressions results in a NOOP
157        if (size > interpreter.Configuration.MaxPointsInProgram) return;
158
159        result = new Expression[size];
160        result[0] = first;
161
162        Array.Copy(expand2.Expressions as Expression[], 0, result, 1, expand2.Expressions.Count);
163      } else {
164        result = new[] { second, first };
165      }
166
167      var expression = new ExecExpandExpression(result);
168
169      interpreter.CodeStack.SetTop(expression);
170    }
171  }
172
173  /// <summary>
174  ///     Pushes TRUE onto the BOOLEAN stack if the top piece of code is a single instruction or a literal,
175  ///     and FALSE otherwise (that is, if it is something surrounded by parentheses).
176  /// </summary>
177  public class CodeAtomExpression : StatelessExpression {
178    protected override string InitStringRepresentation() {
179      return "CODE.ATOM";
180    }
181
182    public override void Eval(IPushGpInterpreter interpreter) {
183      if (interpreter.CodeStack.Count == 0) return;
184
185      var expression = interpreter.CodeStack.Pop();
186      var isExpandExpression = expression.GetType() != typeof(ExecExpandExpression);
187
188      interpreter.BooleanStack.Push(isExpandExpression);
189    }
190  }
191
192  /// <summary>
193  ///     Pushes the first item of the list on top of the CODE stack. For example, if the top piece of code is "( A B )"
194  ///     then this pushes "A" (after popping the argument). If the code on top of the stack is not a list then this has no
195  ///     effect.
196  ///     The name derives from the similar Lisp function; a more generic name would be "FIRST".
197  /// </summary>
198  public class CodeCarExpression : StatelessExpression {
199    protected override string InitStringRepresentation() {
200      return "CODE.CAR";
201    }
202
203    public override void Eval(IPushGpInterpreter interpreter) {
204      if ((interpreter.CodeStack.Count == 0) || (interpreter.CodeStack.Top.GetType() != typeof(ExecExpandExpression))) return;
205
206      var expand = interpreter.CodeStack.Top as ExecExpandExpression;
207
208      if (!expand.IsEmpty) {
209        var first = expand.Expressions[expand.Expressions.Count - 1];
210
211        interpreter.CodeStack.SetTop(first);
212      }
213    }
214  }
215
216  /// <summary>
217  ///     Pushes a version of the list from the top of the CODE stack without its first element.
218  ///     For example, if the top piece of code is "( A B )" then this pushes "( B )" (after popping the argument).
219  ///     If the code on top of the stack is not a list then this pushes the empty list ("( )"). The name derives from
220  ///     the similar Lisp function; a more generic name would be "REST".
221  /// </summary>
222  public class CodeCdrExpression : StatelessExpression {
223    protected override string InitStringRepresentation() {
224      return "CODE.CDR";
225    }
226
227    public override void Eval(IPushGpInterpreter interpreter) {
228      if (interpreter.CodeStack.Count == 0) return;
229
230      Expression expandExpression = null;
231      var top = interpreter.CodeStack.Top;
232
233      if (top.GetType() == typeof(ExecExpandExpression)) {
234        var expand = top as ExecExpandExpression;
235
236        if (expand.IsEmpty) return;
237        var length = expand.Expressions.Count - 1;
238        var newExpressions = new Expression[length];
239
240        Array.Copy(expand.Expressions as Expression[], 0, newExpressions, 0, length);
241
242        expandExpression = new ExecExpandExpression(newExpressions);
243      } else {
244        expandExpression = ExecExpandExpression.Empty;
245      }
246
247      interpreter.CodeStack.SetTop(expandExpression);
248    }
249  }
250
251  /// <summary>
252  ///     Pushes the result of "consing" (in the Lisp sense) the second stack item onto the first stack item
253  ///     (which is coerced to a list if necessary). For example, if the top piece of code is "( A B )" and the
254  ///     second piece of code is "X" then this pushes "( X A B )" (after popping the argument).
255  /// </summary>
256  public class CodeConsExpression : StatelessExpression {
257    protected override string InitStringRepresentation() {
258      return "CODE.CONS";
259    }
260
261    public override void Eval(IPushGpInterpreter interpreter) {
262      if ((interpreter.CodeStack.Count < 2)
263          || (interpreter.CodeStack[interpreter.CodeStack.Count - 1].GetType() != typeof(ExecExpandExpression))) return;
264
265      var first = interpreter.CodeStack.Pop() as ExecExpandExpression;
266
267      var size = first.Expressions.Count + 1;
268
269      if (size > interpreter.Configuration.MaxPointsInProgram) return;
270
271      var expressions = new Expression[size];
272
273      expressions[first.Expressions.Count] = interpreter.CodeStack.Top;
274      Array.Copy(first.Expressions as Expression[], expressions, first.Expressions.Count);
275
276      var result = new ExecExpandExpression(expressions);
277      interpreter.CodeStack.SetTop(result);
278    }
279  }
280
281  /// <summary>
282  ///     Pushes the "container" of the second CODE stack item within the first CODE stack item onto the CODE stack.
283  ///     If second item contains the first anywhere (i.e. in any nested list) then the container is the smallest sub-list
284  ///     that contains but is not equal to the first instance. For example, if the top piece of code is "( B ( C ( A ) ) ( D
285  ///     ( A ) ) )"
286  ///     and the second piece of code is "( A )" then this pushes ( C ( A ) ). Pushes an empty list if there is no such
287  ///     container.
288  /// </summary>
289  public class CodeContainerExpression : StatelessExpression {
290    protected override string InitStringRepresentation() {
291      return "CODE.CONTAINER";
292    }
293
294    public override void Eval(IPushGpInterpreter interpreter) {
295      if ((interpreter.CodeStack.Count < 2)
296          || (interpreter.CodeStack[interpreter.CodeStack.Count - 2].GetType() != typeof(ExecExpandExpression))) return;
297
298      var target = interpreter.CodeStack.Pop();
299      var source = interpreter.CodeStack.Top;
300
301      var container = this.GetContainer(null, source as ExecExpandExpression, target);
302      var result = container == null ? ExecExpandExpression.Empty : container;
303
304      interpreter.CodeStack.SetTop(result);
305    }
306
307    private ExecExpandExpression GetContainer(
308      ExecExpandExpression parent,
309      ExecExpandExpression current,
310      Expression target) {
311      var subContainer =
312        current.Expressions.Where(e => e.GetType() == typeof(ExecExpandExpression))
313          .Select(e => this.GetContainer(current, e as ExecExpandExpression, target))
314          .Where(e => e != null);
315
316      if (subContainer.Any()) return subContainer.OrderBy(c => c.Expressions.Count).LastOrDefault();
317      return current.Expressions.Contains(target) ? current : null;
318    }
319  }
320
321  /// <summary>
322  ///     Pushes TRUE on the BOOLEAN stack if the second CODE stack item contains the first CODE stack
323  ///     item anywhere (e.g. in a sub-list).
324  /// </summary>
325  public class CodeContainsExpression : StatelessExpression {
326    protected override string InitStringRepresentation() {
327      return "CODE.CONTAINS";
328    }
329
330    public override void Eval(IPushGpInterpreter interpreter) {
331      if ((interpreter.CodeStack.Count < 2)
332          || (interpreter.CodeStack[interpreter.CodeStack.Count - 2].GetType() != typeof(ExecExpandExpression))) return;
333
334      var values = interpreter.CodeStack.Pop(2);
335      var second = values[0] as ExecExpandExpression;
336
337      interpreter.BooleanStack.Push(second.Expressions.Contains(values[1]));
338    }
339  }
340
341  /// <summary>
342  ///     Pushes the definition associated with the top NAME on the NAME stack (if any) onto the CODE stack.
343  ///     This extracts the definition for inspection/manipulation, rather than for immediate execution (although it
344  ///     may then be executed with a call to CODE.DO or a similar instruction).
345  /// </summary>
346  public class CodeDefinitionExpression : StatelessExpression {
347    protected override string InitStringRepresentation() {
348      return "CODE.DEFINITION";
349    }
350
351    public override void Eval(IPushGpInterpreter interpreter) {
352      if ((interpreter.NameStack.Count == 0) || !interpreter.CustomExpressions.ContainsKey(interpreter.NameStack.Top)) return;
353
354      var name = interpreter.NameStack.Pop();
355      var definition = interpreter.CustomExpressions[name];
356
357      interpreter.CodeStack.Push(definition);
358    }
359  }
360
361  /// <summary>
362  ///     Pushes a measure of the discrepancy between the top two CODE stack items onto the INTEGER stack. This will be zero
363  ///     if the top
364  ///     two items are equivalent, and will be higher the 'more different' the items are from one another. The calculation
365  ///     is as follows:
366  ///     <list type="bullet">
367  ///         <item>
368  ///             <description>
369  ///                 Construct a list of all of the unique items in both of the lists(where uniqueness is determined by
370  ///                 equalp).
371  ///                 Sub-lists and atoms all count as items.
372  ///         </item>
373  ///         <item>
374  ///             <description>Initialize the result to zero.
375  ///         </item>
376  ///         <item>
377  ///             <description>
378  ///                 For each unique item increment the result by the difference between the number of occurrences of the
379  ///                 item in
380  ///                 the two pieces of code.
381  ///         </item>
382  ///         <item>
383  ///             <description>Push the result.
384  ///         </item>
385  ///     </list>
386  /// </summary>
387  public class CodeDiscrepancyExpression : StatelessExpression {
388    protected override string InitStringRepresentation() {
389      return "CODE.DISCREPANCY";
390    }
391
392    public override void Eval(IPushGpInterpreter interpreter) {
393      if (interpreter.CodeStack.Count < 2) return;
394
395      var expressions = interpreter.CodeStack.Pop(2);
396      var firstItems = new Dictionary<int, int>();
397      var secondItems = new Dictionary<int, int>();
398
399      this.DetermineUniqueItems(expressions[0], secondItems);
400      this.DetermineUniqueItems(expressions[1], firstItems);
401
402      var discrepancy = this.GetDiscrepancy(firstItems, secondItems);
403
404      interpreter.IntegerStack.Push(discrepancy);
405    }
406
407    private int GetDiscrepancy(IDictionary<int, int> first, IDictionary<int, int> second) {
408      var discrepancy = 0;
409      var keys = first.Keys.Concat(second.Keys).Distinct();
410
411      foreach (var key in keys)
412        if (first.ContainsKey(key) && second.ContainsKey(key)) discrepancy += Math.Abs(first[key] - second[key]);
413        else if (first.ContainsKey(key)) discrepancy += first[key];
414        else discrepancy += second[key];
415
416      return discrepancy;
417    }
418
419    private void DetermineUniqueItems(Expression source, IDictionary<int, int> items) {
420      if (source.GetType() == typeof(ExecExpandExpression)) {
421        var expand = source as ExecExpandExpression;
422
423        foreach (var e in expand.Expressions) {
424          var id = e.GetHashCode();
425          if (!items.ContainsKey(id)) items.Add(id, 1);
426          else items[id]++;
427        }
428      } else {
429        items.Add(source.GetHashCode(), 1);
430      }
431    }
432  }
433
434  /// <summary>
435  ///     Pushes the sub-expression of the top item of the CODE stack that is indexed by the top item of the INTEGER stack.
436  ///     The indexing here counts "points," where each parenthesized expression and each literal/instruction is considered a
437  ///     point,
438  ///     and it proceeds in depth first order. The entire piece of code is at index 0; if it is a list then the first item
439  ///     in the list
440  ///     is at index 1, etc. The integer used as the index is taken modulo the number of points in the overall expression
441  ///     (and its
442  ///     absolute value is taken in case it is negative) to ensure that it is within the meaningful range.
443  /// </summary>
444  public class CodeExtractExpression : StatelessExpression {
445    protected override string InitStringRepresentation() {
446      return "CODE.EXTRACT";
447    }
448
449    public override void Eval(IPushGpInterpreter interpreter) {
450      if ((interpreter.IntegerStack.Count == 0) || (interpreter.CodeStack.Count == 0)
451          || (interpreter.CodeStack.Top.GetType() != typeof(ExecExpandExpression))) return;
452
453      var expression = interpreter.CodeStack.Top as ExecExpandExpression;
454      var index = (int)Math.Abs(interpreter.IntegerStack.Pop() % expression.TotalCount);
455      var result = expression.GetFromTree(index);
456
457      interpreter.CodeStack.SetTop(result);
458    }
459  }
460
461  /// <summary>
462  ///     Pops the BOOLEAN stack and pushes the popped item (TRUE or FALSE) onto the CODE stack.
463  /// </summary>
464  public class CodeFromBooleanExpression : StatelessExpression {
465    protected override string InitStringRepresentation() {
466      return "CODE.FROMBOOLEAN";
467    }
468
469    public override void Eval(IPushGpInterpreter interpreter) {
470      if (interpreter.BooleanStack.Count == 0) return;
471
472      var value = interpreter.BooleanStack.Pop();
473      var expression = new BooleanPushExpression(value);
474
475      interpreter.CodeStack.Push(expression);
476    }
477  }
478
479  /// <summary>
480  ///     Pops the FLOAT stack and pushes the popped item onto the CODE stack.
481  /// </summary>
482  public class CodeFromFloatExpression : StatelessExpression {
483    protected override string InitStringRepresentation() {
484      return "CODE.FROMFLOAT";
485    }
486
487    public override void Eval(IPushGpInterpreter interpreter) {
488      if (interpreter.FloatStack.Count == 0) return;
489
490      var value = interpreter.FloatStack.Pop();
491      var expression = new FloatPushExpression(value);
492
493      interpreter.CodeStack.Push(expression);
494    }
495  }
496
497  /// <summary>
498  ///     Pops the INTEGER stack and pushes the popped integer onto the CODE stack.
499  /// </summary>
500  public class CodeFromIntegerExpression : StatelessExpression {
501    protected override string InitStringRepresentation() {
502      return "CODE.FROMINTEGER";
503    }
504
505    public override void Eval(IPushGpInterpreter interpreter) {
506      if (interpreter.IntegerStack.Count == 0) return;
507
508      var value = interpreter.IntegerStack.Pop();
509      var expression = new IntegerPushExpression(value);
510
511      interpreter.CodeStack.Push(expression);
512    }
513  }
514
515  /// <summary>
516  ///     Pops the NAME stack and pushes the popped item onto the CODE stack.
517  /// </summary>
518  public class CodeFromNameExpression : StatelessExpression {
519    protected override string InitStringRepresentation() {
520      return "CODE.FROMNAME";
521    }
522
523    public override void Eval(IPushGpInterpreter interpreter) {
524      if (interpreter.NameStack.Count == 0) return;
525
526      var value = interpreter.NameStack.Pop();
527      var expression = new NameDefineXExecExpression(value);
528
529      interpreter.CodeStack.Push(expression);
530    }
531  }
532
533  /// <summary>
534  ///     Pushes the result of inserting the second item of the CODE stack into the first item, at the position indexed
535  ///     by the top item of the INTEGER stack (and replacing whatever was there formerly).
536  /// </summary>
537  public class CodeInsertExpression : StatelessExpression {
538    protected override string InitStringRepresentation() {
539      return "CODE.INSERT";
540    }
541
542    public override void Eval(IPushGpInterpreter interpreter) {
543      if ((interpreter.IntegerStack.Count == 0) || (interpreter.CodeStack.Count < 2)
544          || (interpreter.CodeStack.Top.GetType() != typeof(ExecExpandExpression))) return;
545
546      var source = interpreter.CodeStack[interpreter.CodeStack.Count - 2];
547      var target = interpreter.CodeStack.Pop() as ExecExpandExpression;
548      var index = (int)interpreter.IntegerStack.Pop();
549
550      Expression[] newExpressions;
551      if (target.Expressions.Count > 0) {
552        index = target.Expressions.Count - 1 - Math.Abs(index % target.Expressions.Count);
553
554        newExpressions = target.CopyExpressions();
555        newExpressions[index] = source.GetType() == typeof(ExecExpandExpression)
556          ? (source as ExecExpandExpression).Copy()
557          : source;
558      } else {
559        newExpressions = new[] { source };
560      }
561
562      var result = new ExecExpandExpression(newExpressions);
563      interpreter.CodeStack.SetTop(result);
564    }
565  }
566
567  /// <summary>
568  ///     Pushes the length of the top item on the CODE stack onto the INTEGER stack.
569  ///     If the top item is not a list then this pushes a 1. If the top item is a list then this pushes the
570  ///     number of items in the top level of the list; that is, nested lists contribute only 1 to this count, no
571  ///     matter what they contain.
572  /// </summary>
573  public class CodeLengthExpression : StatelessExpression {
574    protected override string InitStringRepresentation() {
575      return "CODE.LENGTH";
576    }
577
578    public override void Eval(IPushGpInterpreter interpreter) {
579      if (interpreter.CodeStack.Count == 0) return;
580
581      var expression = interpreter.CodeStack.Pop();
582      var count = 1;
583
584      if (expression.GetType() == typeof(ExecExpandExpression)) count = (expression as ExecExpandExpression).Expressions.Count;
585
586      interpreter.IntegerStack.Push(count);
587    }
588  }
589
590  /// <summary>
591  ///     Pushes a list of the top two items of the CODE stack onto the CODE stack.
592  /// </summary>
593  public class CodeListExpression : StatelessExpression {
594    protected override string InitStringRepresentation() {
595      return "CODE.LIST";
596    }
597
598    public override void Eval(IPushGpInterpreter interpreter) {
599      if (interpreter.CodeStack.Count < 2) return;
600
601      var first = interpreter.CodeStack.Pop();
602      var second = interpreter.CodeStack.Top;
603
604      var expandExpression = new ExecExpandExpression(new[] { second, first });
605
606      interpreter.CodeStack.SetTop(expandExpression);
607    }
608  }
609
610  /// <summary>
611  ///     Pushes TRUE onto the BOOLEAN stack if the second item of the CODE stack is a member of the first item
612  ///     (which is coerced to a list if necessary). Pushes FALSE onto the BOOLEAN stack otherwise.
613  /// </summary>
614  public class CodeMemberExpression : StatelessExpression {
615    protected override string InitStringRepresentation() {
616      return "CODE.MEMBER";
617    }
618
619    public override void Eval(IPushGpInterpreter interpreter) {
620      if (interpreter.CodeStack.Count < 2) return;
621
622      var expressions = interpreter.CodeStack.Pop(2);
623
624      var contains = expressions[1].GetType() == typeof(ExecExpandExpression)
625                       ? (expressions[1] as ExecExpandExpression).Expressions.Contains(expressions[0])
626                       : expressions[1].Equals(expressions[0]);
627
628      interpreter.BooleanStack.Push(contains);
629    }
630  }
631
632  /// <summary>
633  ///     Pushes the nth element of the expression on top of the CODE stack (which is coerced to a list first if necessary).
634  ///     If the expression is an empty list then the result is an empty list. N is taken from the INTEGER stack and is taken
635  ///     modulo the length of the expression into which it is indexing.
636  /// </summary>
637  public class CodeNthExpression : StatelessExpression {
638    protected override string InitStringRepresentation() {
639      return "CODE.NTH";
640    }
641
642    public override void Eval(IPushGpInterpreter interpreter) {
643      if ((interpreter.CodeStack.Count == 0) || (interpreter.IntegerStack.Count == 0)) return;
644
645      var n = interpreter.IntegerStack.Pop();
646      var expression = interpreter.CodeStack.Top;
647
648      Expression nthExpression = null;
649
650      if (expression.GetType() == typeof(ExecExpandExpression)) {
651        var subExpression = expression as ExecExpandExpression;
652
653        if (subExpression.IsEmpty) {
654          nthExpression = ExecExpandExpression.Empty;
655        } else {
656          var index = (int)(subExpression.Expressions.Count - 1 - Math.Abs(n % subExpression.Expressions.Count));
657
658          nthExpression = subExpression.Expressions[index];
659        }
660      } else {
661        nthExpression = expression;
662      }
663
664      interpreter.CodeStack.SetTop(nthExpression);
665    }
666  }
667
668  /// <summary>
669  ///     Pushes the nth "CDR" (in the Lisp sense) of the expression on top of the CODE stack (which is coerced to a list
670  ///     first if necessary). If the expression is an empty list then the result is an empty list. N is taken from the
671  ///     INTEGER
672  ///     stack and is taken modulo the length of the expression into which it is indexing. A "CDR" of a list is the list
673  ///     without
674  ///     its first element.
675  /// </summary>
676  public class CodeNthCdrExpression : StatelessExpression {
677    protected override string InitStringRepresentation() {
678      return "CODE.NTHCDR";
679    }
680
681    public override void Eval(IPushGpInterpreter interpreter) {
682      if ((interpreter.CodeStack.Count == 0) || (interpreter.IntegerStack.Count == 0)) return;
683
684      var n = interpreter.IntegerStack.Pop();
685      var expression = interpreter.CodeStack.Top;
686
687      Expression nthExpression = null;
688
689      if (expression.GetType() == typeof(ExecExpandExpression)) {
690        var subExpressions = (expression as ExecExpandExpression).Expressions;
691
692        if (subExpressions.Count < 2) {
693          nthExpression = ExecExpandExpression.Empty;
694        } else {
695          var index = (int)(subExpressions.Count - 2 - Math.Abs(n % (subExpressions.Count - 1)));
696
697          nthExpression = subExpressions[index];
698        }
699      } else {
700        nthExpression = expression;
701      }
702
703      interpreter.CodeStack.SetTop(nthExpression);
704    }
705  }
706
707  /// <summary>
708  ///     Pushes TRUE onto the BOOLEAN stack if the top item of the CODE stack is an empty list, or FALSE otherwise.
709  /// </summary>
710  public class CodeNullExpression : StatelessExpression {
711    protected override string InitStringRepresentation() {
712      return "CODE.NULL";
713    }
714
715    public override void Eval(IPushGpInterpreter interpreter) {
716      if (interpreter.CodeStack.Count == 0) return;
717
718      var result = interpreter.CodeStack.Pop().Equals(ExecExpandExpression.Empty);
719
720      interpreter.BooleanStack.Push(result);
721    }
722  }
723
724  /// <summary>
725  ///     Pushes onto the INTEGER stack the position of the second item on the CODE stack within the first item
726  ///     (which is coerced to a list if necessary). Pushes -1 if no match is found.
727  /// </summary>
728  public class CodePositionExpression : StatelessExpression {
729    protected override string InitStringRepresentation() {
730      return "CODE.POSITION";
731    }
732
733    public override void Eval(IPushGpInterpreter interpreter) {
734      if (interpreter.CodeStack.Count < 2) return;
735
736      var expressions = interpreter.CodeStack.Pop(2);
737      var first = expressions[1];
738      var second = expressions[0];
739
740      var position = -1;
741      if (first.GetType() == typeof(ExecExpandExpression)) {
742        var expand = first as ExecExpandExpression;
743        position = expand.Expressions.Count - 1
744                   - Array.FindIndex(expand.Expressions as Expression[], e => e.Equals(second));
745      } else if (first.Equals(second)) {
746        position = 0;
747      }
748
749      interpreter.IntegerStack.Push(position);
750    }
751  }
752
753  /// <summary>
754  ///     Pushes the number of "points" in the top piece of CODE onto the INTEGER stack. Each instruction, literal,
755  ///     and pair of parentheses counts as a point.
756  /// </summary>
757  public class CodeSizeExpression : StatelessExpression {
758    protected override string InitStringRepresentation() {
759      return "CODE.SIZE";
760    }
761
762    public override void Eval(IPushGpInterpreter interpreter) {
763      if (interpreter.CodeStack.Count == 0) return;
764
765      var expression = interpreter.CodeStack.Pop();
766      var points = expression.GetType() == typeof(ExecExpandExpression)
767                     ? (expression as ExecExpandExpression).Expressions.Count
768                     : 1;
769
770      interpreter.IntegerStack.Push(points);
771    }
772  }
773
774  /// <summary>
775  ///     Pushes the result of substituting the third item on the code stack for the second item in the first item.
776  ///     As of this writing this is implemented only in the Lisp implementation, within which it relies on the Lisp "subst"
777  ///     function. As such, there are several problematic possibilities; for example "dotted-lists" can result in certain
778  ///     cases with empty-list arguments. If any of these problematic possibilities occurs the stack is left unchanged.
779  /// </summary>
780  public class CodeSubstitutionExpression : StatelessExpression {
781    protected override string InitStringRepresentation() {
782      return "CODE.SUBST";
783    }
784
785    public override void Eval(IPushGpInterpreter interpreter) {
786      if ((interpreter.CodeStack.Count < 3) || (interpreter.CodeStack.Top.GetType() != typeof(ExecExpandExpression))) return;
787
788      var expressions = interpreter.CodeStack.Pop(2);
789      var third = interpreter.CodeStack.Top;
790      var second = expressions[0];
791      var first = expressions[1] as ExecExpandExpression;
792      var newExpressions = new Expression[first.Expressions.Count];
793
794      for (var i = 0; i < first.Expressions.Count; i++)
795        newExpressions[i] = first.Expressions[i].Equals(third)
796                              ? second
797                              /* no cloning needed here because first is removed and therefore newExpression is the
798             only container of sub expressions */
799                              : first.Expressions[i];
800
801      var result = new ExecExpandExpression(newExpressions);
802
803      interpreter.CodeStack.SetTop(result);
804    }
805  }
806}
Note: See TracBrowser for help on using the repository browser.