Notes, Warnings and Errors¶
The compiler provides a framework for handling notes, warnings and errors as they’re encountered and created during the compilation process.
This code can be found in the dfmc-conditions library. Initial skeletal API documentation for this library can be found at The DFMC-CONDITIONS API Reference.
Conceptually, all notes, warnings and errors are subtypes of
<condition>
, so we will often refer to them collectively
as program conditions or instances of <program-condition>
.
Status of this Library¶
This library is interesting (to some) as it is in a half-completed state and many things are not yet fully implemented or used. We will try to note these things below when we discuss them.
Philosophy¶
The Open Dylan compiler tries hard not to abort compilation when an error is noted. This leads to many things that might be fatal errors elsewhere being represented as serious warnings here. For example, an undefined variable reference does not abort compilation, but if the code containing that reference is executed it causes a crash at run time.
This was part of a very exploratory development model under the Open Dylan IDE, where many errors could be corrected while an application was running.
This workflow isn’t commonly used with Dylan today, so we may revise this philosophy and how it applies to the compiler’s handling of program conditions, or at least make it configurable.
Similarly, a key element to how program conditions are currently used today is that when we store values on them, we store them as the raw object so that they’re readily accessible from within the debugger, rather than only storing the string representations.
Program Condition Hierarchy¶
The root of the condition hierarchy is <program-condition>
.
This is an abstract class and one of the subclasses such as
<program-note>
, <program-error>
or
<program-restart>
should be subclassed instead.
Reporting a Program Condition¶
The typical way to report that a program condition has arisen
is to use note
. There are other mechanisms, such as
raise
, restart
, simple-note
and simple-raise
,
but these are not in common usage.
For proper error reporting, you will want to try to report as accurate a source location as you possibly can. This can be tricky at first, so look at other similar warnings if you need the assistance.
The actual code for noting a program condition is pretty straightforward, once you’ve identified the location to emit the program condition, and the type of program condition to emit.
note(<wrong-type-in-assignment>,
variable-name: the-name,
type: binding-type,
rhs: rhs-value,
source-location: fragment-source-location(fragment));
Source Locations¶
There are a couple of useful rules to follow for getting source locations for noting a program condition during compilation.
If you’re in C-FFI, you’re probably working with fragments, and so
fragment-source-location
is the right function.If you’re in
dfmc-definitions
, then you probably also wantfragment-source-location
.If you’re in conversion, you may be dealing with either fragments or model objects. For fragments, you want
fragment-source-location
. For model objects, you wantmodel-source-location
.If you’re in
dfmc-optimization
, then you likely wantdfm-source-location
if you’re working with an object that is part of the control flow or data flow graphs, like any computation or temporary. However, in some cases, you’ll still be working with model objects, so keep an eye out for when you need to usemodel-source-location
.
Defining a new Program Condition¶
Depending on where you are defining your new program condition within the Program Condition Hierarchy, you will need to use the appropriate program condition definer:
An example definition looks like:
define program-warning <ambiguous-copy-down-method>
slot condition-method, required-init-keyword: meth:;
slot condition-other-methods, required-init-keyword: other-methods:;
format-string "Multiple applicable copy-down methods for %s, picking one at random";
format-arguments meth;
end;
An interesting thing to note here is that the other-methods are being
recorded by this <program-note>
even though they are not used
within the formatted output. This is because the additional values can
be useful when viewing the condition within the debugger or by other
programmatic processing such as filtering.
PPML, Pretty Print Markup Language¶
When conditions are stored, their slots are converted to PPML
objects. Many objects within the compiler are already configured
to be able to generate PPML via the many specializations of
as(class == <ppml>, ...)
that can be found within the
dfmc-debug-back-end
(see print-condition.dylan).
Slots are converted to PPML representations via code that
is autogenerated by the various definer macros which create
a specialization on convert-condition-slots-to-ppml
.
Filtering of Program Conditions¶
This is functionality that has not been completed and is currently not entirely in use.
To be written.
How Warnings Are Displayed and Recorded¶
To be written.
Responding to a Program Condition¶
In Dylan, the condition system allows for responses to conditions
and can restart a computation with new information. While parts
of dfmc-conditions
are designed to permit this, this functionality,
has never been completed and is not yet working.
Future Work¶
Look at cleaning up unused API and things that are no longer necessary.
obsolete-condition?
is probably obsolete.format-condition
and related code including<detail-level>
are probably no longer necessary with the code indfmc-debug-back-end
and the specialization onprint-object
present there.The specialization on
print-object
can probably go away.simple-note
andsimple-raise
can go away.There is a comment in
dfmc/conversion/convert.dylan
that the presence ofdfm-context-id
is a hack until true source locations are available. Should we removecontext-id
and the supporting code? (On a related note, does that implementation ofdfm-context-id
even work?
Complete other parts of the implementation:
Program condition filtering.
Program restarts.
Make
<program-error>
distinct from a serious warning. This would also need a change todfmc-debug-back-end
and a specialization oncondition-classification
.Use more of the various subclasses of
<program-note>
like the style, performance and portability notes. This requires getting the filtering to work.The implementation doesn’t use limited collection types where it can.
The DFMC-CONDITIONS API Reference¶
Definers for new Program Conditions¶
-
program-condition-definer
Macro¶ - Macro Call
define [modifier*] program-condition *class-name* (*superclasses*) *slot-spec* format-string *string*; format-arguments *slot*, ...; filter *filter*; end program-note;
- Parameters
modifier – One or more class adjectives. bnf
class-name – A valid Dylan class name. bnf
superclasses – One or more Dylan class names to be used as the superclasses for the newly created program condition.
slot-spec – A slot specification.
format-string – A format string valid for use with
format
.format-arguments – One or more parameters which will be passed to
format
along with the format-string. The parameter values will be drawn from the corresponding slots.filter – A Dylan expression to be used as the value for
program-note-filter
on the new class. This should either be#f
or an instance of<function>
which returns a boolean value.
- Discussion
This is not typically used outside of the
dfmc-conditions
library. It is used for creating a new direct subclass of<program-condition>
. Most often,program-note-definer
or a similar more specific definer macro would be used instead.Any additional slot specifications will be modified slightly:
The
constant
adjective will be removed if present.The type constraint for the slot will be a type union with
<ppml>
.
-
program-note-definer
Macro¶ - Macro Call
define [modifier*] program-note *class-name* *slot-spec* format-string *string*; format-arguments *slot*, ...; filter *filter*; end program-note; define [modifier*] program-note *class-name* (*superclasses*) *slot-spec* format-string *string*; format-arguments *slot*, ...; filter *filter*; end program-note;
- Discussion
Create a new
<program-note>
subclass.
-
performance-note-definer
Macro¶ - Discussion
Create a new
<performance-note>
subclass. Seeprogram-note-definer
for details.
-
portability-note-definer
Macro¶ - Discussion
Create a new
<portability-note>
subclass. Seeprogram-note-definer
for details.
-
program-error-definer
Macro¶ - Discussion
Create a new
<program-error>
subclass. Seeprogram-note-definer
for details.
-
program-restart-definer
Macro¶ - Discussion
Create a new
<program-restart>
subclass. Seeprogram-note-definer
for details.
-
program-warning-definer
Macro¶ - Discussion
Create a new
<program-warning>
subclass. Seeprogram-note-definer
for details.
-
run-time-error-warning-definer
Macro¶ - Discussion
Create a new
<run-time-error-warning>
subclass. Seeprogram-note-definer
for details.
-
serious-program-warning-definer
Macro¶ - Discussion
Create a new
<serious-program-warning>
subclass. Seeprogram-note-definer
for details.
-
style-warning-definer
Macro¶ - Discussion
Create a new
<style-warning-note>
subclass. Seeprogram-note-definer
for details.
-
program-condition-definer-definer
Macro¶ - Discussion
This is not commonly used outside of
dfmc-conditions
. It is creating new program-conditioner definer macros.
Program Conditions¶
-
<program-condition>
Open Abstract Class¶ - Superclasses
<format-string-condition>
- Init-Keywords
compilation-stage – Defaults to the value of
*current-stage*
.program-note-creator – Defaults to the value of
*current-dependent*
.source-location – Defaults to
#f
. Every effort should be made to supply a valid value for this keyword.
- Discussion
The root of the hierarchy is
<program-condition>
. All errors, warnings, etc, about code in a program being compiled should be reported as instances of this class.This class should only be used for type declarations and as the superclass for mixin properties. For instantiable classes, it’s best to subclass one of
<program-error>
,<program-note>
, or<program-restart>
instead.
-
<program-notes>
Type¶ - Supertypes
-
<program-note>
Open Primary Abstract Class¶ - Superclasses
- Init-Keywords
- Discussion
When a context-id has been supplied, this is used to give an indication of the logical context of the source that the note is about, typically to give a concise textual hint, allowing for example (where
"process-foo"
is the context-id:foo.dylan:180:Warning in process-foo: Bogus call to bar.
-
<program-error>
Open Abstract Class¶ - Superclasses
- Discussion
A
<program-error>
is a language error. Examples would be (most) syntax errors, inconsistent direct superclasses, or a reference to an undefined name.
-
<program-restart>
Open Primary Abstract Class¶ - Superclasses
- Init-Keywords
default –
- Discussion
A
<program-restart>
is a<restart>
meant to be used as part of the recovery protocol for some<program-condition>
.
-
<program-warning>
Open Abstract Class¶ - Superclasses
- Discussion
A <program-warning> is a note about something that might be a mistake in program, but the compiler is able to compile it without intervention.
-
<run-time-error-warning>
Open Abstract Class¶ - Superclasses
- Discussion
Run-time-error warnings are given when the compiler can prove that executing the code will lead definitely lead to a run-time error, whether or not that error is handled. These warnings should be hard for the user to suppress. It should be possible for a user to treat these warnings as errors; that is, stop the compilation process because of one.
-
<serious-program-warning>
Open Abstract Class¶ - Superclasses
-
<style-warning>
Open Abstract Class¶ - Superclasses
- Discussion
Style warnings are given when the compiler detects code in a style that is legal (strictly speaking), but not desirable. The display of style warnings can be inhibited globally, or on a class-by-class basis.
-
<performance-note>
Open Abstract Class¶ - Superclasses
- Discussion
Performance notes are given when the compiler is prevented from doing an optimization that should be reasonable or expected in the current context. Typical reasons would be that it has insufficient type, sealing, or program flow information.
-
<portability-note>
Open Abstract Class¶ - Superclasses
- Discussion
Portability notes are given when the compiler detects something that is valid in the Open Dylan compiler, but is not part of portable Dylan or could have undefined effects in Dylan.
It should be possible to turn these warnings into errors, to support a standards-conforming version of the compiler.
Program Condition Slots¶
-
condition-compilation-stage
Generic function¶ - Signature
condition-compilation-stage (object) => (value)
- Parameters
object – An instance of
<program-condition>
.
- Values
value – An instance of
<object>
.
-
condition-context-id
Generic function¶ - Signature
condition-context-id (object) => (value)
- Parameters
object – An instance of
<program-note>
.
- Values
value – An instance of
<object>
.
-
condition-program-note-creator
Generic function¶ - Signature
condition-program-note-creator (object) => (value)
- Parameters
object – An instance of
<program-condition>
.
- Values
value – An instance of
<object>
.
-
condition-source-location
Generic function¶ - Signature
condition-source-location (object) => (value)
- Parameters
object – An instance of
<program-condition>
.
- Values
value – An instance of
<object>
.
Signaling Program Conditions¶
-
note
Open Generic function¶ - Signature
note (class #key #all-keys) => ()
- Parameters
class – An instance of
subclass(<program-condition>)
.
- Discussion
The primary program condition signaling interface is
note
, which callsmake
on the condition class and signals it, possibly returning. It can be used for any program condition, but is mainly oriented towards<program-note>
.- Example
note(<inaccessible-open-definition>, binding: form-variable-binding(form), source-location: form-source-location(form));
-
note(subclass(<program-condition>))
Method¶
-
maybe-note
Macro¶
-
raise
Open Generic function¶ - Signature
raise (class #key #all-keys) => ()
- Parameters
class – An instance of
subclass(<program-condition>)
.
- Discussion
This function is analogous to the standard Dylan
error
function and is guaranteed to not return.
-
raise(subclass(<program-error>))
Method¶
-
restart
Open Generic function¶ - Signature
restart (class #key #all-keys) => ()
- Parameters
class – An instance of
subclass(<program-restart>)
.
-
restart(subclass(<program-restart>))
Method¶
Preserving Program Conditions¶
Program conditions are tracked in each library. They are stored in
a table that is associated with each <library-description>
via library-conditions-table
. There are implementations of
another generic function, remove-dependent-program-conditions
which is commonly invoked during retraction. (What retraction
is for isn’t clear to me at this point.)
-
add-program-condition
Generic function¶ - Signature
add-program-condition (condition) => ()
- Parameters
condition – An instance of
<condition>
.
- Discussion
Records a program condition. This does not usually need to be invoked directly outside of
dfmc-conditions
where it is usually invoked during the filtering of a program condition.
-
add-program-condition(<condition>)
Method¶ - Discussion
Runtime errors that are not
<program-condition>
are not currently tracked. This method doesn’t record them.
-
add-program-condition(<program-condition>)
Method¶ - Discussion
Preserves a program condition by storing it in the
library-conditions-table
for the current library being compiled.
Subnotes¶
This is a very rarely used capability within the program condition system and isn’t currently well supported by the compiler output to standard out and standard error.
Any <program-note>
can have additional notes attached to it.
These notes are useful for attaching extra data to a note, like possible
options or the sets of conflicting items.
An example usage of subnotes is:
note(<ambiguous-copy-down-method>,
meth: m,
other-methods: others,
source-location: m.model-source-location,
subnotes: map(method (m)
make(<ambiguous-copy-down-method-option>,
meth: m,
source-location: m.model-source-location)
end,
others));
Note
Subnotes are not displayed by the default printing of
program conditions by the command line compiler. They can be
found in the condition log file that is created during the
build process. (_build/build/foo/foo.log
)
-
subnotes
Generic function¶ - Signature
subnotes (object) => (value)
- Parameters
object – An instance of
<program-note>
.
- Values
value – An instance of
<program-notes>
.
-
note-during
Macro¶
-
accumulate-subnotes-during
Macro¶
-
*subnotes-queue*
Thread Variable¶
Printing Program Conditions¶
-
*detail-level*
Thread Variable¶ - Type
- Discussion
Note
This is currently ignored.
-
<detail-level>
Type¶ - Equivalent
one-of(#"terse", #"normal", #"verbose")
- Discussion
A simple, three-tiered approach to the amount of detail a condition presents.
Note
This is currently ignored.
- Operations
-
format-condition
Generic function¶ - Signature
format-condition (stream condition detail-level) => ()
- Parameters
stream – An instance of
<stream>
.condition – An instance of
<program-condition>
.detail-level – An instance of
<detail-level>
.
- Discussion
This calls
format
to write to thestream
. The format string and arguments come from the condition’scondition-format-string
andcondition-format-arguments
respectively.
-
print-object(<program-condition>, <stream>)
Method¶ - Signature
print-object (condition, stream) => ()
- Parameters
condition – An instance of
<program-condition>
.stream – An instance of
<stream>
.
- Discussion
This calls
format-condition
with a detail-level of#"terse"
.This is provided for integrating program condition printing with the usual mechanisms for formatted output.
Note
This is not actually called often at all as there is a more specific specialization on
<program-note>
defined indfmc-debug-back-end
.
Unclassified API¶
-
$record-program-note
Constant¶
-
$signal-program-error
Function¶ - Signature
$signal-program-error (c) => ()
- Parameters
c – An instance of
<condition>
.
-
$signal-program-note
Function¶ - Signature
$signal-program-note (c) => ()
- Parameters
c – An instance of
<condition>
.
-
<ignore-serious-note>
Class¶ - Superclasses
- Init-Keywords
format-string –
note –
-
<program-note-filter>
Constant¶
-
convert-condition-slots-to-ppml
Generic function¶ - Signature
convert-condition-slots-to-ppml (condition) => ()
- Parameters
condition – An instance of
<condition>
.
- Discussion
Converts all slots on a condition to their PPML representation. This is typically autogenerated by the various program condition definer macros. It is called from
add-program-condition
.
-
convert-condition-slots-to-ppml(<condition>)
Method¶
-
convert-condition-slots-to-ppml(type-union(<simple-condition>, <simple-error>, <simple-warning>))
Method¶
-
convert-condition-slots-to-ppml(<program-note>)
Method¶
-
convert-condition-slots-to-ppml(<program-restart>)
Method¶
-
convert-condition-slots-to-ppml(<program-warning>)
Method¶
-
convert-condition-slots-to-ppml(<serious-program-warning>)
Method¶
-
convert-condition-slots-to-ppml(<program-error>)
Method¶
-
convert-condition-slots-to-ppml(<run-time-error-warning>)
Method¶
-
convert-condition-slots-to-ppml(<style-warning>)
Method¶
-
convert-condition-slots-to-ppml(<performance-note>)
Method¶
-
convert-condition-slots-to-ppml(<portability-note>)
Method¶
-
convert-condition-slots-to-ppml(<ignore-serious-note>)
Method¶
-
convert-slots-to-ppml
Macro¶
-
dfmc-continue
Thread Variable¶
-
dfmc-restart
Thread Variable¶
-
do-with-program-conditions
Function¶
-
interesting-note?
Generic function¶ - Signature
interesting-note? (note) => (interesting?)
- Parameters
note – An instance of
<program-note>
.
- Values
interesting? – An instance of
<boolean>
.
- Discussion
True if the note is interesting to the user, according to the yet-to-be-defined compiler policy object. Uninteresting conditions are suppressed, either by not printing messages for them or not logging them at all. Because all errors and restarts are serious, they are also interesting.
-
interesting-note?(<program-note>)
Method¶ - Parameters
note – An instance of
<program-note>
.
- Values
interesting? – Always returns
#t
.
-
interesting-note?(<performance-note>)
Method¶ - Parameters
note – An instance of
<performance-note>
.
- Values
interesting? – Always returns
#f
.
-
make-program-note-filter
Generic function¶ - Signature
make-program-note-filter (#key file-name from to in class action) => (filter)
- Parameters
file-name (#key) – An instance of
<string>
.from (#key) – An instance of
<integer>
.to (#key) – An instance of
<integer>
.in (#key) – An instance of
<string>
.class (#key) – An instance of
subclass(<condition>)
.action (#key) – An instance of
<function>
.
- Values
filter – An instance of
<program-note-filter>
.
-
obsolete-condition?
Open Generic function¶ - Signature
obsolete-condition? (condition) => (obsolete?)
- Parameters
condition – An instance of
<program-condition>
.
- Values
obsolete? – An instance of
<boolean>
.
-
obsolete-condition?(<program-condition>)
Method¶ - Parameters
condition – An instance of
<program-condition>
.
- Values
obsolete? – Always returns
#f
.
- Discussion
Note
This is never used.
-
present-program-error
Generic function¶ - Signature
present-program-error (condition) => ()
- Parameters
condition – An instance of
<condition>
.
-
present-program-error(<condition>)
Method¶
-
present-program-error(<program-note>)
Method¶
-
present-program-note
Generic function¶ - Signature
present-program-note (condition) => ()
- Parameters
condition – An instance of
<condition>
.
-
present-program-note(<condition>)
Method¶
-
present-program-note(<program-note>)
Method¶
-
program-note-class-=
Function¶ - Signature
program-note-class-= (class) => (pred)
- Parameters
class – An instance of
subclass(<condition>)
.
- Values
pred – An instance of
<function>
.
-
program-note-file-name-=
Function¶ - Signature
program-note-file-name-= (file-name) => (pred)
- Parameters
file-name – An instance of
<string>
.
- Values
pred – An instance of
<function>
.
-
program-note-filter
Open Generic function¶ - Signature
program-note-filter (class) => (filter)
- Parameters
class – An instance of
subclass(<condition>)
.
- Values
filter – An instance of
<program-note-filter>
.
-
program-note-filter(subclass(<program-note>))
Method¶
-
program-note-filter(subclass(<condition>))
Method¶
-
program-note-filter(subclass(<program-warning>))
Method¶
-
program-note-filter(subclass(<serious-program-warning>))
Method¶
-
program-note-filter(subclass(<run-time-error-warning>))
Method¶
-
program-note-filter(subclass(<style-warning>))
Method¶
-
program-note-filter(subclass(<performance-note>))
Method¶
-
program-note-filter(subclass(<portability-note>))
Method¶
-
program-note-filter-setter
Open Generic function¶ - Signature
program-note-filter-setter (filter class) => (filter)
- Parameters
filter – An instance of
<program-note-filter>
.class – An instance of
subclass(<program-condition>)
.
- Values
filter – An instance of
<program-note-filter>
.
-
program-note-filter-setter(<program-note-filter>, subclass(<program-condition>))
Method¶
-
program-note-in
Function¶ - Signature
program-note-in (form) => (pred)
- Parameters
form – An instance of
<string>
.
- Values
pred – An instance of
<function>
.
-
program-note-location-between
Function¶ - Signature
program-note-location-between (from to) => (pred)
- Parameters
- Values
pred – An instance of
<function>
.
-
report-condition
Open Generic function¶ - Signature
report-condition (condition) => ()
- Parameters
condition – An instance of
<condition>
.
-
serious-note?
Generic function¶ - Signature
serious-note? (note) => (serious?)
- Parameters
note – An instance of
<program-note>
.
- Values
serious? – An instance of
<boolean>
.
- Discussion
True if this note is serious – that is, requires terminating the current processing and picking a restart. The default behavior is that notes are not serious, but the policy object should allow upgrading them, with options like “all warnings are errors” for making
<program-warning>
serious, or “strict Dylan” for making<portability-note>
serious.Errors are always serious, by definition, because the compiler can’t just skip them. Restarts are always serious, as much as such a definition make sense for them.
-
serious-note?(<program-note>)
Method¶ - Parameters
note – An instance of
<program-note>
.
- Values
serious? – Always returns
#f
.
-
serious-note?(<program-error>)
Method¶ - Parameters
note – An instance of
<program-error>
.
- Values
serious? – Always returns
#t
.
-
serious-note?(<serious-program-warning>)
Method¶ - Parameters
note – An instance of
<serious-program-warning>
.
- Values
serious? – Always returns
#t
.
-
simple-note
Generic function¶
-
simple-raise
Generic function¶
-
with-program-conditions
Macro¶
-
with-simple-abort-retry-restart
Macro¶