diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-06-02 21:55:23 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-06-02 21:55:23 -0700 |
commit | e538d15b836c6931bbd14b5fb26f57899a3bff54 (patch) | |
tree | 657f1a8cddd8e105a88e6b8eebcbb8f82be92756 | |
parent | 9cf108dc6e06fbf22e4af312cb0164dc099038a3 (diff) | |
download | txr-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.h | 1 | ||||
-rw-r--r-- | ffi.c | 44 | ||||
-rw-r--r-- | txr.1 | 39 |
3 files changed, 59 insertions, 25 deletions
@@ -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))) @@ -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, @@ -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 |