Age | Commit message (Collapse) | Author |
|
Previously, inserting the variable bindings would make the Oasn
nodes appear before the decl nodes in a block.
Signed-off-by: Mura Li <mural@ctli.io>
|
|
When we have a match statement such as
match x
| `std.Some _ || _:
;;
the order of the patterns `std.seom _ and _ matters.
before the fix, we would get false positive of "pattern
matched by earlier case".
Signed-off-by: Mura Li <mural@ctli.io>
|
|
There could be more than one frontiers for each match arm.
Signed-off-by: Mura Li <mural@ctli.io>
|
|
|
|
Previously, the identifier with the same name in two disjunctive
patterns (aka or-patterns) must be bound to the exactly same location.
For instance,
(x, _) || (x, _) /* ok */
(_, y) || (_, y) /* ok */
(x, _) || (_, x) /* not ok */
In certain Standard ML implementations, it's allowed to write a pattern like
(x, _) || (_, x)
where x is bound to different locations as long as they have the same type.
This patch removes the restriction.
Signed-off-by: Mura Li <mural@ctli.io>
|
|
|
|
|
|
|
|
|
|
|
|
Also, improve slightly the error messages.
|
|
|
|
|
|
(Tested on Linux/AMD64)
Sample count: 506
Dtree Refcnt avg: 5.38 95th percentile: 3.00 maximum: 100
Dtree Size avg: 5.23 95th percentile: 3.00 maximum: 84
Dtree Height avg: 1.39 95th percentile: 1.00 maximum: 12
References:
Mikael Pettersson. A term pattern-match compiler inspired by finite automata
theory. (p.6 "Step 3: Optimizing the DFA")
|
|
|
|
References:
"When Do Match-Compilation Heuristics Matter?" by Kevin Scott and Norman Ramsey
Stats:
Sample count: 506
Dtree Size avg: 5.38 95th percentile: 3.00 maximum: 100
Dtree Height avg: 1.39 95th percentile: 1.00 maximum: 12
Sample generation:
$ MATCH_STATS=1 make bootstrap && mbld -R support/matchstats.myr ./match.csv
|
|
Shrink node sizes, simplify code a bit.
|
|
We tried to be too smart, and we made bugs. let's do it simpler.
|
|
This reverts commit beab0276a94c684f938ae5ea3d2c29c3dc331386.
|
|
|
|
This patch adds tuple access expressions. If t is a tuple, its
N-th component can be retrieved with the syntax t.N. Of course,
the components are zero indexed. I believe the code also works
if 't' is a pointer to a tuple (but I have not checked this).
|
|
|
|
We were overly aggressive in unifying wildcards.
|
|
Hello Myrddin folks,
The current code to handle auto expressions does not correctly
deal with complex values (i.e., values that do not fit in a
register). This patch attempts to fix the issue.
-- Quentin
|
|
Oops.
|
|
|
|
|
|
|
|
|
|
Summary:
--------
During the Myrcon in September Ori suggested an 'auto' operator
that would evaluate what it applies to, store the result in a
temporary t, and call __dispose__(t) when the current block exits.
This patch implements this idea under the form of a unary
operator. This, for instance, allows to have:
impl disposable regex# =
__dispose__ = {r; regex.free(r)}
;;
regex.exec(auto std.try(regex.compile("f..bar")), "foobar")
Like before, it is guaranteed that __dispose__ is called in
reverse order of auto appearance.
Backward compatibility:
-----------------------
Nope. Auto variables are now gone. This should not be a problem,
simply rewrite:
var auto x = foo()
into:
var x = auto foo()
Implementation:
---------------
It largely reuses the code I had written for 'auto' variables
but needs a little finer grain tracking because we don't always
want to call __dispose__ for *all* auto expression results when
leaving a block (some might not be evaluated yet).
For example:
auto 1
if b
-> void
;;
auto 2
Only __dispose__(1) must be called when '-> void' is executed.
If the block falls through, __dispose__(2) and __dispose__(1)
will be called in sequence.
TODO:
-----
- Err when goto jumps in/out of a block that has auto
expressions.
- Support auto in patterns.
match ...
| `std.Some (auto x): ...
is essentially rewritten to:
match ...
| `std.Some (auto x):
auto x
...
- Test edge cases (e.g., auto in loop condition)
Actually, test.
Cheers,
|
|
|
|
|
|
|
|
This happens with externs.
|
|
Fixes #159
|
|
Ugh. Edge cases.
|
|
|
|
|
|
Hello,
I wrote this patch to start a conversation about resource
management in Myrddin.
~ Introduction
~~~~~~~~~~~~~~
The patch attached provides a hopefully life-improving and
surely non-invasive mechanism to handle resources that have
block-limited lifetimes: automatic variables.
This resource-management scheme can be found in multiple
languages today. For example, C++ calls destructors
automatically at the end of the scope of a variable;
similarly, Rust automatically calls user-defined code
when a variable's scope ends; finally, also related is
Go's defer statement which ensures that resource-releasing
code is called at the end of a function.
~ Description
~~~~~~~~~~~~~
The idea is that every "binder" of the language (var/const/
fn args/match) offers the possibility to mark the variables
it binds as "automatic" using the 'auto' keyword.
An automatic variable must be of a type that implements
the new builtin 'disposable' trait below. When the scope
of a variable 'v' marked as automatic ends, '__dispose__(v)'
is called.
That's it.
trait disposable @a =
__dispose__ : (val : @a -> void)
;;
~ Example Programs
~~~~~~~~~~~~~~~~~~
The language modification is shown in action in the program
below.
use std
impl disposable int =
__dispose__ = {x
std.put("__dispose__({})\n", x)
}
;;
const g = {auto x
-> x++ - 1
}
const main = {
var auto i, auto j = 42
for i = 1; i < 6; i=i+1
var auto z : int = 2*i
if i == 3
std.put("z = {} -- cont\n", z)
continue
;;
std.put("z = {}\n", z)
if i/2 == 2
var auto inner : int = 1234
break
;;
;;
i = g(321)
}
The output of the previous test program is:
1: z = 2
2: __dispose__(2)
3: z = 4
4: __dispose__(4)
5: z = 6 -- cont
6: __dispose__(6)
7: z = 8
8: __dispose__(1234)
9: __dispose__(8)
10: __dispose__(322)
11: __dispose__(42)
12: __dispose__(320)
Some important remarks:
* Unlike Go, __dispose__ is called as soon as the scope
of a variable ends, not at the end of the function.
In particular, the variable 'z' in the example is
always disposed of before starting the next iteration.
(An iteration ends the loop body block.)
* __dispose__ is called in reverse order of declaration
This allows variables to depend on resources of
variables already in scope.
* Regardless of how a block is exited (fallthrough,
break, continue, return), variables of the blocks left
are disposed of in reverse order and exactly once.
* As line 10 of the output shows, the __dispose__ calls
happen "after" the return statement of the function.
(It happens after the post-increment, so x's value
when it is disposed of is 322.)
The following example shows that, using an ad hoc type,
it is possible to execute arbitrary code at the end of
a scope.
type defer = (-> void)
impl disposable defer =
__dispose__ = {f: defer; f()}
;;
const foobar = {...
const auto _dummy = ({
std.put("Bye!\n")
}: defer)
...
}
~ Discussion
~~~~~~~~~~~~
Multiple alternatives exist for resource management, and
hopefully this mail starts an interesting debate.
According to me, here are the pros and cons of the current
proposal:
- PROS -
* Opt-in
* Backward compatible
* Simple
* The spirit of C's original auto
* It has an implementation
- CONS -
* No safety guarantees/compiler checks whatsoever
* Syntactic pollution: 'auto' keyword, 'disposable' trait
Finally, note that the current patch does not implement
auto support for variables bound in match statements.
This will come in a followup patch if there is sufficient
interest. Also, the patch does not provide proper support
(or proper errors) for gotos and labels.
|
|
|
|
|
|
A monster function declaration and if condition.
|
|
|
|
These are prototype declarations that must be implemented by the impl (not
necessarily functions), so proto seems like a better name.
|
|
|
|
|
|
Fixes #70
|
|
|
|
We were draining the postinc queue before the rval. Oops.
|
|
|