1 2 3 4 5 6 7 8
9
10 11 12 13
14
15 /*!
16 * ======== Assert ========
17 * Runtime assertion manager
18 *
19 * The `Assert` module provides configurable diagnostics to the program.
20 * Similar to the standard C `assert()` macro, `Assert` methods are
21 * interspersed with other code to add diagnostics to a program. Unlike
22 * the standard C assert support, the `Assert` module provides greater
23 * flexibility in managing the messages displayed, the message string
24 * space overhead, and the runtime handling of failures. In addition,
25 * because the `Assert` methods build atop the Diags module, you can
26 * precisely control which asserts remain in the final application, if any.
27 *
28 * The `Assert` module works in conjunction with the `{@link Diags}` module.
29 * `Assert` statements are added to the code using the
30 * `{@link #isTrue Assert_isTrue()}` function. Execution of assert
31 * statements is controlled by the `{@link Diags#ASSERT}` and
32 * `{@link Diags#INTERNAL}` bits in a module's diagnostics mask. By default,
33 * all module's `Diags_ASSERT` bit is enabled and the `Diags_INTERNAL` bit
34 * is disabled. See `{@link Types#Common$ Types.Common$}` for the
35 * declaration of the bits in the diagnostics mask and
36 * `{@link Defaults#common$ Default.common$}` for the default module settings.
37 *
38 * Two types of asserts are supported: public asserts and internal asserts.
39 *
40 * @p(blist)
41 * - Public asserts have an assert ID and are, by default, controlled
42 * by the `{@link Diags#ASSERT}` bit.
43 * - Internal asserts don't have an assert ID (other than NULL) and
44 * are active only when both the `{@link Diags#ASSERT}` and
45 * `{@link Diags#INTERNAL}` bits of the module's diagnostics mask are set.
46 * @p
47 *
48 * `Assert` IDs are small integer values that index into a table of
49 * assertion descriptors. These descriptors hold an error message
50 * and a diagnostics mask that is used to enable and disable the
51 * assertion at runtime.
52 *
53 * You can remap individual public asserts to different bits in the
54 * diagnostics mask, or can disable the assert altogether. This is
55 * done by setting the mask property of the assert ID. Setting the
56 * mask to 0 disables the assert. In all other cases, the `Diags.ASSERT`
57 * bit is OR'd together with the mask to define the controlling bits.
58 * For example, the module's diagnostics mask must have the `Diags.ASSERT`
59 * bit set and any other bit specified in the mask property of the
60 * assert ID in order to activate the assert.
61 *
62 * @a(Examples)
63 * Example 1: The following C code adds an assert to application code
64 * which is not in a module. This assert does not have an assert
65 * identifier (the second argument is NULL); this makes it an internal
66 * assert.
67 *
68 * @p(code)
69 * // file.c
70 * #include <xdc/runtime/Assert.h>
71 *
72 * Assert_isTrue(count > 0, NULL);
73 * @p
74 *
75 * The following XDC configuration statements set both the ASSERT and
76 * INTERNAL bits in the diagnostics mask to enable the internal assert
77 * created in the previous C code. Since the C code is not in a module,
78 * you must set the bits in the diagnostics mask of the
79 * `{@link xdc.runtime.Main xdc.runtime.Main}` module. The Main module
80 * is used to control all `{@link Log}` and `Assert` statements that are
81 * not part of the implementation of a module; for example, top-level
82 * application code or any existing sources that simply call the `Log` or
83 * `Assert` methods.
84 *
85 * @p(code)
86 * // program.cfg
87 * var Assert = xdc.useModule('xdc.runtime.Assert');
88 * var Diags = xdc.useModule('xdc.runtime.Diags');
89 * var Main = xdc.useModule('xdc.runtime.Main');
90 *
91 * Main.common$.diags_ASSERT = Diags.ALWAYS_ON;
92 * Main.common$.diags_INTERNAL = Diags.ALWAYS_ON;
93 * @p
94 *
95 * @p(html)
96 * <hr />
97 * @p
98 *
99 * Example 2: The following example shows how to use and configure an
100 * assert ID that is declared by a module. It adds that assert to the
101 * application's C source code, and configures the application to
102 * execute the assert.
103 *
104 * This is part of the XDC file for the module that declares an `Assert` Id:
105 *
106 * @p(code)
107 * // Mod.xdc
108 * import xdc.runtime.Assert;
109 * import xdc.runtime.Diags;
110 *
111 * config Assert.Id A_nonZero = {
112 * msg: "A_nonZero: value must be non-zero"
113 * };
114 * @p
115 *
116 * This is part of the C code for the application:
117 *
118 * @p(code)
119 * // Mod.c
120 * #include <xdc/runtime/Assert.h>
121 *
122 * Assert_isTrue(x != 0, Mod_A_nonZero);
123 * @p
124 *
125 * This is part of the XDC configuration file for the application:
126 *
127 * @p(code)
128 * // program.cfg
129 * var Diags = xdc.useModule('xdc.runtime.Diags');
130 * var Mod = xdc.useModule('my.pkg.Mod');
131 * Mod.common$.diags_ASSERT = Diags.ALWAYS_ON;
132 * @p
133 */
134
135 @CustomHeader
136
137 module Assert {
138
139 /*!
140 * ======== Assert_Desc ========
141 * Assert descriptor
142 *
143 * Each public assert is defined with an assert descriptor. This
144 * structure defines which bits in the module's diagnostics mask
145 * control this assert, and the message raised when the assert fails.
146 * The mask property is optional, it defaults to the
147 * `{@link Diags#ASSERT}` bit.
148 *
149 * @field(mask) Specifies which bits enable the assert.
150 * @field(msg) The message printed when the assert fails.
151 */
152 metaonly struct Desc {
153 Diags.Mask mask;
154 String msg;
155 };
156
157 /*!
158 * ======== Assert_Id ========
159 * Assert identifier
160 *
161 * Each metaonly assert descriptor is encoded into a target accessable
162 * assert Id type which can be passed to the `{@link #isTrue}` function.
163 */
164 @Encoded typedef Desc Id;
165
166 /*!
167 * ======== E_assertFailed ========
168 * The `{@link Error#Id}` raised when an assertion violation is detected
169 *
170 * When an assertion violation is triggered, an error is raised via
171 * `Error_raise()`. `E_assert_Failed` is the `{@link Error#Id}` passed
172 * to `Error_raise()`.
173 *
174 * The first string argument (%s) will be either "", if the assertion Id
175 * is `NULL` (for internal asserts), or ": " (for public asserts).
176 * The second string argument (%s) is the
177 * `Assert.Desc.msg` string associated with the assertion Id; if the
178 * Id is `NULL` (an internal assert) or if text is not loaded
179 * (`!{@link Text#isLoaded}()`), this string is "".
180 *
181 * @see #isTrue
182 * @see Error#Id
183 */
184 readonly config Error.Id E_assertFailed = {msg: "assertion failure%s%s"};
185
186 /*!
187 * ======== Assert_isTrue ========
188 * Test an assertion
189 *
190 * `Assert_isTrue()` statements may be conditionally enabled (disabled)
191 * on a per module basis by setting the calling module's
192 * `{@link IModule#$common $common.diags_ASSERT}` configuration
193 * parameter. If
194 * the `Assert_isTrue()` statement is not in a module, the calling
195 * module is the `{@link Main}` module. You must enable the
196 * `{@link Diags#ASSERT}` bit in the module's diagnostics mask for this
197 * call to be enabled. If a `NULL` assert id is specified, then you
198 * must enable the `{@link Diags#INTERNAL}` in addition to the
199 * `ASSERT` bit.
200 *
201 * If the `Assert_isTrue()` statement is enabled and `expr` evaluates to
202 * false, the assert specified by `id` is raised; i.e., the
203 * `{@link E_assertFailed}` error is raised with a `NULL` error block.
204 * In other words, the standard `{@link Error#raise}` handling hooks will
205 * be run, `{@link System#abort()}` will be called, and control does not
206 * return to the caller. The `id` may be `null`, in which case you will
207 * get a generic assert message.
208 *
209 * @param(expr) the expression which should evaluate to true
210 * @param(id) identifies the assert being raised
211 *
212 * @a(Examples)
213 * C Code
214 * @p(code)
215 * #include <xdc/runtime/Assert.h>
216 *
217 * Assert_isTrue(count > 0, NULL);
218 * @p
219 */
220 @Macro Void isTrue(Bool expr, Id id);
221
222 internal:
223
224 Void raise(Types.ModuleId mod, String file, Int line, Id id);
225
226 }
227 228 229
230