module IntMap { int_map = (int size,entries map) entries = (entry* entries) entry = (int key, int value) }The above is one possible abstract description of a mapping from integers to integers. It would be more efficient to implement such a mapping as a binary tree. Described as with the ASDL definition below.
module IntMap { int_map = (size int,map tree) tree = Node(int key,int value,tree left,tree right) | Empty }
Although this is a much more efficient representation it exposes implementation details in the pickle. If we decided to change the implementation of int_maps to use a hash table the underlying pickle format will change too, and all other clients that use our pickles will have to be updated.
Views let you write the first version so you get a simple and abstract representation on the disk, while letting you choose a different efficient in-core representation. They do this by letting the user control how asdlGen converts the description of a module into an actual implementation.
view = "view" id "{" {view_entry} "}" view_entry = id "." {id} "<=" id lit_txt | "module" id "<=" id lit_txtwhere lit_txt is either a ":" followed by some arbitrary text that continues to the end of the line or a "%%" balanced by a "%%" at the beginning of a line. The lit_txt is then passed to another internal parser that interprets the string based on the property name. This is a hack to make the view mechanism extendible without changing the grammar.
module IntMap { int_map = (int size,entries map) entries = (entry* entries) entry = (int key, int value) } view C { IntMap.entries <= natural_type : Bst.bst IntMap.entries <= wrapper : entries2bst IntMap.entries <= unwrapper : bst2entries module IntMap <= interface_prologue %% #include "bst.h" %% module IntMap <= implementation_prologue %% /* proto_types for wrapper functions */ static entries2bst(IntMap_entries_ty x) { /* code to convert int_map to a bst */ } static IntMap_entries_ty bst2entries(Bst_bst_ty x) { /* code to convert bst to an int map */ } %% } view C_with_HT { IntMap.entries <= natural_type : Ht.ht IntMap.entries <= wrapper : entries2ht IntMap.entries <= unwrapper : ht2entries module IntMap <= interface_prologue : #include "ht.h" module IntMap <= implementation_prologue %% /* ... */ %% }
Views like modules are named. In this example we have two different views named C and C_with_HT. By default when translating a module asdlGen looks for a language specific view depending on the type of output code. When asdlGen is invoked with --lang it looks for the viewed named Lang. The default view can be overridden with the --view command line.
N.B. Currently only the C and SML translators do anything interesting with the view data.
Views contain entries of the form
It is illegal to name an ASDL base type as an entity. e.g.
For example natural_type is a property that is a language independent identifier which names the type identifier which describes the in-core type to use in place of entries. In the first view it refers to the type bst which lives in a Bst module. It is mangled so that it appears in the C code as Bst_bst_ty. Using the standard ASDL mangling conventions.
The module properties interface_prologue and implementation_prologue are language dependent since they allow the literal inclusion of arbitrary user defined code in the output. In future there will be better support to split the language dependent and independent parts of views, as well as support to inherit or import entries from other views.
Running asdlGen on the above code produces IntMap.h and IntMap.c. Notice how the definition for the entries type is not completely removed. You need this type definition in order to write the conversion functions. Everywhere there normally would have been a IntMap_entires_ty type there now is the user type Bst_bst_ty. For example there is still a constructor prototype and constructor for IntMap_entries_ty. But the IntMap_int_map constructor now expects an argument of type Bst_bst_ty. The structs also reflect this.
IntMap_entries_ty IntMap_entries(IntMap_entry_list_ty entries); IntMap_int_map_ty IntMap_int_map(int_ty size, Bst_bst_ty map);Notice also that the pickle functions now return and expect a Bst_bst_ty
Bst_bst_ty IntMap_read_entries(instream_ty s); void IntMap_write_entries(Bst_bst_ty x, outstream_ty s);
The implementation of the pickle functions now also call the user supplied wrapper and unwrapper functions. The wrapper and unwrapper function names are language independent identifiers. It just so happens they don't need to be mangled. Since they're also local to our implementation we don't qualify them.
Bst_bst_ty IntMap_read_entries(instream_ty s) { Bst_bst_ty ret; .... tmp->entries = IntMap_read_entry_list(s); ret = bst2entries(tmp); return ret; } void IntMap_write_entries(Bst_bst_ty x, outstream_ty s) { IntMap_entries_ty tmp; tmp = entries2bst(x); IntMap_write_entry_list(tmp->entries, s); }
Set the value of the enumeration produced in the code.
view C { Slp.Times <= enum_value : 1 Slp.Plus <= enum_value : 100 Slp.Print <= enum_value : 5 }