-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DSL for module semantics #32
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, thanks! I have some comments, see below.
spectec/spec/1-syntax.watsup
Outdated
@@ -57,7 +57,7 @@ syntax resulttype hint(desc "result type") = | |||
valtype* | |||
|
|||
syntax limits hint(desc "limits") = | |||
`[u32 .. u32] | |||
`[u32 .. u32?] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, I dropped the option on purpose, since I figured it's simpler to just desugar an empty upper bound into 2^32-1 in the AST.
spectec/spec/6-reduction.watsup
Outdated
-- if $table(z, x) = ti | ||
-- if $grow_table(ti, n, ref) = ti' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-- if $table(z, x) = ti | |
-- if $grow_table(ti, n, ref) = ti' | |
-- if $grow_table($table(z, x), n, ref) = ti' |
spectec/spec/6-reduction.watsup
Outdated
z; ref (CONST I32 n) (TABLE.GROW x) ~> $with_tableinst(z, x, ti'); (CONST I32 $(|$table(z, x).ELEM|)) | ||
-- if $table(z, x) = ti | ||
-- if $grow_table(ti, n, ref) = ti' | ||
-- Tabletype_ok: |- ti'.TYPE : OK |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This condition should probably be moved to $grow_table, such that that becomes a self-contained abstraction.
spectec/spec/6-reduction.watsup
Outdated
-- if $mem(z, 0) = mi | ||
-- if $grow_memory(mi, n) = mi' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-- if $mem(z, 0) = mi | |
-- if $grow_memory(mi, n) = mi' | |
-- if $grow_memory($mem(z, 0), n) = mi' |
spectec/spec/6-reduction.watsup
Outdated
z; (CONST I32 n) (MEMORY.GROW) ~> $with_meminst(z, 0, mi'); (CONST I32 $(|$mem(z, 0).DATA| / (64 * $Ki))) | ||
-- if $mem(z, 0) = mi | ||
-- if $grow_memory(mi, n) = mi' | ||
-- Memtype_ok: |- mi'.TYPE : OK |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment as above.
spectec/spec/7-module.watsup
Outdated
-- if elem = ELEM reftype expr* elemmode | ||
-- if n = |expr*| | ||
-- if elemmode = TABLE x instr* | ||
-- Step : s; f; instr* (CONST I32 0) (CONST I32 n) (TABLE.INIT x i) (ELEM.DROP i) ~> s_new; f_new; epsilon |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh. The run functions are supposed to be auxiliary functions that produce a program to run (i.e., desugar active segments), not actually execute the instructions.
spectec/spec/7-module.watsup
Outdated
-- if $run_data((s_elem; f_elem), data*, 0) = s_res; f_res | ||
|
||
def $instantiation(s, module, externval*) = (s_res, m) | ||
-- if module = MODULE import* func* global* table* mem* elem* data* start export* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we avoid duplicating the definition? Why would the approach from the spec not work?
spectec/spec/7-module.watsup
Outdated
|
||
;; Instantiation | ||
|
||
def $instantiation(store, module, externval*) : (store, moduleinst) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, the instantiate (and similarly invoke) functions in the spec are meant to macro-expand into an actual instruction sequence, which then can be reduced separately by the usual means. This definition seems to be interleave expansion and execution and couple them together, which I'd rather like to avoid.
spectec/spec/7-module.watsup
Outdated
-- if m_res = $alloc_import(m_new, import'*, externval'*) | ||
|
||
|
||
def $alloc_func(state, func*) : (store, funcaddr*) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and below we are conflating the allocx functions with the allocx* liftings. Could we keep them separate? In particular, for the Latex spec, we will only want to include the allocx ones, and not write out each of the others.
spectec/spec/7-module.watsup
Outdated
-- if m_ex = m_im ++ { FUNC fa*, GLOBAL ga*, TABLE ta*, MEM ma*, ELEM ea*, DATA da*, EXPORT epsilon } | ||
-- if xi* = $alloc_export(m_ex, export)* | ||
-- if m_res = m_ex[.EXPORT = xi*] | ||
-- if s_res = $replace_moduleinst(s_data, fa*, m_res) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see why you did it this way, but now the alloc_module functions is not actually allocating one module instance, but an arbitrary number of them. Can we change this so that there is only one module instance being created in the end?
Also, Conrad suggested we can avoid resorting to mutating immutable parts of the store and instead break the cycle by precomputing the function addresses and the module instance before creating the function instances.
Co-authored-by: Andreas Rossberg <[email protected]>
Co-authored-by: Andreas Rossberg <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I refined the module semantics. To reflect the aforementioned comments, I extended the DSL (you can see the detailed explanation below). This change requires updating the EL parser, IL validation and other components, and we're planning to update them. Before that, I'd like to know whether the updated DSL looks good enough.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm implementing this in dsl branch. It might be helpful to see the implementation to understand the extended syntax.
spectec/spec/7-module.watsup
Outdated
def $funcs(externval*) = [fa|FUNC fa <- externval] | ||
def $globals(externval*) = [ga|GLOBAL ga <- externval] | ||
def $tables(externval*) = [ta|TABLE ta <- externval] | ||
def $mems(externval*) = [ma|MEM ma <- externval] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the syntax in 236de04.
def $funcs(externval*) = `[fa|FUNC fa <- externval]
def $globals(externval*) = `[ga|GLOBAL ga <- externval]
def $tables(externval*) = `[ta|TABLE ta <- externval]
def $mems(externval*) = `[ma|MEM ma <- externval]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense, though extending the DSL may be quite a cost for a one-off auxiliary definition like this. Let's perhaps discuss this on Thursday.
spectec/spec/7-module.watsup
Outdated
-- if ta* = |s.TABLE| ... $(|s.TABLE| + |table*| - 1) | ||
-- if ma* = |s.MEM| ... $(|s.MEM| + |mem*| - 1) | ||
-- if ea* = |s.ELEM| ... $(|s.ELEM| + |elem*| - 1) | ||
-- if da* = |s.DATA| ... $(|s.DATA| + |data*| - 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest new syntax for range to precomputing the addresses.
For example, 0 ... 5
means 0 1 2 3 4 5
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this perhaps be expressed by an auxiliary function?
def $range(nat_1, nat_2) : nat* hint(show %...%)
def $range(n_1, n_2) = epsilon -- if n_1 > n_2
def $range(n_1, n_2) = n_1 $range(n_1+1, n_2) -- otherwise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the idea. I'll reflect it.
spectec/spec/7-module.watsup
Outdated
-- if s_3 = s_2[.TABLE =.. $alloctable(tabletype)*] | ||
-- if s_4 = s_3[.MEM =.. $allocmem(memtype)*] | ||
-- if s_5 = s_4[.ELEM =.. $allocelem(rt, ref*)*] | ||
-- if s_6 = s_5[.DATA =.. $allocdata(byte*)*] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now, we don't need allocx* liftings.
But we can use allocx* liftings, if you want.
def $allocfunc(store, moduleinst, func) : store
def $allocfunc(s, m, func) = s[.FUNC =.. fi]
-- if fi = { MODULE m, CODE func }
def $allocfunc*(store, moduleinst, func*) : store
def $allocfunc*(s, m, epsilon) = s
def $allocfunc*(s, m, func func'*) = $allocfunc*($allocfunc(s, m, func), m, func'*)
...
def $allocmodule(store, module, externval*, val*, (ref*)*) : (store, moduleinst)
def $allocmodule(s, module, externval*, val*, (ref*)*) = (s_6, m)
...
-- if s_1 = $allocfunc*(s, m, func*)
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The alloc functions are meant as an abstraction that encapsulates allocation (and they are used in other places, specifically, the embedding interface in the appendix). The formulation you suggest, while cute, would be problematic in that sense, because then these functions no longer actually allocate.
So I'd go with the liftings for now. (You probably need to name them without the star and make that a show-hint.)
Mid-term I'd like to revamp the module representation into a linear list of declaration that is processed sequentially. Then this mess should go away.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a few questions related to the comments you made:
- To avoid mutation, we decided to precompute the addresses before allocation. As a result, the alloc functions no longer return address. Is it acceptable to return store only?
- In the spec, the allocx lifting is defined for arbitrary object kinds, but DSL doesn't allow it. So I define a lifting function for each of the alloc functions. Is this approach acceptable?
- You mentioned that it is necessary to name the lifting functions without a star. If we remove the star, the name of lifting function would be the same as the name of allocation function. To ensure distinct names, would it be appropriate to use the name
allocfuncs
for the lifting function? - I didn't fully understand the sentence: "Mid-term I'd like to revamp the module representation into a linear list of declaration that is processed sequentially." Could you provide further clarification on its meaning?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re 1: Well, if you rephrase "precompute" as "predict", then no change to the allocation functions is necessary, I believe.
Re 2: Yes, defining a function for each type is fine for the DSL. We can probably still tweak it to produce a single template in the Latex output.
Re 3: allocfuncs
sounds good to me.
Re 4: With some of the future extensions, module checking and instantiation becomes more sequential, with ordered dependencies between declarations. Also, there are ideas for allowing multiple appearances of section types, so that the order of different sorts of declarations can be mixed. So I would like to refactor modules to be more like a sequence of different declarations that is processed in order, which would also eliminate the specific iterations. I still have to work out the details, though, in particular wrt instantiation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your kind reply!
spectec/spec/7-module.watsup
Outdated
|
||
def $instantiation(store, module, externval*) : config | ||
def $instantiation(s, module, externval*) = | ||
s'; f; ...$runelem(elem*[i], i)* ...$rundata(data*[j], j)* (CALL x)? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need range for runelem
and rundata
.
Here, i*
is a range 0 ... $(n-1)
, so $runelem(elem*[i], i)*
means $runelem(elem*[0], 0) ... $runelem(elem*[$(n-1)]), $(n-1))
where n = |elem*|
.
However, type of $runelem(..)
is instr*
, so type of $runelem(..)*
is instr**
.
Therefore, it requires new syntax for flattening.
...$runelem(..)*
notation stands for kind of flattening which comes from JavaScript syntax spread.
Alternatively, we can use notations from Scala or Python
Scala repeated parameters: $runelem(..):_*
Python unpacking: *($runelem(..)*)
Rather than using *-notation, we can also use syntax similar to the spec
$runelem(elem*[0], 0) ... $runelem(elem*[$(n-1)], $(n-1))
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, at this point I wonder if we shouldn't have a version of iteration with an index variable, e.g., exp^(i<n)
. Then this could be expressed as
(runelem_(i, elem))^(i<n)
when given elem^n
. But maybe that's going too far?
Note that the spec also defines an auxiliary concat
operator for flattening (see here).
A monomorphic version of that can already be defined in the DSL. For example, this works:
def $concat(nat**) : nat*
def $concat(epsilon) = epsilon
def $concat(n* n'**) = n* $concat(n'**)
def $f(nat) : nat*
def $f(n) = n n n
def $g(nat*) : nat*
def $g(n*) = $concat($f(n)*) $concat($f(n)*)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, Thanks for the ideas! I'll reflect them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also use iteration with an index to express the range
For example, fa* = $range(|s.FUNC|, $(|s.FUNC| + |func*| - 1))
can be replaced by fa* = $(|s.FUNC| + i)^(i<n)
where n
is |func*|
.
I think it is more compact.
I updated module-semantics, filter with recursive version. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks mostly good, module nits. However, I would suggest minor refactorings of the new AST node:
-
Instead of a separate IndexedListN, have single
ListN of exp * id option
. That avoids repeating the logic for the exponent. -
Introduce the same in the EL and disambiguate the syntax in the parser.
@@ -762,7 +766,7 @@ and elab_exp_notation' env e t : Il.exp list = | |||
| (EpsE | SeqE _), IterT (t1, iter) -> | |||
[elab_exp_notation_iter env (unseq_exp e) (t1, iter) t e.at] | |||
| IterE (e1, iter1), IterT (t1, iter) -> | |||
if (iter = Opt) <> (iter1 = Opt) then | |||
if (iter = Opt) && (iter1 <> Opt) then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this change needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def $instantiation(s, module, externval*) = s'; f; instr_elem* instr_data* (CALL x)?
...
This is instantiation function in DSL.
In this context, (CALL x)?
should be interpreted as admininstr*
, which can either be epsilon
(empty) or have a length of one.
So, it is intended to allow the optional iterative expression to have a list iteration type.
spectec/src/frontend/elab.ml
Outdated
| ListN e -> | ||
match e.it with | ||
| ParenE ({ it = CmpE ({ it = VarE id; _ }, LtOp, e); _}, _) -> | ||
Il.IndexedListN (id, elab_exp env e (NatT $ e.at)) | ||
| _ -> Il.ListN (elab_exp env e (NatT $ e.at)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest we introduce an IndexedListN constructor in the EL as well and disambiguate in the parser already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comments. I have a few questions.
- I want to check whether I understand correctly. As I understand, EL should include both
ListN of id
andIndexedListN of exp * id
, while IL should only haveListN of exp * id option
. Is it correct? - To have both
ListN
andIndexedListN
in EL,
iter :
| QUEST { Opt }
| PLUS { List1 }
| STAR { List }
| UP arith_prim
{ match $2.it with
| ParenE ({ it = CmpE({ it = VarE id; _ }, LtOp, e); _}, false) ->
IndexedListN (e, id)
| _ -> ListN $2
}
is it enough for parser code, or do I have to refactor parsing the iter
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, sorry for the confusion, I wrote this comment about IndexedListN in EL before I arrived at the other. I'd prefer both to use ListN of exp * id option
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see.
However, I believe pattern matching is still necessary to obtain id information if we do not intend to refactor the parser.
iter :
| QUEST { Opt }
| PLUS { List1 }
| STAR { List }
| UP arith_prim
{ match $2.it with
| ParenE ({ it = CmpE({ it = VarE id; _ }, LtOp, e); _}, false) ->
ListN (e, Some id)
| _ -> ListN ($2, None)
}
Is this pattern matching seems okay?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's fine with me.
spectec/src/il/validation.ml
Outdated
| IndexedListN _ | ||
| ListN _ -> List |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| IndexedListN _ | |
| ListN _ -> List | |
| ListN _ | IndexedListN _ -> List |
spectec/src/backend-latex/render.ml
Outdated
@@ -694,6 +694,16 @@ let render_conditions env = function | |||
" &\\quad\n " ^ word "if" ^ "~" ^ | |||
concat_map_nl " \\\\\n &&&&\\quad {\\land}~" "" (render_prem env) prems | |||
|
|||
let render_func_conditions env = function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only difference between this function and render_red_conditions seems to be the number of tabs to insert. Instead of duplicating the entire definition, can we perhaps make tab string ("&&&" vs "&&&&") a parameter?
I reflected your comments! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I have mostly nits, but I think there are few things missing around checking the iteration variable.
spectec/src/il/free.ml
Outdated
| ListN (e, None) -> free_exp e | ||
| ListN (e, Some id) -> | ||
union (free_exp e) (free_varid id) | ||
| ListN (e, _) -> free_exp e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't his be
| ListN (e, _) -> free_exp e | |
| ListN (e, id_opt) → union (free_exp e) (free_opt free_varid id_opt) |
spectec/src/frontend/multiplicity.ml
Outdated
|
||
(match iter' with | ||
| ListN (_, Some id) -> | ||
assert (List.length ids' = 1 && id.it = (List.hd ids').it) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand this assertion. Why can't there be any other ids in that case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is because I would like to block the use of "iter with index" like this:
def $foo() : nat
def $foo() = 0
-- if x* = 0 1 2
-- if (x*[i] = y)^(i<3)
If you think we should allow semantics like this, I will remove the assertion.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I follow, what problem do you see with that example? In Shouldn't using them for indexing be one of the primary use cases for iter vars?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I apologize for not providing sufficient explanation earlier.
My intention was to use 'iter with index' in a way that restricts iteration on variables other than the index variable.
However, upon further consideration, I realized that 'iter with index' merely introduces an index for iteration, so there shouldn't be such a restriction. I'll erase the assertion.
spectec/src/frontend/multiplicity.ml
Outdated
@@ -163,13 +162,9 @@ let union = Env.union (fun _ ctx1 ctx2 -> assert (ctx1 = ctx2); Some ctx1) | |||
let rec annot_iter env iter : Il.Ast.iter * occur = | |||
match iter with | |||
| Opt | List | List1 -> iter, Env.empty | |||
| ListN (e, None) -> | |||
| ListN (e, opt) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit:
| ListN (e, opt) -> | |
| ListN (e, id_opt) -> |
Also, I believe this needs to check that the variable has the right type.
spectec/src/frontend/multiplicity.ml
Outdated
let e', occur1 = annot_exp env e in | ||
let occur2 = Env.singleton id.it (Env.find id.it env) in | ||
ListN (e', Some id), union occur1 occur2 | ||
ListN (e', opt), occur |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ListN (e', opt), occur | |
ListN (e', id_opt), occur |
spectec/src/frontend/multiplicity.ml
Outdated
@@ -68,8 +68,7 @@ let iter_nl_list f xs = List.iter (function Nl -> () | Elem x -> f x) xs | |||
let rec check_iter env ctx iter = | |||
match iter with | |||
| Opt | List | List1 -> () | |||
| ListN (e, opt) -> | |||
Option.iter (fun id -> check_id env ctx id) opt; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we still need this check?
spectec/src/il/validation.ml
Outdated
let iter' = | ||
match fst iter with | ||
| ListN _ -> List | ||
| iter' -> iter' | ||
in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: I think you can undo the reformatting now.
spectec/src/middlend/sub.ml
Outdated
@@ -119,7 +119,7 @@ and t_exp' env = function | |||
| SubE (e, t1, t2) -> SubE (e, t1, t2) | |||
|
|||
and t_iter env = function | |||
| ListN e -> ListN (t_exp env e) | |||
| ListN (e, id) -> ListN (t_exp env e, id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ListN (e, id) -> ListN (t_exp env e, id) | |
| ListN (e, id_opt) -> ListN (t_exp env e, id_opt) |
spectec/src/middlend/totalize.ml
Outdated
@@ -78,7 +78,7 @@ and t_exp' env = function | |||
| SubE (e, t1, t2) -> SubE (e, t1, t2) | |||
|
|||
and t_iter env = function | |||
| ListN e -> ListN (t_exp env e) | |||
| ListN (e, id) -> ListN (t_exp env e, id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ListN (e, id) -> ListN (t_exp env e, id) | |
| ListN (e, id_opt) -> ListN (t_exp env e, id_opt) |
spectec/src/middlend/unthe.ml
Outdated
@@ -156,7 +156,7 @@ and t_iterexp n (iter, vs) = | |||
unary t_iter n iter (fun iter' -> (iter', vs)) | |||
|
|||
and t_iter n iter = match iter with | |||
| ListN e -> unary t_exp n e (fun e' -> ListN e') | |||
| ListN (e, id) -> unary t_exp n e (fun e' -> ListN (e', id)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ListN (e, id) -> unary t_exp n e (fun e' -> ListN (e', id)) | |
| ListN (e, id_opt) -> unary t_exp n e (fun e' -> ListN (e', id_opt)) |
spectec/src/middlend/wild.ml
Outdated
@@ -180,7 +180,7 @@ and t_iterexp env (iter, vs) = | |||
unary t_iter env iter (fun iter' -> (iter', vs)) | |||
|
|||
and t_iter env iter = match iter with | |||
| ListN e -> unary t_exp env e (fun e' -> ListN e') | |||
| ListN (e, id) -> unary t_exp env e (fun e' -> ListN (e', id)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ListN (e, id) -> unary t_exp env e (fun e' -> ListN (e', id)) | |
| ListN (e, id_opt) -> unary t_exp env e (fun e' -> ListN (e', id_opt)) |
I introduced a check for the 'iter with index.' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Now that you mention it, I think no iteration variables should occur in any variable dimension. They are not part of the "dimension type". I believe this means that in multiplicity.ml:
- check_iter needs to strip the variable, like you suggest
- both check_exp and check_prem also need to strip any variable from the iter that they add to the ctx list in the cases of IterE and IterPr,
- the equality assertion in annot_iterexp must strip iter before comparing it.
And in il/validation.ml:
- in valid_iter the iter must be stripped before comparing to dim
Perhaps some other places I am missing?
spectec/src/el/print.ml
Outdated
@@ -71,8 +71,7 @@ let rec string_of_iter iter = | |||
| List -> "*" | |||
| List1 -> "+" | |||
| ListN (e, None) -> "^" ^ string_of_exp e | |||
| ListN (e, Some (id)) -> | |||
"^(" ^ id.it ^ "<" ^ string_of_exp e ^ ")" | |||
| ListN (e, Some (id)) -> "^(" ^ id.it ^ "<" ^ string_of_exp e ^ ")" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed this nit before:
| ListN (e, Some (id)) -> "^(" ^ id.it ^ "<" ^ string_of_exp e ^ ")" | |
| ListN (e, Some id) -> "^(" ^ id.it ^ "<" ^ string_of_exp e ^ ")" |
spectec/src/frontend/multiplicity.ml
Outdated
| ListN (e, opt) -> | ||
Option.iter (fun id -> check_id env (iter::ctx) id) opt; | ||
check_exp env ctx e |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ListN (e, opt) -> | |
Option.iter (fun id -> check_id env (iter::ctx) id) opt; | |
check_exp env ctx e | |
| ListN (e, id_opt) -> | |
Option.iter (fun id -> check_id env (ListN (e, None) :: ctx) id) id_opt; | |
check_exp env ctx e |
spectec/src/frontend/multiplicity.ml
Outdated
| ListN (e, None) -> | ||
let e', occur = annot_exp env e in | ||
ListN (e', opt), occur | ||
ListN (e', None), occur | ||
| ListN (e, Some id) -> | ||
let e', occur1 = annot_exp env e in | ||
let occur2 = Env.singleton id.it [] in | ||
ListN (e', Some id), union occur1 occur2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| ListN (e, None) -> | |
let e', occur = annot_exp env e in | |
ListN (e', opt), occur | |
ListN (e', None), occur | |
| ListN (e, Some id) -> | |
let e', occur1 = annot_exp env e in | |
let occur2 = Env.singleton id.it [] in | |
ListN (e', Some id), union occur1 occur2 | |
| ListN (e, id_opt) -> | |
let e', occur1 = annot_exp env e in | |
let occur2 = | |
match id_opt with None -> Env.empty | Some id -> Env.singleton id.it [] in | |
ListN (e', id_opt), union occur1 occur2 |
spectec/src/frontend/multiplicity.ml
Outdated
|
||
(match iter' with | ||
| ListN (_, Some id) -> | ||
assert (List.length ids' = 1 && id.it = (List.hd ids').it) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I follow, what problem do you see with that example? In Shouldn't using them for indexing be one of the primary use cases for iter vars?
spectec/src/frontend/elab.ml
Outdated
@@ -336,7 +336,7 @@ let rec elab_iter env iter : Il.iter = | |||
| Opt -> Il.Opt | |||
| List -> Il.List | |||
| List1 -> Il.List1 | |||
| ListN (e, opt) -> Il.ListN (elab_exp env e (NatT $ e.at), opt) | |||
| ListN (e, id_opt) -> Il.ListN (elab_exp env e (NatT $ e.at), id_opt) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also needs to check the type of the id.
spectec/src/frontend/elab.ml
Outdated
| ListN (e, id_opt) -> | ||
Option.iter (fun id -> | ||
let t = find "variable" env.vars (prefix_id id) in | ||
if (t.it <> NatT) then error_typ e.at "iteration index" (NatT $ e.at) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I add type check for index variable.
However, there is no region information of index, the error prints the wrong region.
@@ -160,16 +164,18 @@ type occur = Il.Ast.iter list Env.t | |||
let union = Env.union (fun _ ctx1 ctx2 -> assert (ctx1 = ctx2); Some ctx1) | |||
|
|||
|
|||
let strip_index = function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be defined twice in this module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I defined strip_index
for both El and Il. Would it better to use distinct names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, sorry, missed that. It's fine then.
spectec/src/frontend/multiplicity.ml
Outdated
@@ -286,16 +292,12 @@ and annot_iterexp env occur1 (iter, ids) at : Il.Ast.iterexp * occur = | |||
Env.filter_map (fun _ iters -> | |||
match iters with | |||
| [] -> None | |||
| iter1::iters' -> assert (Il.Eq.eq_iter iter iter1); Some iters' | |||
| iter1::iters' -> | |||
assert (Il.Eq.eq_iter (strip_index iter) iter1); Some iters' | |||
) occur1 | |||
in | |||
let ids' = List.map (fun (x, _) -> x $ at) (Env.bindings occur1') in | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
spectec/src/il/validation.ml
Outdated
@@ -241,15 +241,7 @@ let valid_list valid_x_y env xs ys at = | |||
let rec valid_iter env iter = | |||
match iter with | |||
| Opt | List | List1 -> () | |||
| ListN (e, None) -> valid_exp env e (NatT $ e.at) | |||
| ListN (e, Some id) -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you still need to validate the id here, see comment below.
spectec/src/il/validation.ml
Outdated
@@ -478,6 +470,11 @@ and valid_path env p t : typ = | |||
t' | |||
|
|||
and valid_iterexp env (iter, ids) : env = | |||
let iter = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, sorry for not being clearer. We still need to validate the variable. We only need to strip it for the purpose of the eq_iter check below. Because this combination should be legal:
(...x...)^n (...x...)^(i<n)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I see. I've fixed it.
Thanks for the comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can we name this iter' to avoid confusion?
Co-authored-by: Andreas Rossberg <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, modulo the two comments below. Thanks!
spectec/src/il/validation.ml
Outdated
@@ -478,6 +470,11 @@ and valid_path env p t : typ = | |||
t' | |||
|
|||
and valid_iterexp env (iter, ids) : env = | |||
let iter = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: can we name this iter' to avoid confusion?
Co-authored-by: Andreas Rossberg <[email protected]>
@ShinWonho, I fixed a couple of bugs in the multiplicity annotation and the renderer backend that I had overlooked during the code review. However, the bigger issue I really only noticed now is that the index variable is completely ignored in all the middlend phases. Who will implement this? Or is the plan to have a pass that eliminates the variable first? |
My naive thought was that introducing 'iter with index' wouldn't affect the middle-end phases. |
Merge with upstream/`wasm-3.0+exn`
DSL for module semantics.
This PR depends on #30