summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2017-06-02 21:55:23 -0700
committerKaz Kylheku <kaz@kylheku.com>2017-06-02 21:55:23 -0700
commite538d15b836c6931bbd14b5fb26f57899a3bff54 (patch)
tree657f1a8cddd8e105a88e6b8eebcbb8f82be92756
parent9cf108dc6e06fbf22e4af312cb0164dc099038a3 (diff)
downloadtxr-e538d15b836c6931bbd14b5fb26f57899a3bff54.tar.gz
txr-e538d15b836c6931bbd14b5fb26f57899a3bff54.tar.bz2
txr-e538d15b836c6931bbd14b5fb26f57899a3bff54.zip
ffi: evaluate expressions in type notation.
Places where an integer constant was previously allowed now allow an expression. The way enum syntax works is now different. A temporary lexical environment is created, and each enumeration is bound in that environment. The value expressions are evaluated in that environment. The decision to allow keyword symbols to be enumeration contants is retracted. * eval.h (special_s): Declared. * ffi.c (ffi_eval_expr): New static function. (make_ffi_type_enum): Enums are introduced into a temporary environment, in which the value expressions are evaluated. By this means, the expressions can refer can refer to previous enums and do arbitrary computation. Also, we drop the requirement that enums can be keyword symbols. (ffi_type_compile): Array dimension and buf size are evaluated as expresions. Array and buffer syntax is transformed by substitution of the evaluated size. * txr.1: Documented use of expressions in FFI type notation.
-rw-r--r--eval.h1
-rw-r--r--ffi.c44
-rw-r--r--txr.139
3 files changed, 59 insertions, 25 deletions
diff --git a/eval.h b/eval.h
index 75cf2c75..4fb46426 100644
--- a/eval.h
+++ b/eval.h
@@ -32,6 +32,7 @@ extern val eq_s, eql_s, equal_s;
extern val car_s, cdr_s;
extern val last_form_evaled, last_form_expanded;
extern val load_path_s, load_recursive_s;
+extern val special_s;
#define load_path (deref(lookup_var_l(nil, load_path_s)))
diff --git a/ffi.c b/ffi.c
index 44ffc3bf..db7ae8cd 100644
--- a/ffi.c
+++ b/ffi.c
@@ -2064,6 +2064,12 @@ static val make_ffi_type_array(val syntax, val lisp_type,
return obj;
}
+static val ffi_eval_expr(val expr, val menv, val env)
+{
+ val expr_ex = expand(expr, menv);
+ return eval(expr_ex, env, expr_ex);
+}
+
static val make_ffi_type_enum(val syntax, val enums, val self)
{
struct txr_ffi_type *tft = coerce(struct txr_ffi_type *,
@@ -2077,6 +2083,8 @@ static val make_ffi_type_enum(val syntax, val enums, val self)
val iter;
val sym_num = make_hash(nil, nil, t);
val num_sym = make_hash(nil, nil, nil);
+ val enum_env = make_env(nil, nil, nil);
+ val shadow_menv = make_env(nil, nil, nil);
tft->ft = &ffi_type_sint;
tft->syntax = syntax;
@@ -2097,8 +2105,8 @@ static val make_ffi_type_enum(val syntax, val enums, val self)
val nn;
if (symbolp(en)) {
val sym = en;
- if (!bindable(sym) && !keywordp(sym))
- uw_throwf(error_s, lit("~s: ~s member ~s isn't bindable or a keyword"),
+ if (!bindable(sym))
+ uw_throwf(error_s, lit("~s: ~s member ~s isn't a bindable symbol"),
self, syntax, sym, nao);
if (cur == INT_MAX)
uw_throwf(error_s, lit("~s: ~s overflow at member ~s"),
@@ -2108,23 +2116,24 @@ static val make_ffi_type_enum(val syntax, val enums, val self)
self, syntax, sym, nao);
sethash(num_sym, sym, nn = num(++cur));
sethash(sym_num, nn, sym);
+ env_vbind(enum_env, sym, nn);
+ env_vbind(shadow_menv, sym, special_s);
if (cur > highest)
highest = cur;
} else {
- val n = cadr(en);
+ val expr = cadr(en);
val sym = car(en);
- if (!bindable(sym) && !keywordp(sym))
- uw_throwf(error_s, lit("~s: ~s member ~s isn't bindable or a keyword"),
+ val n;
+ if (!bindable(sym))
+ uw_throwf(error_s, lit("~s: ~s member ~s isn't a bindable symbol"),
self, syntax, sym, nao);
if (gethash(num_sym, sym))
uw_throwf(error_s, lit("~s: ~s duplicate member ~s"),
self, syntax, sym, nao);
- if (symbolp(n)) {
- n = gethash(num_sym, n);
- if (!n)
- uw_throwf(error_s, lit("~s: ~s member ~s value ~s not defined"),
- self, syntax, n, nao);
- } else if (!integerp(n)) {
+
+ n = ffi_eval_expr(expr, shadow_menv, enum_env);
+
+ if (!integerp(n)) {
uw_throwf(error_s, lit("~s: ~s member ~s value ~s not integer"),
self, syntax, n, nao);
}
@@ -2135,6 +2144,8 @@ static val make_ffi_type_enum(val syntax, val enums, val self)
self, syntax, n, nao);
sethash(num_sym, sym, nn = num(cur));
sethash(sym_num, nn, sym);
+ env_vbind(enum_env, sym, nn);
+ env_vbind(shadow_menv, sym, special_s);
if (cur < lowest)
lowest = cur;
}
@@ -2217,9 +2228,10 @@ val ffi_type_compile(val syntax)
tft->size = 0;
return type;
} else if (length(syntax) == three) {
- val dim = cadr(syntax);
+ val dim = ffi_eval_expr(cadr(syntax), nil, nil);
val eltype_syntax = caddr(syntax);
val eltype = ffi_type_compile(eltype_syntax);
+ val xsyntax = list(sym, dim, eltype_syntax, nao);
struct txr_ffi_type *etft = ffi_type_struct(eltype);
if (etft->size == 0)
@@ -2232,7 +2244,7 @@ val ffi_type_compile(val syntax)
self, syntax, nao);
{
- val type = make_ffi_type_array(syntax, vec_s, dim, eltype);
+ val type = make_ffi_type_array(xsyntax, vec_s, dim, eltype);
struct txr_ffi_type *tft = ffi_type_struct(type);
if (sym == zarray_s) {
@@ -2291,8 +2303,10 @@ val ffi_type_compile(val syntax)
ffi_ptr_out_s_in, ffi_ptr_out_out,
0, target_type);
} else if (sym == buf_s || sym == buf_d_s) {
- cnum nelem = c_num(cadr(syntax));
- val type = make_ffi_type_builtin(syntax, buf_s,
+ val size = ffi_eval_expr(cadr(syntax), nil, nil);
+ val xsyntax = list(sym, size, nao);
+ cnum nelem = c_num(size);
+ val type = make_ffi_type_builtin(xsyntax, buf_s,
sizeof (mem_t *),
alignof (mem_t *),
&ffi_type_pointer,
diff --git a/txr.1 b/txr.1
index 99b49a25..a9ba02de 100644
--- a/txr.1
+++ b/txr.1
@@ -53539,6 +53539,12 @@ are instantiated with parameters. Each such expression has a type constructor
symbol in the operator position, from a limited, fixed vocabulary, which cannot
be extended.
+Some constituents of compound type syntax are expressions which evaluate to
+integer values: the dimension value for array types, the size for buffers,
+and the value expressions for enumeration constants are such expressions.
+These expressions allow full use of \*(TL. They are evaluated without
+visibility into any apparent surrounding lexical scope.
+
Some predefined types which are provided are in fact typedef names.
For instance, the
.code size-t
@@ -53963,15 +53969,20 @@ type. The remaining arguments specify the enumeration constants.
In the enumeration constant syntax, each occurrence of
.meta sym
-They must be either a keyword symbol, or a symbols for which the
+They must be a bindable symbol according to the
.code bindable
-function returns true. The symbols may not repeat.
+function. The symbols may not repeat within the same enumerated type.
+Unlike in the C language, different enumerations may use the same symbols;
+they are in separate spaces.
If a
.meta sym
is given, it is associated with an integer value which is one greater
than the integer value associated with the previous symbol.
-If there is no previous symbol, then the value is zero.
+If there is no previous symbol, then the value is zero. If the previous
+symbol has been assigned the highest possible value of the FFI
+.code int
+type, then an error exception is thrown.
If
.meti >> ( sym << value )
@@ -53979,12 +53990,13 @@ is given, then
.code sym
is given the specified value. The
.meta value
-argument may be either an integer token, or a symbol. If it is an integer
-token, then the value must be in range of the FFI
+is an expression which must evaluate to an integer value in range of the FFI
.code int
-type. If a symbol is given, it must be be one of the symbols already defined
-in the same enumerated type. The new symbol is given the same value as that
-symbol.
+type.
+It is evaluated in an environment in which the previous
+symbols from the same enumeration appear as variables whose binding are the
+their enumeration values, making it possible to use earlier enumerations in the
+definition of later enumerations.
The FFI
.code enum
@@ -54089,6 +54101,11 @@ Since Lisp arrays and C arrays do not share the same representation,
temporary buffers are automatically created and destroyed by FFI
to manage the conversion.
+The
+.code dim
+argument is an ordinary Lisp expression expanded and evaluated in the
+top-level environment. It must produce a non-negative integer value.
+
In addition, several types are treated specially: when
.meta type
is one of
@@ -54539,8 +54556,10 @@ and
.codn buf-d ,
respectively. The
.meta size
-argument must be an integer literal, which specifies the buffer
-size. Because they have a size, these types have useful get
+argument is an expression which is evaluated in the top-level
+environment, and must produce a non-negative integer.
+
+Because they have a size, these types have useful get
semantics.
The get semantics of