| 63 | | |
| 64 | | $pure $set<T> $set_with($set<T> s, T x); // s U {x} |
| 65 | | $pure $set<T> $set_without($set<T> s, T x); // s - {x} |
| 66 | | $pure $set<T> $set_union($set<T> s1, $set<T> s2); // s1 U s2 |
| 67 | | $pure $set<T> $set_difference($set<T> s1, $set<T> s2); // s1-s2 |
| 68 | | $pure $set_intersection($set<T> s1, $set<T> s2); // s1 \cap s2 |
| 69 | | $pure T[] $set_elements($set<T> s); |
| 70 | | $pure _Bool $set_isSubsetOf($set<T> s1, $set<T> s2); |
| 71 | | $pure $set<U> $set_map($set<T> s, $fun<T,U> f); |
| 72 | | |
| 73 | | |
| 74 | | Mutation functions: |
| 75 | | _Bool $set_add($set<T> * this, T x); |
| 76 | | _Bool $set_remove($set<T> * this, T x); |
| 77 | | void $set_addAll($set<T> * this, $set<T> that); |
| 78 | | void $set_removeAll($set<T> * this, $set<T> that); |
| 79 | | void $set_keepOnly($set<T> * this, $set<T> that); |
| 80 | | |
| 81 | | Sequences (arrays) |
| 82 | | ========= |
| 83 | | Expressions: |
| 84 | | a1 == a2 |
| 85 | | a[i] |
| 86 | | (T[]){ x1, ... } |
| | 63 | - `$pure $set<T> $set_with($set<T> s, T x);` // s U {x} |
| | 64 | - `$pure $set<T> $set_without($set<T> s, T x);` // s - {x} |
| | 65 | - `$pure $set<T> $set_union($set<T> s1, $set<T> s2);` // s1 U s2 |
| | 66 | - `$pure $set<T> $set_difference($set<T> s1, $set<T> s2);` // s1-s2 |
| | 67 | - `$pure $set_intersection($set<T> s1, $set<T> s2);` // s1 \cap s2 |
| | 68 | - `$pure T[] $set_elements($set<T> s);` |
| | 69 | - `$pure _Bool $set_isSubsetOf($set<T> s1, $set<T> s2);` |
| | 70 | - `$pure $set<U> $set_map($set<T> s, $fun<T,U> f);` |
| | 71 | |
| | 72 | Mutating procedures: |
| | 73 | - ` _Bool $set_add($set<T> * this, T x);` |
| | 74 | - ` _Bool $set_remove($set<T> * this, T x);` |
| | 75 | - `void $set_addAll($set<T> * this, $set<T> that);` |
| | 76 | - `void $set_removeAll($set<T> * this, $set<T> that);` |
| | 77 | - `void $set_keepOnly($set<T> * this, $set<T> that);` |
| | 78 | |
| | 79 | == Sequences (arrays) |
| | 80 | |
| | 81 | Non-mutating expressions: |
| | 82 | - `a1 == a2` |
| | 83 | - `a[i]` |
| | 84 | - `(T[]){ x1, ... }` |
| | 85 | |
| | 86 | Logic functions: |
| | 87 | - `$pure T[] $seq_fun($int len, $fun<$int,T> f);` |
| | 88 | - `$pure T[] $seq_uniform($int n, T val);` |
| | 89 | - `$pure $int $length(T[] a);` // length of a |
| | 90 | - `$pure T[] $seq_write(T[] a, int i, T x);` // a[i:=x] |
| | 91 | - `$pure T[] $seq_subseq(T[] a, int i, int n);` // a[i..i+n-1] |
| | 92 | - `$pure T[] $seq_without(T[] a, int i);` // a with position i removed |
| | 93 | - `$pure T[] $seq_with(T[] a, int i, T x);` |
| | 94 | - `$pure T[] $seq_concat(T[] a1, T[] a2);` |
| | 95 | - `$pure U[] $seq_map(T[] a, $fun<T,U> f);` |
| | 96 | - `$pure T[] $seq_filter(T[] a, $fun<T,_Bool> f);` |
| | 97 | - `$pure U $seq_foldl(T[] a, $fun<$tuple<T,U>,U> f, U init);` |
| | 98 | - `$pure U $seq_foldr(T[] a, $fun<$tuple<T,U>,U> f, U init); ` |
| | 99 | |
| | 100 | Mutating expressions: |
| | 101 | - `a[i]=x;` |
| | 102 | |
| | 103 | Mutating procedures: |
| | 104 | - `T $seq_remove(T[] * this, int i);` |
| | 105 | - `void $seq_insert(T[] * this, int i, T x);` |
| | 106 | - `void $seq_append(T[] * this, T[] that);` |
| | 107 | |
| | 108 | == Maps |
| | 109 | |
| | 110 | Non-mutating expressions: |
| | 111 | - `m1 == m2` |
| | 112 | - `($map<K,V>)$empty` |
| | 113 | - `$pure V $map_get($map<K,V> K key);` |
| | 114 | - `$pure _Bool $map_containsKey($map<K,V> map, K key);` |
| | 115 | - `$pure _Bool $map_containsValue($map<K,V> map, V val);` |
| | 116 | - `$pure $map<K,V> $map_with($map<K,V> map, K key, V val);` |
| | 117 | - `$pure $map<K,V> $map_without($map<K,V> map, K key);` |
| | 118 | - `$pure $set<K> $map_keys($map<K,V> map);` |
| | 119 | - `$pure $set<$tuple<K,V>> $map_entries($map<K,V> map);` |
| | 120 | |
| | 121 | Mutating procedures: |
| | 122 | - `V $map_put($map<K,V> * this, K key, V val);` |
| | 123 | - `V $map_remove($map<K,V> * this, K key);` |
| | 124 | - `void $map_removeAll($map<K,V> * this, $set<K> keys);` |
| | 125 | - `void $map_addAll($map<K,V> * this, $map<K,V> that);` |
| | 126 | |
| | 127 | == Functions |
| | 128 | |
| | 129 | There are two kinds of functions in PIL: |
| | 130 | 1. (Imperative) procedures |
| | 131 | 1. Logic functions |
| | 132 | |
| | 133 | === Procedures |
| | 134 | |
| | 135 | Like in C. These can be nested. Obviously they can have side-effects, be nondeterministic, and the behavior can depend on non-local state. A procedure call `f(x1,...,xn)` is an expression that can be used anywhere an expression with side-effects is allowed. Imperative procedures are not values and cannot be assigned to anything. However, as in C, a pointer to a procedure is a first-class value that can be assigned, used as an argument, returned, etc. There is a procedure type, exactly like C's function type, e.g., |
| | 136 | {{{ |
| | 137 | typedef int(int) i2i; |
| | 138 | }}} |
| | 139 | defines `i2i` to be the type "procedure consuming int and returning int". Most commonly, pointers to procedure types will be used, e.g., |
| | 140 | {{{ |
| | 141 | typedef int(int)* i2ip; |
| | 142 | }}} |
| | 143 | defines the type "pointer to procedure from int to int". As in C, a pointer to a procedure can be used in a procedure call. |
| | 144 | |
| | 145 | A procedure definition can be templated: |
| | 146 | {{{ |
| | 147 | <T1,T2,...> <procedure def> |
| | 148 | }}} |
| | 149 | This defines one procedure for each assignment of types to the Ti. |
| | 150 | |
| | 151 | === Logic functions |
| | 152 | |
| | 153 | Typically specified by a $lambda expression. These are first-class objects in PIL: they can be assigned to variables, passed as an argument in a function call (including a procedure call), and can be returned by a function. Each has a type of the form `$fun<T1,...,Tn;U>` (functions from `T1` x ... x `Tn` to `U`). They are side-effect-free. An application of a logic function `f(x1,...,xn)` is an expression that can be used anywhere an expression is allowed. A logic function is not necessarily pure, i.e., the value of an application may depend on any part of the state, not just the arguments. |
| 88 | | Built-in logic functions: |
| 89 | | $pure T[] $seq_fun($int len, $fun<$int,T> f); |
| 90 | | $pure T[] $seq_uniform($int n, T val); |
| 91 | | $pure $int $length(T[] a); // length of a |
| 92 | | $pure T[] $seq_write(T[] a, int i, T x); // a[i:=x] |
| 93 | | $pure T[] $seq_subseq(T[] a, int i, int n); // a[i..i+n-1] |
| 94 | | $pure T[] $seq_without(T[] a, int i); // a with position i removed |
| 95 | | $pure T[] $seq_with(T[] a, int i, T x); |
| 96 | | $pure T[] $seq_concat(T[] a1, T[] a2); |
| 97 | | $pure U[] $seq_map(T[] a, $fun<T,U> f); |
| 98 | | $pure T[] $seq_filter(T[] a, $fun<T,_Bool> f); |
| 99 | | $pure U $seq_foldl(T[] a, $fun<$tuple<T,U>,U> f, U init); |
| 100 | | $pure U $seq_foldr(T[] a, $fun<$tuple<T,U>,U> f, U init); |
| 101 | | |
| 102 | | Mutating operations: |
| 103 | | a[i]=x; |
| 104 | | |
| 105 | | Mutating Procedures: |
| 106 | | T $seq_remove(T[] * this, int i); |
| 107 | | void $seq_insert(T[] * this, int i, T x); |
| 108 | | void $seq_append(T[] * this, T[] that); |
| 109 | | |
| 110 | | Maps |
| 111 | | ==== |
| 112 | | Non-mutation: |
| 113 | | m1 == m2 |
| 114 | | ($map<K,V>)$empty |
| 115 | | $pure V $map_get($map<K,V> K key); |
| 116 | | $pure _Bool $map_containsKey($map<K,V> map, K key); |
| 117 | | $pure _Bool $map_containsValue($map<K,V> map, V val); |
| 118 | | $pure $map<K,V> $map_with($map<K,V> map, K key, V val); |
| 119 | | $pure $map<K,V> $map_without($map<K,V> map, K key); |
| 120 | | $pure $set<K> $map_keys($map<K,V> map); |
| 121 | | $pure $set<$tuple<K,V>> $map_entries($map<K,V> map); |
| 122 | | |
| 123 | | Mutation: |
| 124 | | V $map_put($map<K,V> * this, K key, V val); |
| 125 | | V $map_remove($map<K,V> * this, K key); |
| 126 | | void $map_removeAll($map<K,V> * this, $set<K> keys); |
| 127 | | void $map_addAll($map<K,V> * this, $map<K,V> that); |
| 128 | | |
| 129 | | Functions |
| 130 | | ========= |
| 131 | | There are two kinds of functions in PIL: |
| 132 | | |
| 133 | | 1. (Imperative) procedures, like in C. These can be nested. |
| 134 | | Obviously they can have side-effects, be nondeterministic, and |
| 135 | | the behavior can depend on non-local state. A procedure call |
| 136 | | f(x1,...,xn) is an expression that can be used anywhere an |
| 137 | | expression with side-effects is allowed. Imperative procedures |
| 138 | | are not values and cannot be assigned to anything. However, as |
| 139 | | in C, a pointer to a procedure is a first-class value that can be |
| 140 | | assigned, used as an argument, returned, etc. There is a |
| 141 | | procedure type, exactly like C's function type, e.g., |
| 142 | | |
| 143 | | typedef int(int) i2i; |
| 144 | | |
| 145 | | defines i2i to be the type "procedure consuming int and returning |
| 146 | | int". Most commonly, pointers to procedure types will be used, |
| 147 | | e.g., |
| 148 | | |
| 149 | | typedef int(int)* i2ip; |
| 150 | | |
| 151 | | defines the type "pointer to procedure from int to int". As in |
| 152 | | C, a pointer to a procedure can be used in a procedure call. |
| 153 | | |
| 154 | | A procedure definition can be templated: |
| 155 | | |
| 156 | | <T1,T2,...> <procedure def> |
| 157 | | |
| 158 | | This defines one procedure for each assignment of types to |
| 159 | | the Ti. |
| 160 | | |
| 161 | | 2. Logic functions. Typically specified by a $lambda expression. |
| 162 | | These are first-class objects in PIL: they can be assigned to |
| 163 | | variables, passed as an argument in a function call (including a |
| 164 | | procedure call), and can be returned by a function. Each has a |
| 165 | | type of the form $fun<T1,...,Tn;U> (functions from T1 x...x Tn to |
| 166 | | U). They are side-effect-free. An application of a logic |
| 167 | | function f(x1,...,xn) is an expression that can be used anywhere |
| 168 | | an expression is allowed. A logic function is not necessarily |
| 169 | | pure, i.e., the value of an application may depend on any part of |
| 170 | | the state, not just the arguments. |
| 171 | | |
| 172 | | Lambda expressions: have the form |
| 173 | | |
| | 155 | === Lambda expressions |
| | 156 | |
| | 157 | These have the form |
| | 158 | {{{ |
| 175 | | |
| 176 | | where the Ti and Uj are types, the xi and vj are variables, |
| 177 | | and expr is an expression in which the only variables that can |
| 178 | | occur free are the x1,..., xn, v1,..., vm. The initializer |
| 179 | | expressions initj are expressions using any variables in scope. |
| 180 | | The expression has type $fun<T1,...,Tn; V>, where V is the type |
| 181 | | of expr. |
| 182 | | |
| 183 | | Semantics: the lambda expression is evaluated to yield a *closure*: |
| 184 | | an ordered pair consisting of a dyscope and an expression. The |
| 185 | | dyscope has variables v1, ..., vm, initialized by evaluating init1, |
| 186 | | ..., initm. The dyscope has no parent scope, it is associated only |
| 187 | | with the closure. The expression is expr. The dyscope is destroyed |
| 188 | | whenever it becomes unreachable, i.e., whenever no part of the state |
| 189 | | is assigned the closure. |
| 190 | | |
| 191 | | A logic function application f(e1,...,en) is evaluated by first |
| 192 | | evaluating the arguments ei, then assigning the ei to the xi and |
| 193 | | evaluating expr in the closure dyscope. Note that since expr |
| 194 | | has no side effects, the values of the xi are constant. |
| 195 | | [Note: a possible change is to allow side-effects in logic |
| 196 | | functions.] |
| 197 | | |
| 198 | | Heaps |
| 199 | | ===== |
| 200 | | |
| 201 | | There is a single heap for dynamic allocation. The following |
| 202 | | built-in procedures are provided: |
| 203 | | |
| 204 | | T* $new<T>(): creates an object A of type T in heap and returns &A. |
| 205 | | |
| 206 | | T* $alloc<T>(int n): creates an array A of length n of T in heap and |
| 207 | | returns &A[0]. |
| 208 | | |
| 209 | | [Question: how to model C's malloc? Must be able to execute it |
| 210 | | without knowing T.] |
| 211 | | |
| 212 | | void $free<T>(T* p): frees the object referred to by p, the |
| 213 | | pointer returned by an earlier call to $new or $alloc. |
| 214 | | |
| 215 | | |
| 216 | | Questions |
| 217 | | how to deal with "undefined" values? |
| 218 | | |
| 219 | | can there be nondeterministic expressions, i.e., expressions that |
| 220 | | evaluate to a set of values instead of one value? |
| 221 | | |
| 222 | | how to implement C's malloc? |
| | 160 | }}} |
| | 161 | where the `Ti` and `Uj` are types, the `xi` and `vj` are variables, and `expr` is an expression in which the only variables that can occur free are the `x1`,..., `xn`, `v1`,..., `vm`. The initializer expressions `initj` are expressions using any variables in scope. The expression has type `$fun<T1,...,Tn; V>`, where `V` is the type of `expr`. |
| | 162 | |
| | 163 | ==== Semantics |
| | 164 | |
| | 165 | The lambda expression is evaluated to yield a *closure*: an ordered pair consisting of a dyscope and an expression. The dyscope has variables `v1`, ..., `vm`, initialized by evaluating `init1`, ..., `initm`. The dyscope has no parent scope, it is associated only with the closure. The expression is `expr`. The dyscope is destroyed whenever it becomes unreachable, i.e., whenever no part of the state is assigned the closure. |
| | 166 | |
| | 167 | A logic function application `f(e1,...,en)` is evaluated by first evaluating the arguments `ei`, then assigning the `ei` to the `xi` and evaluating expr in the closure dyscope. Note that since expr has no side effects, the values of the xi are constant. [Note: a possible change is to allow side-effects in logic functions.] |
| | 168 | |
| | 169 | == Heaps |
| | 170 | |
| | 171 | There is a single heap for dynamic allocation. The following built-in procedures are provided: |
| | 172 | |
| | 173 | - `T* $new<T>()`: creates an object `A` of type `T` in heap and returns `&A`. |
| | 174 | - `T* $alloc<T>(int n)`: creates an array `A` of length `n` of `T` in heap and returns `&A[0]`. |
| | 175 | - `void $free<T>(T* p)`: frees the object referred to by `p`, the pointer returned by an earlier call to `$new` or `$alloc`. |
| | 176 | |
| | 177 | |
| | 178 | == Questions |
| | 179 | |
| | 180 | * how to deal with "undefined" values? |
| | 181 | * can there be nondeterministic expressions, i.e., expressions that evaluate to a set of values instead of one value? |
| | 182 | * how to implement C's malloc? |
| | 183 | |
| | 184 | Ideas on malloc: |