absvtype
stkarray_vtype (a:vt@ype+, m:int, n:int) = ptr
We then introduce some shorthands as follows:
stadef stkarray = stkarray_vtype vtypedef stkarray (a:vt0p) = [m,n:int] stkarray_vtype (a, m, n)Given a type T, an integer M and another integer N, the type stkarray(T, M, N) is for an array-based stack such that (1) the elements stored in the stack are of type T, (2) the capacity of the stack is M, and (3) the current size of the stack is N. Clearly, M >= N and N >= 0 holds, and this property is encoded into the type of the following proof function lemma_stkarray_param:
praxi lemma_stkarray_param {a:vt0p}{m,n:int} (!stkarray (INV(a), m, n)): [m >= n; n >= 0] void // end of [lemma_stkarray_param]
As always, functions are needed for creating and destroying (linear) stkarray-values:
// fun{a:vt0p} stkarray_make_cap {m:int} (cap: size_t(m)):<!wrt> stkarray (a, m, 0) // fun stkarray_free{a:vt0p}{m:int} (stkarray (a, m, 0)):<!wrt> void //Given a size M, stkarray_make_cap creates an empty stack of capacity M. As linear elements stored in a stack are leaked after the stack is freed, the type of stkarray_free indicates that the function can only be applied to a stack containing no elements.
For inserting an element, we have the following function:
fun{a:vt0p} stkarray_insert {m,n:int | m > n} ( stk: !stkarray (a, m, n) >> stkarray (a, m, n+1), x0: a ) :<!wrt> void // endfunNote that stkarray_insert can only be called on a stack if its current size is strictly less than its capacity. The type of stkarray_insert states that the size of a stack argument is increased by 1 after an element is inserted into it.
For taking out an element, we have the following function:
fun{a:vt0p} stkarray_takeout {m,n:int | n > 0} (stk: !stkarray (a, m, n) >> stkarray (a, m, n-1)):<!wrt> (a) // end of [stkarray_takeout]Note that stkarray_takeout can only be called on a stack if its current size is positive. The type of stkarray_takeout states that the size of a stack is decreased by 1 after an element is taken out of it.
typedef struct { atstype_ptr stkarray_beg ; // the beg pointer atstype_ptr stkarray_end ; // the end pointer atstype_ref stkarray_cur ; // the current pointer } atslib_stkarray_struct ;The pointers stkarray_beg and stkarray_end point to the beginning and end of the base array while the pointer stkarray_cur points the top of the current stack. Note that the beginning of the base array is the bottom of the represented stack.
Let us introduce the folllowing two functions for getting and setting the pointer stkarray_cur:
extern fun stkarray_get_ptrcur{a:vt0p} {m,n:int} (stk: !stkarray (INV(a), m, n)):<> ptr = "mac#atslib_stkarray_get_ptrcur" extern fun stkarray_set_ptrcur{a:vt0p} {m,n:int} (stk: !stkarray (INV(a), m, n), ptr):<!wrt> void = "mac#atslib_stkarray_set_ptrcur"As can be expected, these two functions are to be implemented in C directly. The following implementation of stkarray_insert makes use of these two functions as well as an unsafe function of the name ptr0_set:
implement{a} stkarray_insert {m,n} (stk, x0) = let // val p_cur = stkarray_get_ptrcur (stk) val ((*void*)) = $UN.ptr0_set<a> (p_cur, x0) val ((*void*)) = stkarray_set_ptrcur (stk, ptr_succ<a> (p_cur)) // prval () = __assert (stk) where { extern praxi __assert (!stkarray (a, m, n) >> stkarray (a, m, n+1)): void } (* end of [prval] *) // in // nothing end // end of [stkarray_insert]Note that ptr0_set writes a value (its 2nd argument) to a given memory location (its 1st argument) without requiring a proof (of some at-view) associated with the location. In other words, ptr0_set performs a memory update precisely in the same way as it is done in C. Also note that a proof function __assert is introduced so as to make it possible for the implementation to pass typechecking. The keyword praxi means that the introduced proof function should be treated as an assertion and no implementation for it is expected.
The following implementation of stkarray_takeout makes use of ptr0_get, which reads through a given pointer without requiring a proof (of some at-view) associated with the location. Also, just like in the implementation of stkarray_insert, a proof function is asserted for the sole purpose of making the implementation of stkarray_takeout pass typechecking.
implement{a} stkarray_takeout {m,n} (stk) = x0 where { // val p_cur = stkarray_get_ptrcur (stk) val p1_cur = ptr_pred<a> (p_cur) val x0 = $UN.ptr0_get<a> (p1_cur) val () = stkarray_set_ptrcur (stk, p1_cur) // prval () = __assert (stk) where { extern praxi __assert (!stkarray (a, m, n) >> stkarray (a, m, n-1)): void } (* end of [prval] *) // } // end of [stkarray_takeout]The C code implementing stkarray_get_ptrcur and stkarray_set_ptrcur is given below:
ATSinline() atstype_ptr atslib_stkarray_get_ptrcur (atstype_ptr p) { return ((atslib_stkarray_struct*)p)->stkarray_cur ; } // end of [atslib_stkarray_get_ptrcur] ATSinline() atsvoid_t0ype atslib_stkarray_set_ptrcur (atstype_ptr p, atstype_ptr p2) { ((atslib_stkarray_struct*)p)->stkarray_cur = p2 ; return ; } // end of [atslib_stkarray_set_ptrcur]The C-names for stkarray_get_ptrcur and stkarray_set_ptrcur are chosen to be atslib_stkarray_get_ptrcur and atslib_stkarray_set_ptrcur, respectively.
For more on array-based stack implementation, please see: stkarray.sats , stkarray.dats , and stkarray.cats.
extern fun{a:vt0p} stkarray_insert_opt (stk: !stkarray (INV(a)) >> _, x0: a):<!wrt> Option_vt(a) implement{a} stkarray_insert_opt (stk, x0) = let // val isnot = stkarray_isnot_full (stk) // in // if isnot then let val () = stkarray_insert (stk, x0) in None_vt() end else Some_vt{a}(x0) // end // end of [stkarray_insert_opt]Similarly, a caller may attempt to take an element out of a stack that happens to be empty. The following function stkarray_takeout_opt returns an optional value so that its caller can tell whether an element has actually been taken out of a given stack:
extern fun{a:vt0p} stkarray_takeout_opt (stk: !stkarray (INV(a)) >> _):<!wrt> Option_vt(a) implement{a} stkarray_takeout_opt (stk) = let // val isnot = stkarray_isnot_nil (stk) // in // if isnot then let val x0 = stkarray_takeout (stk) in Some_vt{a}(x0) end else None_vt((*void*)) // end // end of [stkarray_takeout_opt]For some sample code making use of the array-based stack implementation, please see postfix_eval.dats, where an evaluator of arithmetic expressions written in the postfix-notation is coded.
This article is written by Hongwei Xi.