/// # C#/Dafny interop: Dafny side
///
/// See README.md for details.  This file receives a C# value and prints it.

/// We start by including the model generated by AutoExtern (this file does not
/// exist in the repository; it must be created by running ``make``).

include "LibraryModel.dfy"

/// Then we define the entry point that C# uses, which is marked `{:extern}`
/// because we don't want name mangling for it:

module {:extern "App.DafnyPrinter"} App.DafnyPrinter {
  import opened Library

  class {:extern "Printer"} Printer {
    static method PrintGroceryList(list: GroceryList<Fruit>)
      decreases *
    {
      var items: LinkedList<Entry<Fruit>> := list.items;

      print "# Printing a grocery list\n";

/// Surprisingly, the generated trait `LinkedList` refers to the `Length` field
/// as `LinkedList_Length`.  This is because C# is more flexible than Dafny, and
/// allows a class to define a field with a name that conflicts with that of an
/// interface property.  `AutoExtern` resolves this by renaming interface
/// fields.

      print "   (", items.LinkedList_Length, " items in the list)\n";

      while items is Cons<Entry<Fruit>>
        decreases *
      {
        var cons := items as Cons<Entry<Fruit>>;
        print "## ", cons.hd.item, ": ", cons.hd.count, " @ ", cons.hd.price.ToStr(), "\n";

/// Here we have a concrete type implementing `Length`, so we can refer to it
/// directly:

        print "   (", cons.Length, " item(s) left)\n";

/// Finally we move to the next element in the list:

        items := cons.tl;
      }
    }
  }
}
