Skip to content

Commit 44aa7dd

Browse files
committed
fixed markdown notation in RAP9
1 parent 584dec7 commit 44aa7dd

File tree

1 file changed

+56
-45
lines changed
  • courses/RascalAmendmentProposals/RAP9

1 file changed

+56
-45
lines changed

courses/RascalAmendmentProposals/RAP9/RAP9.md

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -12,40 +12,48 @@ sidebar_position: 9
1212

1313
## Abstract
1414

15-
Proposal to merge the (open-ended) data-types for Rascal exceptions, Java exceptions, error messages, assert failures and test results into a single common representation.
15+
Proposal to merge the (open-ended) data-types for:
16+
* Rascal exceptions,
17+
* Java exceptions,
18+
* error messages,
19+
* assert failures, and
20+
* test results,
1621

17-
The representation features a cause tree, source locations, context parameters and user-friendly messages. This new representation can be used to \`throw\` exceptions, collect static error messages and warnings, and report on test results. All in the same unified manner.
22+
into a single common representation.
23+
24+
The representation features a cause tree, source locations, context parameters and user-friendly messages. This new representation can be used to `throw` exceptions, collect static error messages and warnings, and report on test results. All in the same unified manner.
1825

1926
Different back-end tools can be reused based on this shared representation, such as UI (error panes, highlights, stack traces) and analysis (root cause analysis, statistical debugging).
2027

2128
## Motivation
2229

23-
Exceptions are modeled as values in Rascal. In the standard library we have a common data-type called \`RuntimeException\` for them. A special kind of exception is reserved for assertion failures. Then we have \`Message\` to represent errors (info, warning, error, fatal), and we have test results (hidden inside the quick check feature). Finally normal Java exceptions also play an important role in our runtime which are now all mapped to the \`Java(str message)\` Exception constructor.
30+
Exceptions are modeled as values in Rascal. In the standard library we have a common data-type called `RuntimeException` for them. A special kind of exception is reserved for assertion failures. Then we have `Message` to represent errors (info, warning, error, fatal), and we have test results (hidden inside the quick check feature). Finally normal Java exceptions also play an important role in our runtime which are now all mapped to the `Java(str message)` Exception constructor.
2431

2532
These formats all share characteristics:
2633

2734
* They are an intermediate representation between some thing that happened and its reporting in the UI;
2835
* They each require user reporting, causal tracing and analysis;
29-
* They are all \`open\` ended, in the sense that many types of exceptions, errors and test results will exist which can not be thought of in advance.
36+
* They are all _open-ended_, in the sense that many types of exceptions, errors and test results will exist which can not be thought of in advance.
3037

3138
In the interest of simplicity and reuse (of representation, of analysis and of UI components), we can unify these representations into a single data-type. This will remove unnecessary code from different kinds of tools and enable newbies to start off with something that has everything they needed before they even thought of it.
3239

3340
## Specification
3441

35-
data Severity \= info() | warning() | error() | fatal();
42+
```
43+
data Severity = info() | warning() | error() | fatal();
3644
3745
@synopsis{An event is something to throw or report which has a severity, a source location, a cause, and a user-friendly message. Events kinds are modelled using an open-ended set of constructors of the data-type Event}
3846
data Event(
39-
Severity severity \= info(),
40-
loc src \= |unknown:|,
41-
Event cause \= root(),
42-
str message \= “”
47+
Severity severity = info(),
48+
loc src = |unknown:|,
49+
Event cause = root(),
50+
str message = “”
4351
);
4452
4553
@synopsis{Events can be composed using boolean logic to explain their causes}
4654
data Event
47-
\= and(list\[Event\] causes) // all these causes are required to produce the event
48-
| or(list\[Event\] causes) // either one of these caused were required
55+
= and(list[Event] causes) // all these causes are required to produce the event
56+
| or(list[Event] causes) // either one of these caused were required
4957
| root() // this is the root cause of the event
5058
| not(Event cause) // the absence of this event caused the event
5159
;
@@ -55,16 +63,16 @@ data Event
5563
5664
@synopsis{Events to model stack traces}
5765
data Event
58-
\= methodCall(str class, str name, severity=info())
66+
= methodCall(str class, str name, severity=info())
5967
| functionCall(str module, str name, severity=info())
6068
| mainCall(str class)
6169
| staticInit(str class)
6270
;
6371
6472
@synopsis{Events to model test results and assertion results, with their causes.}
6573
data Event
66-
\= testFailure(str name, map\[str, value\] parameters, Severity severity=error())
67-
| testSuccess(str name, map\[str, value\] parameters, Severity severity=info())
74+
= testFailure(str name, map[str, value] parameters, Severity severity=error())
75+
| testSuccess(str name, map[str, value] parameters, Severity severity=info())
6876
| assertFailed(Severity severity=error())
6977
| assertSucceeded(Severity severity=info())
7078
| expectedEqual(value lhs, value rhs)
@@ -75,69 +83,72 @@ data Event
7583
7684
@synopsis{Events to model static errors and warnings}
7785
data Event
78-
\= unexpectedType(Type got, Type expected, Severity severity=error())
86+
= unexpectedType(Type got, Type expected, Severity severity=error())
7987
| undeclaredName(str name, Severity=error())
80-
; /\* etc \*/
88+
; /* etc */
8189
8290
@synopsis{Events to model run-time errors}
8391
data Event
84-
\= matchFailed(Severity severity=warning())
92+
= matchFailed(Severity severity=warning())
8593
| divisionByZero(Severity severity=error())
8694
| permissionDenied(Severity severity=error())
87-
; /\* etc \*/
95+
; /* etc */
96+
```
8897

8998
1. a “stack trace” is modeled via the “cause” of an event.
90-
1. The \`throw\` statement, when confronted with an expression of sub-type \`node\`, will re-ify the stack by adding to the\`causes\` field to the element \`functionCall(...)\` that is the current function with its current parameters.
91-
1. If the Event thrown already has user-defined causes, then these are kept as conjunctive causes. For example if the current throw is part of a catch block, the programmer might link the caught Event into the current Event by setting: \`catch Event caughtEvent: { throw newEvent(cause=caughtEvent\`); }\`
99+
1. The `throw` statement, when confronted with an expression of sub-type `node`, will re-ify the stack by adding to the`causes` field to the element `functionCall(...)` that is the current function with its current parameters.
100+
1. If the Event thrown already has user-defined causes, then these are kept as conjunctive causes. For example if the current throw is part of a catch block, the programmer might link the caught Event into the current Event by setting: `catch Event caughtEvent: { throw newEvent(cause=caughtEvent`); }`
92101
2. Every functionCall on the causes chain has its own singleton cause, namely its own caller.
93-
3. \`throw\` will also generate the \`src\` location of itself into the Event, and also annotate functionCall and methodCall values with this information where possible.
94-
4. the causes of test failure may be the \`expected\*\` events or an exception thrown during the execution of the test, or both.
102+
3. `throw` will also generate the `src` location of itself into the Event, and also annotate functionCall and methodCall values with this information where possible.
103+
4. the causes of test failure may be the `expected*` events or an exception thrown during the execution of the test, or both.
95104
2. static error messages may be caused by observations or inferences from the source code rather than run-time events.
96105
1. The Event data-type may wrap arbitrary complex symbols to represent the results of name and type analysis which are relevant to explain an error message.
97-
2. The \`not\` event can be used that some errors are caused by the absence of something rather than the presence. For example: \`not(subTypeOf(x, y))\` explains that an error is caused by a required event (x being a subtype of y) has not happened.
98-
3. Errors may also be linked in this way, and repeated errors can be cleaned up if they are caused by other errors, to prevent spamming the user. This clean up can be done generically based on a list of Event’s rather than the checker having to manage these dependencies explicitly. All the checker has to do is to record meticulously what causes every error.
99-
3. The standard attributes of \`Events\` can be produced by automatically \`throw\` but also programmatically provided (e.g. by a type checker or test runner). This makes no difference for the downstream processing of Events.
100-
4. We have to rewrite all existing Messages, Exceptions and test result representations
106+
2. The `not` event can be used that some errors are caused by the absence of something rather than the presence. For example: `not(subTypeOf(x, y))` explains that an error is caused by a required event (x being a subtype of y) has not happened.
107+
3. Errors may also be linked in this way, and repeated errors can be cleaned up if they are caused by other errors, to prevent spamming the user. This clean up can be done generically based on a list of Event’s rather than the checker having to manage these dependencies explicitly. All the checker has to do is to record meticulously what causes every error. See Phd thesis of Bastiaan Heeren.
108+
3. The standard attributes of `Events` can be produced by automatically `throw` but also programmatically provided (e.g. by a type checker or test runner). This makes no difference for the downstream processing of Events.
109+
4. We would rewrite all existing Messages, Exceptions and test result representations
101110
1. Declarations in Message, Exception
102111
2. Representations in QuickCheck
103112
5. Java exceptions are modeled as constructors of Event as well. If not known in advance they are declared and generated at run-time using Java reflection.
104113
1. the name of the event constructor being the simple name of the Java Throwable class: e.getClass().getSimpleName().
105-
2. the message set to \`e.getMessage()\`
106-
3. the causes set to top of the stack-trace, recursively to be represented by \`methodCall\` Event constructors
107-
4. The Java \`getCause()\` if not \`null\` is a conjunctive cause of the top exception, so if that exists a Java exception will have both a stacktrace of its own, and another exception as causes.
114+
2. the message set to `e.getMessage()`
115+
3. the causes set to top of the stack-trace, recursively to be represented by `methodCall` Event constructors
116+
4. The Java `getCause()` if not `null` is a conjunctive cause of the top exception, so if that exists a Java exception will have both a stacktrace of its own, and another exception as causes.
108117

109118
## Examples
110119

111-
data Event \= insufficientGiniDatapoints(str message=”The Gini coefficient requires at least three datapoints to make sense”); // default keyword parameter links event kind to user-friendly message
120+
```
121+
data Event = insufficientGiniDatapoints(str message=”The Gini coefficient requires at least three datapoints to make sense”); // default keyword parameter links event kind to user-friendly message
112122
113-
int giniCoefficient(list\[num\] data) {
114-
if (size(data) \<= 2\)
123+
int giniCoefficient(list[num] data) {
124+
if (size(data) <= 2\)
115125
throw insufficientGiniDatapoints(); // throw fills in causality (trace, location)
116126
117127
}
118128
119-
data Event \= failedTodo(str title, str message=”the task \<title\> failed to complete”);
129+
data Event = failedTodo(str title, str message=”the task <title\> failed to complete”);
120130
121-
void process(list\[TODO\] x) {
122-
for (t \<- todo) {
131+
void process(list[TODO] x) {
132+
for (t <- todo) {
123133
try {
124134
t.task();
125135
}
126136
catch Event e : {
127-
throw failedTodo(t.title, causes=\[e\]); // link the cause and the stack trace
137+
throw failedTodo(t.title, causes=[e]); // link the cause and the stack trace
128138
}
129139
}
130140
}
131141
132-
data Event \= unexpectedType(str exp, Type actual, Type expected, Severity=error(), str message=”\<exp\> requires parameters of type \<expected\>, but we have a \<actual\> here.” );
133-
list\[Event\] typecheck(Program p) \= \[\*check(ast) | /Expression ast := p\];
134-
list\[Event\] check(add(Exp l, Exp r)) \= \[unexpectedType(“addition”, l.type, \\int(), src=l.src\]
142+
data Event = unexpectedType(str exp, Type actual, Type expected, Severity=error(), str message=”<exp\> requires parameters of type <expected\>, but we have a <actual\> here.” );
143+
list[Event] typecheck(Program p) = [*check(ast) | /Expression ast := p];
144+
list[Event] check(add(Exp l, Exp r)) = [unexpectedType(“addition”, l.type, \int(), src=l.src]
135145
when l.type \!= int();
136-
default list\[Event\] check(Expression e) \= \[\];
146+
default list[Event] check(Expression e) = [];
147+
```
137148

138149
## Backwards Compatibility
139150

140-
1. Code which used produced the Message datatype or threw exceptions of the \`Exception\` data-type will have to be reviewed and modified
151+
1. Code which used produced the Message datatype or threw exceptions of the `Exception` data-type will have to be reviewed and modified
141152
1. TypePal will need to be adapted to generate Events rather than Messages
142153
2. We have to move user-friendly messages to the declaration sites of error kinds.
143154
2. UI facing components, such as Eclipse support and LSP support will have to be adapted.
@@ -146,15 +157,15 @@ default list\[Event\] check(Expression e) \= \[\];
146157
## Implementation
147158

148159
* Code generated for the throw statement needs changing
149-
* Code generated for \`java\` methods needs to be wrapped with a try-catch, such that the stack trace can be reified as \`methodCall\` events, and the exception can be modeled as a new constructor of Event using reflection. E.g:
160+
* Code generated for `java` methods needs to be wrapped with a try-catch, such that the stack trace can be reified as `methodCall` events, and the exception can be modeled as a new constructor of Event using reflection. E.g:
150161
* catch (Throwable e) {
151-
* C \= tf.constructor(Event, e.getClass().getSimpleName());
162+
* C = tf.constructor(Event, e.getClass().getSimpleName());
152163
* throw vf.constructor(C).setParameter(“causes”, …);
153164
* }
154165
* Reifing the stack trace as Event::methodCall and Event::functionCall IConstructors may be quite an expensive operation.
155166
* It could be worth the trouble to implement IConstructor again especially for these two constructors, and let them wrap a JVM exception trace for on-demand reification.
156-
* And lazily produce the next wrapper for their \`causes\` on request (i.e. lazily implementing \`getParamer\` or \`getField\`)
157-
* Possibly a generic \`*LazyConstructor* class *implements* *IConstructor\`* could be added to Vallang which would take Producer\<IValue\> as constructor parameters rather than IValues directly, and a \`*LazyKeywordParameterWrapper implements IWithKeywordParameters\`*, likewise would take Producer\<IValue\> lambda’s.
167+
* And lazily produce the next wrapper for their `causes` on request (i.e. lazily implementing `getParamer` or `getField`)
168+
* Possibly a generic `*LazyConstructor* class *implements* *IConstructor`* could be added to Vallang which would take Producer<IValue\> as constructor parameters rather than IValues directly, and a `*LazyKeywordParameterWrapper implements IWithKeywordParameters`*, likewise would take Producer<IValue\> lambda’s.
158169
* There is no way I know of to retrieve method parameter values from Java stack traces; except:
159170
* [https://github.com/cretz/stackparam](https://github.com/cretz/stackparam)
160171
* Java 10 came with a new stack trace API:

0 commit comments

Comments
 (0)