001package daikon.test.diff;
002
003import static java.util.logging.Level.INFO;
004import static org.junit.Assert.assertEquals;
005
006import daikon.*;
007import daikon.config.*;
008import daikon.diff.*;
009import daikon.inv.*;
010import daikon.inv.unary.scalar.*;
011import daikon.split.*;
012import daikon.split.misc.*;
013import daikon.test.*;
014import java.io.ByteArrayOutputStream;
015import java.io.PrintStream;
016import java.lang.reflect.InvocationTargetException;
017import java.lang.reflect.Method;
018import java.util.ArrayList;
019import java.util.List;
020import junit.framework.*;
021import org.junit.Before;
022import org.junit.BeforeClass;
023import org.junit.Test;
024
025@SuppressWarnings({"nullness", "UnusedVariable"}) // testing code
026public class DiffTester {
027
028  private Diff diffSome;
029  private Diff diffAll;
030
031  private PptMap empty;
032
033  private PptMap ppts1;
034  private PptMap ppts2;
035  private PptMap ppts3;
036  private PptMap ppts4;
037
038  // ppts1 plus conditional program points
039  private PptMap pptsCond;
040
041  private PptMap invs1;
042  private PptMap invs2;
043  private PptMap invs3;
044  private PptMap imps1;
045  private PptMap imps2;
046
047  /** prepare for tests */
048  @BeforeClass
049  public static void setUpClass() {
050    daikon.LogHelper.setupLogs(INFO);
051    FileIO.new_decl_format = true;
052  }
053
054  @Before
055  public void setUp()
056      throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
057    diffSome = new Diff();
058    diffAll = new Diff(true);
059
060    empty = new PptMap();
061
062    ppts1 = new PptMap();
063    ppts1.add(newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]));
064    ppts1.add(newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]));
065    ppts1.add(newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]));
066
067    ppts2 = new PptMap();
068    ppts2.add(newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]));
069    ppts2.add(newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]));
070
071    // Permutation of ppts1
072    ppts3 = new PptMap();
073    ppts3.add(newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]));
074    ppts3.add(newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]));
075    ppts3.add(newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]));
076
077    {
078      ppts4 = new PptMap();
079      ppts4.add(newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]));
080      PptTopLevel ppt1 = newPptTopLevel("Foo.Bar(int):::EXIT19", new VarInfo[0]);
081      PptTopLevel ppt2 = newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]);
082      ppts4.add(ppt1);
083      ppts4.add(ppt2);
084    }
085
086    {
087      pptsCond = new PptMap();
088      PptTopLevel ppt1 = newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]);
089      Splitter split = new ReturnTrueSplitter();
090      PptSplitter ppt_split = new PptSplitter(ppt1, split);
091      ppt1.splitters = new ArrayList<PptSplitter>();
092      ppt1.splitters.add(ppt_split);
093      pptsCond.add(ppt1);
094      pptsCond.add(newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]));
095      pptsCond.add(newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]));
096    }
097
098    // Invoke private method using reflection
099    Method mAddViews = PptTopLevel.class.getDeclaredMethod("addViews", new Class<?>[] {List.class});
100    mAddViews.setAccessible(true);
101
102    {
103      invs1 = new PptMap();
104      VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")};
105      PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars);
106      PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]});
107      Invariant invx = LowerBound.get_proto().instantiate(slicex);
108      slicex.addInvariant(invx);
109      PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]});
110      Invariant invy = LowerBound.get_proto().instantiate(slicey);
111      slicey.addInvariant(invy);
112      PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]});
113      Invariant invz = LowerBound.get_proto().instantiate(slicez);
114      slicez.addInvariant(invz);
115      List<PptSlice> v = new ArrayList<>();
116      v.add(slicex);
117      v.add(slicey);
118      v.add(slicez);
119      mAddViews.invoke(ppt, new Object[] {v});
120      invs1.add(ppt);
121    }
122
123    {
124      // Permutation of invs1
125      invs2 = new PptMap();
126      VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")};
127      PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars);
128      PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]});
129      Invariant invy = LowerBound.get_proto().instantiate(slicey);
130      slicey.addInvariant(invy);
131      PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]});
132      Invariant invx = LowerBound.get_proto().instantiate(slicex);
133      slicex.addInvariant(invx);
134      PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]});
135      Invariant invz = LowerBound.get_proto().instantiate(slicez);
136      slicez.addInvariant(invz);
137      List<PptSlice> v = new ArrayList<>();
138      v.add(slicey);
139      v.add(slicex);
140      v.add(slicez);
141      mAddViews.invoke(ppt, new Object[] {v});
142      invs2.add(ppt);
143    }
144
145    {
146      invs3 = new PptMap();
147      VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")};
148      PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars);
149      PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]});
150      Invariant invx = LowerBound.get_proto().instantiate(slicex);
151      slicex.addInvariant(invx);
152      PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]});
153      Invariant invy = UpperBound.get_proto().instantiate(slicey);
154      slicex.addInvariant(invy);
155      PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]});
156      Invariant invz = LowerBound.get_proto().instantiate(slicez);
157      slicez.addInvariant(invz);
158      List<PptSlice> v = new ArrayList<>();
159      v.add(slicex);
160      v.add(slicey);
161      v.add(slicez);
162      mAddViews.invoke(ppt, new Object[] {v});
163      invs3.add(ppt);
164    }
165
166    {
167      // Ensure that Modulus is enabled
168      Configuration.getInstance().apply(daikon.inv.unary.scalar.Modulus.class, "enabled", "true");
169
170      imps1 = new PptMap();
171      VarInfo[] vars = {newIntVarInfo("x")};
172      PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars);
173      PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]});
174      Invariant inv1 = LowerBound.get_proto().instantiate(slicex);
175      Invariant inv2 = Modulus.get_proto().instantiate(slicex);
176      Invariant inv3 = UpperBound.get_proto().instantiate(slicex);
177      Implication imp1 = Implication.makeImplication(ppt, inv1, inv2, false, inv1, inv2);
178      Implication imp2 = Implication.makeImplication(ppt, inv1, inv3, false, inv1, inv3);
179      Implication imp3 = Implication.makeImplication(ppt, inv2, inv1, false, inv2, inv1);
180      Implication imp4 = Implication.makeImplication(ppt, inv2, inv3, false, inv2, inv3);
181      Implication imp5 = Implication.makeImplication(ppt, inv3, inv1, false, inv3, inv1);
182      Implication imp6 = Implication.makeImplication(ppt, inv3, inv2, false, inv3, inv2);
183      imps1.add(ppt);
184    }
185
186    // Permutation of the nullary invariants in invs1
187    {
188      imps2 = new PptMap();
189      VarInfo[] vars = {newIntVarInfo("x")};
190      PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars);
191      PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]});
192      Invariant inv1 = LowerBound.get_proto().instantiate(slicex);
193      Invariant inv2 = Modulus.get_proto().instantiate(slicex);
194      Invariant inv3 = UpperBound.get_proto().instantiate(slicex);
195      Implication imp3 = Implication.makeImplication(ppt, inv2, inv1, false, inv2, inv1);
196      Implication imp2 = Implication.makeImplication(ppt, inv1, inv3, false, inv1, inv3);
197      Implication imp4 = Implication.makeImplication(ppt, inv2, inv3, false, inv2, inv3);
198      Implication imp5 = Implication.makeImplication(ppt, inv3, inv1, false, inv3, inv1);
199      Implication imp6 = Implication.makeImplication(ppt, inv3, inv2, false, inv3, inv2);
200      Implication imp1 = Implication.makeImplication(ppt, inv1, inv2, false, inv1, inv2);
201      imps2.add(ppt);
202    }
203  }
204
205  @SuppressWarnings("interning")
206  public static VarInfo newIntVarInfo(String name) {
207    return new VarInfo(
208        name, ProglangType.INT, ProglangType.INT, VarComparabilityNone.it, VarInfoAux.getDefault());
209  }
210
211  @Test
212  public void testEmptyEmpty() {
213    RootNode diff = diffSome.diffPptMap(empty, empty);
214    RootNode ref = new RootNode();
215    assertEquals(printTree(ref), printTree(diff));
216  }
217
218  @Test
219  public void testEmptyPpts1() {
220    RootNode diff = diffSome.diffPptMap(empty, ppts1);
221
222    RootNode ref = new RootNode();
223    PptNode node;
224    node = new PptNode(null, newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]));
225    ref.add(node);
226    node = new PptNode(null, newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]));
227    ref.add(node);
228    node = new PptNode(null, newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]));
229    ref.add(node);
230
231    assertEquals(printTree(ref), printTree(diff));
232  }
233
234  @Test
235  public void testPpts1Empty() {
236    RootNode diff = diffSome.diffPptMap(ppts1, empty);
237
238    RootNode ref = new RootNode();
239    PptNode node;
240    node = new PptNode(newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]), null);
241    ref.add(node);
242    node = new PptNode(newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]), null);
243    ref.add(node);
244    node = new PptNode(newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]), null);
245    ref.add(node);
246
247    assertEquals(printTree(ref), printTree(diff));
248  }
249
250  @Test
251  public void testPpts1Ppts1() {
252    RootNode diff = diffSome.diffPptMap(ppts1, ppts1);
253
254    RootNode ref = new RootNode();
255    PptNode node;
256    node =
257        new PptNode(
258            newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]),
259            newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]));
260    ref.add(node);
261    node =
262        new PptNode(
263            newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]),
264            newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]));
265    ref.add(node);
266    node =
267        new PptNode(
268            newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]),
269            newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]));
270    ref.add(node);
271
272    assertEquals(printTree(ref), printTree(diff));
273  }
274
275  @Test
276  public void testPpts1Ppts2() {
277    RootNode diff = diffSome.diffPptMap(ppts1, ppts2);
278
279    RootNode ref = new RootNode();
280    PptNode node;
281    node =
282        new PptNode(
283            newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]),
284            newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]));
285    ref.add(node);
286    node =
287        new PptNode(
288            newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]),
289            newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]));
290    ref.add(node);
291    node = new PptNode(newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]), null);
292    ref.add(node);
293
294    assertEquals(printTree(ref), printTree(diff));
295  }
296
297  @Test
298  public void testPpts1Ppts3() {
299    RootNode diff = diffSome.diffPptMap(ppts1, ppts3);
300
301    RootNode ref = new RootNode();
302    PptNode node;
303    node =
304        new PptNode(
305            newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]),
306            newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]));
307    ref.add(node);
308    node =
309        new PptNode(
310            newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]),
311            newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]));
312    ref.add(node);
313    node =
314        new PptNode(
315            newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]),
316            newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]));
317    ref.add(node);
318
319    assertEquals(printTree(ref), printTree(diff));
320  }
321
322  @Test
323  public void testInvs1Empty() {
324    RootNode diff = diffSome.diffPptMap(invs1, empty);
325
326    RootNode ref = new RootNode();
327
328    VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")};
329    PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars);
330    PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]});
331    Invariant invx = LowerBound.get_proto().instantiate(slicex);
332    slicex.addInvariant(invx);
333    PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]});
334    Invariant invy = LowerBound.get_proto().instantiate(slicey);
335    slicey.addInvariant(invy);
336    PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]});
337    Invariant invz = LowerBound.get_proto().instantiate(slicez);
338    slicez.addInvariant(invz);
339    PptNode pptNode;
340    pptNode = new PptNode(ppt, null);
341    InvNode invNode;
342    invNode = new InvNode(invx, null);
343    pptNode.add(invNode);
344    invNode = new InvNode(invy, null);
345    pptNode.add(invNode);
346    invNode = new InvNode(invz, null);
347    pptNode.add(invNode);
348    ref.add(pptNode);
349    assertEquals(printTree(ref), printTree(diff));
350  }
351
352  @Test
353  public void testInvs1Invs1() {
354    RootNode diff = diffSome.diffPptMap(invs1, invs1);
355
356    RootNode ref = new RootNode();
357
358    VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")};
359    PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars);
360    PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]});
361    Invariant invx = LowerBound.get_proto().instantiate(slicex);
362    slicex.addInvariant(invx);
363    PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]});
364    Invariant invy = LowerBound.get_proto().instantiate(slicey);
365    slicey.addInvariant(invy);
366    PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]});
367    Invariant invz = LowerBound.get_proto().instantiate(slicez);
368    slicez.addInvariant(invz);
369
370    PptNode pptNode;
371    pptNode = new PptNode(ppt, ppt);
372    InvNode invNode;
373    invNode = new InvNode(invx, invx);
374    pptNode.add(invNode);
375    invNode = new InvNode(invy, invy);
376    pptNode.add(invNode);
377    invNode = new InvNode(invz, invz);
378    pptNode.add(invNode);
379    ref.add(pptNode);
380
381    assertEquals(printTree(ref), printTree(diff));
382  }
383
384  @Test
385  public void testInvs1Invs2() {
386    RootNode diff = diffSome.diffPptMap(invs1, invs2);
387
388    RootNode ref = new RootNode();
389
390    VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")};
391    PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars);
392    PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]});
393    Invariant invx = LowerBound.get_proto().instantiate(slicex);
394    slicex.addInvariant(invx);
395    PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]});
396    Invariant invy = LowerBound.get_proto().instantiate(slicey);
397    slicey.addInvariant(invy);
398    PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]});
399    Invariant invz = LowerBound.get_proto().instantiate(slicez);
400    slicez.addInvariant(invz);
401
402    PptNode pptNode;
403    pptNode = new PptNode(ppt, ppt);
404    InvNode invNode;
405    invNode = new InvNode(invx, invx);
406    pptNode.add(invNode);
407    invNode = new InvNode(invy, invy);
408    pptNode.add(invNode);
409    invNode = new InvNode(invz, invz);
410    pptNode.add(invNode);
411    ref.add(pptNode);
412
413    assertEquals(printTree(ref), printTree(diff));
414  }
415
416  @Test
417  public void testInvs1Invs3() {
418    RootNode diff = diffSome.diffPptMap(invs1, invs3);
419
420    RootNode ref = new RootNode();
421
422    VarInfo[] vars = {newIntVarInfo("x"), newIntVarInfo("y"), newIntVarInfo("z")};
423    PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars);
424    PptSlice slicex = new PptSlice1(ppt, new VarInfo[] {vars[0]});
425    Invariant invx = LowerBound.get_proto().instantiate(slicex);
426    PptSlice slicey = new PptSlice1(ppt, new VarInfo[] {vars[1]});
427    Invariant invy1 = LowerBound.get_proto().instantiate(slicey);
428    Invariant invy2 = UpperBound.get_proto().instantiate(slicey);
429    PptSlice slicez = new PptSlice1(ppt, new VarInfo[] {vars[2]});
430    Invariant invz = LowerBound.get_proto().instantiate(slicez);
431
432    PptNode pptNode;
433    pptNode = new PptNode(ppt, ppt);
434    InvNode invNode;
435    invNode = new InvNode(invx, invx);
436    pptNode.add(invNode);
437    invNode = new InvNode(invy1, null);
438    pptNode.add(invNode);
439    invNode = new InvNode(invz, invz);
440    pptNode.add(invNode);
441    invNode = new InvNode(null, invy2);
442    pptNode.add(invNode);
443    ref.add(pptNode);
444
445    assertEquals(printTree(ref), printTree(diff));
446  }
447
448  @Test
449  public void testNullaryInvs() {
450    // executed for side effect
451    diffSome.diffPptMap(imps1, imps2);
452  }
453
454  @Test
455  public void testNonModulus() {
456    // Ensure that NonModulus is enabled
457    Configuration.getInstance().apply(daikon.inv.unary.scalar.NonModulus.class, "enabled", "true");
458
459    PptMap map = new PptMap();
460    VarInfo[] vars = {newIntVarInfo("x")};
461    PptTopLevel ppt = newPptTopLevel("Foo.Baa(int):::ENTER", vars);
462    PptSlice slice = new PptSlice1(ppt, vars);
463    Invariant inv = NonModulus.get_proto().instantiate(slice);
464    slice.addInvariant(inv);
465    map.add(ppt);
466
467    diffSome.diffPptMap(map, map);
468  }
469
470  // Runs diff on a PptMap containing a PptConditional, with
471  // examineAllPpts set to false.  The PptConditional should be
472  // ignored.
473  @Test
474  public void testConditionalPptsFalse() {
475    RootNode diff = diffSome.diffPptMap(ppts1, pptsCond);
476
477    RootNode ref = new RootNode();
478    PptNode node;
479    node =
480        new PptNode(
481            newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]),
482            newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]));
483    ref.add(node);
484    node =
485        new PptNode(
486            newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]),
487            newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]));
488    ref.add(node);
489    node =
490        new PptNode(
491            newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]),
492            newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]));
493    ref.add(node);
494
495    assertEquals(printTree(ref), printTree(diff));
496  }
497
498  // Runs diff on a PptMap containing a PptConditional, with
499  // examineAllPpts set to true.  The PptConditional should be
500  // ignored.
501  @Test
502  public void testConditionalPptsTrue() {
503    RootNode diff = diffAll.diffPptMap(ppts1, pptsCond);
504
505    RootNode ref = new RootNode();
506    PptNode node;
507    node =
508        new PptNode(
509            newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]),
510            newPptTopLevel("Foo.Baa(int):::ENTER", new VarInfo[0]));
511    ref.add(node);
512    node =
513        new PptNode(
514            null,
515            newPptTopLevel(
516                "Foo.Baa(int):::ENTER;condition=\"not(return == true)\"", new VarInfo[0]));
517    ref.add(node);
518    node =
519        new PptNode(
520            null,
521            newPptTopLevel("Foo.Baa(int):::ENTER;condition=\"return == true\"", new VarInfo[0]));
522    ref.add(node);
523    node =
524        new PptNode(
525            newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]),
526            newPptTopLevel("Foo.Bar(int):::ENTER", new VarInfo[0]));
527    ref.add(node);
528    node =
529        new PptNode(
530            newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]),
531            newPptTopLevel("Foo.Bar(int):::EXIT", new VarInfo[0]));
532    ref.add(node);
533
534    assertEquals(printTree(ref), printTree(diff));
535  }
536
537  private static String printTree(RootNode root) {
538    ByteArrayOutputStream baos = new ByteArrayOutputStream();
539    PrintStream ps = new PrintStream(baos);
540    PrintAllVisitor v = new PrintAllVisitor(ps, false, true);
541    root.accept(v);
542    @SuppressWarnings("DefaultCharset") // toString(Charset) was introduced in Java 10
543    String result = baos.toString();
544    return result;
545  }
546
547  ///////////////////////////////////////////////////////////////////////////
548  /// Helper functions
549  ///
550
551  static PptTopLevel newPptTopLevel(String pptname, VarInfo[] vars) {
552    return Common.makePptTopLevel(pptname, vars);
553  }
554}