2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/templates/cexcept.h Fri Oct 28 22:58:50 2016 +0200
2.3 @@ -0,0 +1,251 @@
2.4 +/*===
2.5 +cexcept.h 2.0.1-Lichen (2016-Oct-27-Thu)
2.6 +A modified form of...
2.7 +cexcept.h 2.0.1 (2008-Jul-19-Sat)
2.8 +http://www.nicemice.net/cexcept/
2.9 +Adam M. Costello
2.10 +http://www.nicemice.net/amc/
2.11 +
2.12 +An interface for exception-handling in ANSI C (C89 and subsequent ISO
2.13 +standards), developed jointly with Cosmin Truta.
2.14 +
2.15 + Copyright (c) 2000-2008 Adam M. Costello and Cosmin Truta.
2.16 + Copyright (c) 2016 Paul Boddie (modified for Lichen).
2.17 + This software may be modified only if its author and version
2.18 + information is updated accurately, and may be redistributed
2.19 + only if accompanied by this unaltered notice. Subject to those
2.20 + restrictions, permission is granted to anyone to do anything
2.21 + with this software. The copyright holders make no guarantees
2.22 + regarding this software, and are not responsible for any damage
2.23 + resulting from its use.
2.24 +
2.25 +The cexcept interface is not compatible with and cannot interact
2.26 +with system exceptions (like division by zero or memory segmentation
2.27 +violation), compiler-generated exceptions (like C++ exceptions), or
2.28 +other exception-handling interfaces.
2.29 +
2.30 +When using this interface across multiple .c files, do not include
2.31 +this header file directly. Instead, create a wrapper header file that
2.32 +includes this header file and then invokes the define_exception_type
2.33 +macro (see below). The .c files should then include that header file.
2.34 +
2.35 +The interface consists of one type, one well-known name, and six macros.
2.36 +
2.37 +
2.38 +define_exception_type(type_name);
2.39 +
2.40 + This macro is used like an external declaration. It specifies
2.41 + the type of object that gets copied from the exception thrower to
2.42 + the exception catcher. The type_name can be any type that can be
2.43 + assigned to, that is, a non-constant arithmetic type, struct, union,
2.44 + or pointer. Examples:
2.45 +
2.46 + define_exception_type(int);
2.47 +
2.48 + enum exception { out_of_memory, bad_arguments, disk_full };
2.49 + define_exception_type(enum exception);
2.50 +
2.51 + struct exception { int code; const char *msg; };
2.52 + define_exception_type(struct exception);
2.53 +
2.54 + Because throwing an exception causes the object to be copied (not
2.55 + just once, but twice), programmers may wish to consider size when
2.56 + choosing the exception type.
2.57 +
2.58 +
2.59 +struct __exception_context;
2.60 +
2.61 + This type may be used after the define_exception_type() macro has
2.62 + been invoked. A struct __exception_context must be known to both
2.63 + the thrower and the catcher. It is expected that there be one
2.64 + context for each thread that uses exceptions. It would certainly
2.65 + be dangerous for multiple threads to access the same context.
2.66 + One thread can use multiple contexts, but that is likely to be
2.67 + confusing and not typically useful. The application can allocate
2.68 + this structure in any way it pleases--automatic, static, or dynamic.
2.69 + The application programmer should pretend not to know the structure
2.70 + members, which are subject to change.
2.71 +
2.72 +
2.73 +struct __exception_context *__the_exception_context;
2.74 +
2.75 + The __Try/__Catch and __Throw statements (described below) implicitly
2.76 + refer to a context, using the name __the_exception_context. It is
2.77 + the application's responsibility to make sure that this name yields
2.78 + the address of a mutable (non-constant) struct __exception_context
2.79 + wherever those statements are used. Subject to that constraint, the
2.80 + application may declare a variable of this name anywhere it likes
2.81 + (inside a function, in a parameter list, or externally), and may
2.82 + use whatever storage class specifiers (static, extern, etc) or type
2.83 + qualifiers (const, volatile, etc) it likes. Examples:
2.84 +
2.85 + static struct __exception_context
2.86 + * const __the_exception_context = &foo;
2.87 +
2.88 + { struct __exception_context *__the_exception_context = bar; ... }
2.89 +
2.90 + int blah(struct __exception_context *__the_exception_context, ...);
2.91 +
2.92 + extern struct __exception_context __the_exception_context[1];
2.93 +
2.94 + The last example illustrates a trick that avoids creating a pointer
2.95 + object separate from the structure object.
2.96 +
2.97 + The name could even be a macro, for example:
2.98 +
2.99 + struct __exception_context ec_array[numthreads];
2.100 + #define __the_exception_context (ec_array + thread_id)
2.101 +
2.102 + Be aware that __the_exception_context is used several times by the
2.103 + __Try/__Catch/__Throw macros, so it shouldn't be expensive or have side
2.104 + effects. The expansion must be a drop-in replacement for an
2.105 + identifier, so it's safest to put parentheses around it.
2.106 +
2.107 +
2.108 +void __init_exception_context(struct __exception_context *ec);
2.109 +
2.110 + For context structures allocated statically (by an external
2.111 + definition or using the "static" keyword), the implicit
2.112 + initialization to all zeros is sufficient, but contexts allocated
2.113 + by other means must be initialized using this macro before they
2.114 + are used by a __Try/__Catch statement. It does no harm to initialize
2.115 + a context more than once (by using this macro on a statically
2.116 + allocated context, or using this macro twice on the same context),
2.117 + but a context must not be re-initialized after it has been used by a
2.118 + __Try/__Catch statement.
2.119 +
2.120 +
2.121 +__Try statement
2.122 +__Catch (expression) statement
2.123 +
2.124 + The __Try/__Catch/__Throw macros are capitalized in order to avoid
2.125 + confusion with the C++ keywords, which have subtly different
2.126 + semantics.
2.127 +
2.128 + A __Try/__Catch statement has a syntax similar to an if/else statement,
2.129 + except that the parenthesized expression goes after the second
2.130 + keyword rather than the first. As with if/else, there are two
2.131 + clauses, each of which may be a simple statement ending with a
2.132 + semicolon or a brace-enclosed compound statement. But whereas
2.133 + the else clause is optional, the __Catch clause is required. The
2.134 + expression must be a modifiable lvalue (something capable of being
2.135 + assigned to) of the same type (disregarding type qualifiers) that
2.136 + was passed to define_exception_type().
2.137 +
2.138 + If a __Throw that uses the same exception context as the __Try/__Catch is
2.139 + executed within the __Try clause (typically within a function called
2.140 + by the __Try clause), and the exception is not caught by a nested
2.141 + __Try/__Catch statement, then a copy of the exception will be assigned
2.142 + to the expression, and control will jump to the __Catch clause. If no
2.143 + such __Throw is executed, then the assignment is not performed, and
2.144 + the __Catch clause is not executed.
2.145 +
2.146 + The expression is not evaluated unless and until the exception is
2.147 + caught, which is significant if it has side effects, for example:
2.148 +
2.149 + __Try foo();
2.150 + __Catch (p[++i].e) { ... }
2.151 +
2.152 + IMPORTANT: Jumping into or out of a __Try clause (for example via
2.153 + return, break, continue, goto, longjmp) is forbidden--the compiler
2.154 + will not complain, but bad things will happen at run-time. Jumping
2.155 + into or out of a __Catch clause is okay, and so is jumping around
2.156 + inside a __Try clause. In many cases where one is tempted to return
2.157 + from a __Try clause, it will suffice to use __Throw, and then return
2.158 + from the __Catch clause. Another option is to set a flag variable and
2.159 + use goto to jump to the end of the __Try clause, then check the flag
2.160 + after the __Try/__Catch statement.
2.161 +
2.162 + IMPORTANT: The values of any non-volatile automatic variables
2.163 + changed within the __Try clause are undefined after an exception is
2.164 + caught. Therefore, variables modified inside the __Try block whose
2.165 + values are needed later outside the __Try block must either use static
2.166 + storage or be declared with the "volatile" type qualifier.
2.167 +
2.168 +
2.169 +__Throw expression;
2.170 +
2.171 + A __Throw statement is very much like a return statement, except that
2.172 + the expression is required. Whereas return jumps back to the place
2.173 + where the current function was called, __Throw jumps back to the __Catch
2.174 + clause of the innermost enclosing __Try clause. The expression must
2.175 + be compatible with the type passed to define_exception_type(). The
2.176 + exception must be caught, otherwise the program may crash.
2.177 +
2.178 + Slight limitation: If the expression is a comma-expression, it must
2.179 + be enclosed in parentheses.
2.180 +
2.181 +
2.182 +__Try statement
2.183 +__Catch_anonymous statement
2.184 +
2.185 + When the value of the exception is not needed, a __Try/__Catch statement
2.186 + can use __Catch_anonymous instead of __Catch (expression).
2.187 +
2.188 +
2.189 +Everything below this point is for the benefit of the compiler. The
2.190 +application programmer should pretend not to know any of it, because it
2.191 +is subject to change.
2.192 +
2.193 +===*/
2.194 +
2.195 +
2.196 +#ifndef CEXCEPT_H
2.197 +#define CEXCEPT_H
2.198 +
2.199 +
2.200 +#include <setjmp.h>
2.201 +
2.202 +#define define_exception_type(etype) \
2.203 +struct __exception_context { \
2.204 + jmp_buf *penv; \
2.205 + int caught; \
2.206 + volatile struct { etype etmp; } v; \
2.207 +}
2.208 +
2.209 +/* etmp must be volatile because the application might use automatic */
2.210 +/* storage for __the_exception_context, and etmp is modified between */
2.211 +/* the calls to setjmp() and longjmp(). A wrapper struct is used to */
2.212 +/* avoid warnings about a duplicate volatile qualifier in case etype */
2.213 +/* already includes it. */
2.214 +
2.215 +#define __init_exception_context(ec) ((void)((ec)->penv = 0))
2.216 +
2.217 +#define __Try \
2.218 + { \
2.219 + jmp_buf *exception__prev, exception__env; \
2.220 + exception__prev = __the_exception_context->penv; \
2.221 + __the_exception_context->penv = &exception__env; \
2.222 + if (setjmp(exception__env) == 0) { \
2.223 + do
2.224 +
2.225 +#define exception__catch(action) \
2.226 + while (__the_exception_context->caught = 0, \
2.227 + __the_exception_context->caught); \
2.228 + } \
2.229 + else { \
2.230 + __the_exception_context->caught = 1; \
2.231 + } \
2.232 + __the_exception_context->penv = exception__prev; \
2.233 + } \
2.234 + if (!__the_exception_context->caught || action) { } \
2.235 + else
2.236 +
2.237 +#define __Catch(e) exception__catch(((e) = __the_exception_context->v.etmp, 0))
2.238 +#define __Catch_anonymous exception__catch(0)
2.239 +
2.240 +/* __Try ends with do, and __Catch begins with while(0) and ends with */
2.241 +/* else, to ensure that __Try/__Catch syntax is similar to if/else */
2.242 +/* syntax. */
2.243 +/* */
2.244 +/* The 0 in while(0) is expressed as x=0,x in order to appease */
2.245 +/* compilers that warn about constant expressions inside while(). */
2.246 +/* Most compilers should still recognize that the condition is always */
2.247 +/* false and avoid generating code for it. */
2.248 +
2.249 +#define __Throw \
2.250 + for (;; longjmp(*__the_exception_context->penv, 1)) \
2.251 + __the_exception_context->v.etmp =
2.252 +
2.253 +
2.254 +#endif /* CEXCEPT_H */
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/templates/exceptions.h Fri Oct 28 22:58:50 2016 +0200
4.3 @@ -0,0 +1,29 @@
4.4 +#ifndef __EXCEPTIONS_H__
4.5 +#define __EXCEPTIONS_H__
4.6 +
4.7 +#include "cexcept.h"
4.8 +#include "types.h"
4.9 +
4.10 +/* Define the exception type. */
4.11 +
4.12 +typedef struct
4.13 +{
4.14 + __attr arg;
4.15 + int raising;
4.16 + int raising_else;
4.17 + int completing;
4.18 +} __exc;
4.19 +
4.20 +define_exception_type(__exc);
4.21 +#undef define_exception_type
4.22 +
4.23 +extern struct __exception_context __the_exception_context[1];
4.24 +
4.25 +/* More specific macros. */
4.26 +
4.27 +#define __Raise(value) __Throw ((__exc) {value, 1, 0, 0})
4.28 +#define __RaiseElse(value) __Throw ((__exc) {value, 0, 1, 0})
4.29 +#define __Return(value) __Throw ((__exc) {value, 0, 0, 1})
4.30 +#define __Complete __Throw((__exc) {__NULL, 0, 0, 1})
4.31 +
4.32 +#endif /* __EXCEPTIONS_H__ */
5.1 --- a/templates/ops.c Fri Oct 28 22:50:55 2016 +0200
5.2 +++ b/templates/ops.c Fri Oct 28 22:58:50 2016 +0200
5.3 @@ -4,8 +4,6 @@
5.4 #include "progconsts.h"
5.5 #include "progtypes.h"
5.6
5.7 -__attr null = {0, 0};
5.8 -
5.9 /* Direct access to functions. */
5.10
5.11 __attr __load_function(__func fn)
5.12 @@ -83,7 +81,7 @@
5.13
5.14 __attr __check_and_load_via_object(__ref obj, int pos, int code)
5.15 {
5.16 - return __HASATTR(obj, pos, code) ? __load_via_object(obj, pos) : null;
5.17 + return __HASATTR(obj, pos, code) ? __load_via_object(obj, pos) : __NULL;
5.18 }
5.19
5.20 __attr __check_and_load_via_any(__ref obj, int pos, int code)
5.21 @@ -124,7 +122,7 @@
5.22
5.23 /* NOTE: An error may be more appropriate. */
5.24
5.25 - return null;
5.26 + return __NULL;
5.27 }
5.28
5.29 __attr __replace_context(__ref context, __attr attr)
5.30 @@ -195,8 +193,8 @@
5.31
5.32 int __ISNULL(__attr value)
5.33 {
5.34 - /* (value.context == null.context) is superfluous */
5.35 - return (value.value == null.value);
5.36 + /* (value.context == __NULL.context) is superfluous */
5.37 + return (value.value == 0); /* __NULL.value */
5.38 }
5.39
5.40 /* Attribute codes and positions for type objects. */