You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
151 lines
4.2 KiB
151 lines
4.2 KiB
## -*- tcl -*- |
|
# # ## ### ##### ######## ############# ##################### |
|
# Pragmas for MetaData Scanner. |
|
# n/a |
|
|
|
# CriTcl Utility Commands. Generation of functions handling conversion |
|
# from and to a C enum. Not a full Tcl_ObjType. Based on |
|
# Tcl_GetIndexFromObj() instead. |
|
|
|
package provide critcl::enum 1.2 |
|
|
|
# # ## ### ##### ######## ############# ##################### |
|
## Requirements. |
|
|
|
package require Tcl 8.6 ; # Min supported version. |
|
package require critcl 3.1.11 ; # make, include -- dict portability |
|
package require critcl::literals 1.1 ; # String pool for conversion to Tcl. |
|
|
|
namespace eval ::critcl::enum {} |
|
|
|
# # ## ### ##### ######## ############# ##################### |
|
## API: Generate the declaration and implementation files for the enum. |
|
|
|
proc ::critcl::enum::def {name dict {use tcl}} { |
|
# Arguments are |
|
# - the C name of the enumeration, and |
|
# - dict of strings to convert. Key is the symbolic C name, value |
|
# is the string. Numeric C value is in the order of the strings in |
|
# the dict, treating it as list for that case. |
|
# |
|
# dict: C symbolic name -> Tcl string (Tcl symbolic name). |
|
|
|
if {![dict size $dict]} { |
|
return -code error -errorcode {CRITCL ENUM DEF INVALID} \ |
|
"Expected an enum definition, got empty string" |
|
} |
|
|
|
set plist 0 |
|
foreach m $use { |
|
switch $m { |
|
tcl {} |
|
+list { set plist 1 } |
|
default { |
|
return -code error -errorcode {CRITCL ENUM DEF MODE INVALID} \ |
|
"Unknown mode $m, expected one of \"+list\", or \"tcl\"" |
|
} |
|
} |
|
} |
|
|
|
critcl::literals::def ${name}_pool $dict $use |
|
|
|
# <name>_pool_names = C enum of symbolic names, and implied numeric values. |
|
# <name>_pool.h = Header |
|
# <name>_pool ( interp, code ) => Tcl_Obj* :: up-conversion C to Tcl. |
|
|
|
# Exporting: |
|
# Header <name>.h |
|
# Function <name>_ToObj (interp, code) -> obj |
|
# Function <name>_ToObjList (interp, count, code*) -> obj (**) |
|
# Function <name>_GetFromObj (interp, obj, flags, &code) -> Tcl code |
|
# Enum type <name>_names |
|
# |
|
# (**) Mode +list only. |
|
|
|
dict for {sym str} $dict { |
|
lappend table "\t\t\"$str\"," |
|
} |
|
|
|
lappend map @NAME@ $name |
|
lappend map @TABLE@ \n[join $table \n] |
|
lappend map @TSIZE@ [llength $table] |
|
lappend map @TSIZE1@ [expr {1 + [llength $table]}] |
|
|
|
if {$plist} { |
|
lappend map @PLIST@ \ |
|
"\n #define ${name}_ToObjList(i,c,l) (${name}_pool_list(i,c,l))" |
|
} else { |
|
lappend map @PLIST@ "" |
|
} |
|
|
|
critcl::include [critcl::make ${name}.h \n[critcl::at::here!][string map $map { |
|
#ifndef @NAME@_HEADER |
|
#define @NAME@_HEADER |
|
#include <@NAME@_pool.h> |
|
#include <tcl.h> |
|
|
|
typedef @NAME@_pool_names @NAME@; |
|
#define @NAME@_LAST @NAME@_pool_name_LAST |
|
|
|
extern int |
|
@NAME@_GetFromObj (Tcl_Interp* interp, |
|
Tcl_Obj* obj, |
|
int flags, |
|
int* literal); |
|
|
|
#define @NAME@_ToObj(i,l) (@NAME@_pool(i,l))@PLIST@ |
|
#endif |
|
}]] |
|
|
|
# Create second function, down-conversion Tcl to C. |
|
|
|
critcl::ccode [critcl::at::here!][string map $map { |
|
extern int |
|
@NAME@_GetFromObj (Tcl_Interp* interp, |
|
Tcl_Obj* obj, |
|
int flags, |
|
int* literal ) |
|
{ |
|
static const char* strings[@TSIZE1@] = {@TABLE@ |
|
NULL |
|
}; |
|
|
|
return Tcl_GetIndexFromObj (interp, obj, strings, |
|
"@NAME@", |
|
flags, literal); |
|
} |
|
}] |
|
|
|
|
|
# V. Define convenient argument- and result-type definitions |
|
# wrapping the de- and encoder functions for use by cprocs. |
|
|
|
critcl::argtype $name \n[critcl::at::here!][string map $map { |
|
if (@NAME@_GetFromObj (interp, @@, TCL_EXACT, &@A) != TCL_OK) return TCL_ERROR; |
|
}] int int |
|
|
|
critcl::argtype ${name}-prefix \n[critcl::at::here!][string map $map { |
|
if (@NAME@_GetFromObj (interp, @@, 0, &@A) != TCL_OK) return TCL_ERROR; |
|
}] int int |
|
|
|
# Use the underlying literal pool directly. |
|
critcl::resulttype $name = ${name}_pool |
|
return |
|
} |
|
|
|
# # ## ### ##### ######## ############# ##################### |
|
## Export API |
|
|
|
namespace eval ::critcl::enum { |
|
namespace export def |
|
catch { namespace ensemble create } |
|
} |
|
|
|
namespace eval ::critcl { |
|
namespace export enum |
|
catch { namespace ensemble create } |
|
} |
|
|
|
# # ## ### ##### ######## ############# ##################### |
|
## Ready |
|
return
|
|
|