SimpleType v1.0
The Simple Development Library types handling
Project: the Simple Development Library.
::Simple::Type::assert-is
type value ?extra? ?description?::Simple::Type::cget
::Simple::Type::configure
::Simple::Type::convert binary
integer::Simple::Type::convert boolean
extBoolean::Simple::Type::convert decimal
integer::Simple::Type::convert flag
flag::Simple::Type::convert hexadecimal
integer::Simple::Type::convert octal
integer::Simple::Type::convert optional
optional::Simple::Type::declare
type ?-description string? ?-matchingscript script?::Simple::Type::delete
type::Simple::Type::information declared
?typePattern?::Simple::Type::information description
type::Simple::Type::information exists
type::Simple::Type::information matchingscript
type::Simple::Type::is
type value ?extra?::Simple::Type::modify description
type description::Simple::Type::modify matchingscript
type matchingScript::Simple::Type::outside-range
range value::Simple::Type::BAD-DERIVED-TYPE
::Simple::Type::DERIVED-TYPE-OUT-OF-CONTEXT
::Simple::Type::NEGATIVE-INT
::Simple::Type::ALREADY-EXISTS
::Simple::Type::assert-is
type value ?extra? ?description?::Simple::Type::cget
::Simple::Type::configure
::Simple::Type::convert binary
integer::Simple::Type::convert boolean
extBoolean::Simple::Type::convert decimal
integer::Simple::Type::convert flag
flag::Simple::Type::convert hexadecimal
integer::Simple::Type::convert octal
integer::Simple::Type::convert optional
optional::Simple::Type::declare
type ?-description string? ?-matchingscript script?::Simple::Type::delete
type::Simple::Type::information declared
?typePattern?::Simple::Type::information description
type::Simple::Type::information exists
type::Simple::Type::information matchingscript
type::Simple::Type::is
type value ?extra?::Simple::Type::modify description
type description::Simple::Type::modify matchingscript
type matchingScript::Simple::Type::outside-range
range valueSynopsis: the Simple Development Library types handling.
Keywords: type, decimal, hexadecimal, binary, octal, base, convert, range and array.
This package allows to handle types. A type associates a type name to a matching script used to assess whether a value conforms to the type.
Procedures are provided to declare (although a wealth of predefined types are supplied) delete and modify types, get information about a type and obtain the list of types, as well as several others to convert between different types. ::Simple::Type::is
allows to assess whether a value conforms to a type.
Types are declared via ::Simple::Type::declare
or embedded within programs (declare-program
) or packages (declare-package
). Types can be deleted via ::Simple::Type::delete
or modified via ::Simple::Type::modify
. The ::Simple::Type::information
procedure provides several subcommands to query information about types: exists
, declared
, description
and matchingscript
.
The ::Simple::Type::convert
set of procedures convert a value between different types. The ::Simple::Type::is
procedure returns whether a value conforms to a type.
There are two kind of types: basic and derived. Derived types are derived from basic types and are denoted as basic type-derivation where basic type is the basic type name (such as integer) and derivation is the kind of derivation. All basic types can be derived but boolflag. Four derivations are currently supported: arrays, pairs, lists and ranges:
Derived array types (basic type-array) denote the name of an array whose elements conform to the type. Non-existing arrays conform to all types.
Derived pair types (basic type-pairs) denote a list with an even number of elements suitable to be given as argument to the array get
command. The second element in each pair conforms to the basic type.
Derived list types (basic type-list) denote a list whose elements conform to the basic type.
Derived range types (numeric-range) denote a range whose limits conform to the type which must be numeric, i.e., one of integer, float, decimal, hexadecimal, binary, octal, anybase or number. The form of the range is lower limit:upper limit where the lower, the upper or even both limits may be missing. The colon may also be missing if just one limit is given: the range is restricted then to that exact value; this also happens if both limits are equal.
The double derivation numeric-range-list is also valid and corresponds to a list of numeric ranges, such as {1 -2:3 :100} for the integer-range-list type. As the double derivation type-list-array is always valid for any type but boolflag, it follows that the triple derivation numeric-range-list-array is also valid.
Derived types are only accepted by the ::Simple::Type::is
and ::Simple::Type::information exists
procedures.
# Install the package package require SimplePackage ::Simple::Package::require-and-install SimpleType # Configure The Simple Development Library to store the metadata ::Simple::configure -storemetadata true # Declare a type bar which can only hold either bar or BAR ::Simple::Type::declare { bar } -description { can only hold either bar or BAR } -matchingscript { return [expr\ {![string compare $value bar] || ![string compare $value BAR]}] } # Assert the type bar exists # This displays the following: # |The type bar exists if {[::Simple::Type::information exists bar]} { puts {The type bar exists} } # Get some information about the type bar # This displays the following: # |The type bar can only hold either bar or BAR puts "The type bar [::Simple::Type::information description bar]" # Check the allowed contents for a variable of type bar # This displays the following: # |"bar" is of type bar # |"foo" is NOT of type bar # |"BAR" is of type bar # |"bAR" is NOT of type bar foreach contents {bar foo BAR bAR} { puts -nonewline "\"$contents\" is " if {![::Simple::Type::is bar $contents]} { puts -nonewline {NOT } } puts {of type bar} } # Get rid of the type bar ::Simple::Type::delete bar # Assert the type bar no longer exists # This displays the following: # |The type bar no longer exists if {![::Simple::Type::information exists bar]} { puts {The type bar no longer exists} } # More fun. A type made of three elements: # an integer, a boolean and an alphabetic ::Simple::Type::declare { foo } -description { integer + boolean + alphabetic } -matchingscript { foreach localType [list integer boolean alphabetic] localValue $value { if {![::Simple::Type::is $localType $localValue]} { return 0 } } return 1 } # Check the allowed contents for a variable of type foo # This displays the following: # |"2 1 bar" is of type foo # |"2 x bar" is NOT of type foo foreach contents {{2 1 bar} {2 x bar}} { puts -nonewline "\"$contents\" is " if {![::Simple::Type::is foo $contents]} { puts -nonewline {NOT } } puts {of type foo} } # Derived list type # This displays the following: # |"-2:1" is a proper integer range # |"2:1" is NOT a proper integer range foreach contents {{-2:1} {2:1}} { puts -nonewline "\"$contents\" is " if {![::Simple::Type::is integer-range $contents]} { puts -nonewline {NOT } } puts {a proper integer range} } # Derived range type # This displays the following: # |"1.0 3 -1.E-2" is a proper list of floats # |"1.0 foo -2.1" is NOT a proper list of floats foreach contents {{1.0 3 -1.E-2} {1.0 foo -2.1}} { puts -nonewline "\"$contents\" is " if {![::Simple::Type::is float-list $contents]} { puts -nonewline {NOT } } puts {a proper list of floats} }
Date | Reason |
19-feb-1999 | Unreleased first version 0.1 |
23-apr-2000 | First public release, version 0.2 |
10-sep-2001 | Second public release, version 0.4 |
17-feb-2003 | Third public release, version 0.5 |
29-mar-2003 | Extra package, version 0.5.1 |
09-jan-2004 | Derived type range accepts equal limits, version 0.5.2 |
18-nov-2004 | Added ::Simple::Type::assert-is , version 0.5.3 |
22-jun-2005 | The Simple Development Library version 1.0 |
Copyright (C) 1999-2005, Juan C. Gil (jgil@gmv.es).
Paradigm: procedural.
Requisites: SimpleSubcommand 1.0
.
Description: integer number: +1, 0, -192, ...
Description: floating point number: -1.2e23, +3.0, ...
Description: decimal number: 1234, ...
Description: hexadecimal number: xF12, ...
Description: binary number: b01011, ...
Description: octal number: 0723, ...
Description: decimal, hexadecimal, binary or octal number.
Description: any number.
Description: character.
Description: string.
Description: alphabetic (letters only).
Description: alphanumeric (letters and digits).
Description: boolean: 0 or 1.
Description: Tcl extended boolean: 0, 1, true, false, ...
Description: Tcl word.
Description: Tcl script.
Description: Tcl expression: 2 + 3, ...
Description: Tcl list.
Description: Tcl channel: stdin, file0, sock2, ...
Description: Tcl namespace: ::foo::bar, ...
Description: Tcl qualified name: ::foo::Bar, ::foo::bar, ...
Description: Tcl unqualified name: foo, Bar, ...
Description: Tcl qualified or unqualified name: foo, ::Bar, ...
Description: Tcl command name with optional subcommand: foo bar, ::Gee zuu, ...
Description: Tcl command name with optional subcommand: foo bar, Gee zuu, ...
Description: Tcl qualified variable name: ::foo::Bar, ::foo::bar(gee), ...
Description: Tcl unqualified variable name: foo, Bar(gee), ...
Description: Tcl qualified or unqualified variable name: foo, ::Bar(gee), ...
Description: Tcl qualified or unqualified variable or command name: ::Bar(gee), bar gee, ...
Description: Tcl pattern: foo*bar, ...
Description: Tcl regular expression: [A-Z]+, ...
Description: Tcl format string.
Description: Tk widget: .foo.bar, ...
Description: type name: integer, ...
Description: flag: -name, ...
Description: optional variable: ?name?, ...
Description: item declaration: a list containing a class, command, ... declaration.
Description: date: Fri Feb 03 19:09:35 WET 1984, ...
Description: choice list: {one two three}, ...
Description: any value.
Description: boolean flag.
Description: URL: http://wiki.tcl.tk.
None.
::Simple::Type
::Simple::Type::Priv
::Simple::Type::assert-is
type value ?extra? ?description?Synopsis: throws an error if a value does not conform to a type.
Details: see section 4.1.
::Simple::Type::cget
Synopsis: gets the package options.
Details: see section 4.2.
::Simple::Type::configure
Synopsis: configures the package options.
Details: see section 4.3.
::Simple::Type::convert binary
integerSynopsis: converts an integer in any base to binary.
Details: see section 4.4.
::Simple::Type::convert boolean
extBooleanSynopsis: converts an extended boolean to boolean.
Details: see section 4.5.
::Simple::Type::convert decimal
integerSynopsis: converts an integer in any base to decimal.
Details: see section 4.6.
::Simple::Type::convert flag
flagSynopsis: converts a flag to an unqualified name.
Details: see section 4.7.
::Simple::Type::convert hexadecimal
integerSynopsis: converts an integer in any base to hexadecimal.
Details: see section 4.8.
::Simple::Type::convert octal
integerSynopsis: converts an integer in any base to octal.
Details: see section 4.9.
::Simple::Type::convert optional
optionalSynopsis: converts an optional value to an unqualified name.
Details: see section 4.10.
::Simple::Type::declare
type ?-description string? ?-matchingscript script?Synopsis: declares a type.
Details: see section 4.11.
::Simple::Type::delete
typeSynopsis: deletes a type.
Details: see section 4.12.
::Simple::Type::information declared
?typePattern?Synopsis: returns the list of declared types.
Details: see section 4.13.
::Simple::Type::information description
typeSynopsis: returns a type description.
Details: see section 4.14.
::Simple::Type::information exists
typeSynopsis: returns whether a type exists.
Details: see section 4.15.
::Simple::Type::information matchingscript
typeSynopsis: returns a type matching script.
Details: see section 4.16.
::Simple::Type::is
type value ?extra?Synopsis: returns whether a value conforms to a type.
Details: see section 4.17.
::Simple::Type::modify description
type descriptionSynopsis: modifies a type description.
Details: see section 4.18.
::Simple::Type::modify matchingscript
type matchingScriptSynopsis: modifies a type matching script.
Details: see section 4.19.
::Simple::Type::outside-range
range valueSynopsis: returns whether a numeric value is outside a numeric range.
Details: see section 4.20.
::Simple::Type::BAD-DERIVED-TYPE
Message: invalid derived type "derived type".
Explanation: the derived type derived type is invalid. All basic types can be derived but "boolflag". The only derived range types valid are those in which the basic type is one of integer, float, decimal, hexadecimal, binary, octal, anybase or number.
::Simple::Type::DERIVED-TYPE-OUT-OF-CONTEXT
Message: a derived type such as "derived type" is not valid in this context.
Explanation: derived type is a derived type, but these types are valid for the ::Simple::Type::is
and ::Simple::Type::information exists
procedures only.
::Simple::Type::NEGATIVE-INT
Message: negative integer "integer".
Explanation: the integer integer is negative but a positive integer was expected.
::Simple::Type::ALREADY-EXISTS
Message: type "type" already exists.
Explanation: type type could not be created because it already exists.
Corrective action: delete the type.
This package supports the concept of hidden types for internal use by The Simple Development Library. Hidden types are similar to regular types, but they remain hidden to the public API. The purpose is that packages that define new types may use those types for other entities (variables, attributes, commands arguments, ...) but the types remain hidden until package installation.
Extend the concept of derived types to support arbitrary nested extensions of lists such as integer-list-list. Not only that, but derivations such as integer-pairs-list or word-pairs-array should be handled correctly. The ::Simple::Type::is
and ::Simple::Type::information exists
procedures should be adapted to invoke themselves recursively for such multiple derivations.
It would be nice to have a procedure which guesses the type of a given value.
The basic name regular expression ([_a-zA-Z0-9%][-_a-zA-Z0-9%]*) should be a package option. All type matching scripts requiring it should reference the package option. Alternatively, for maximum performance, upon changing this option, all types matching scripts using it should be recreated.
::Simple::Type::assert-is
type value ?extra? ?description?Synopsis: throws an error if a value does not conform to a type.
Access mode: public.
This procedure throws an error if a value does not conform to a type. The message uses the description, if given; otherwise, the type description is used, if it was stored when the type was created; otherwise, the type name is used.
Arguments:
Argument | Type | Default value/ choices | Description |
type | type | (n/a) | Type name |
value | any | (n/a) | Value or list of values |
?extra? | string | (empty string) | Extra data required to check the conformation |
?description? | string | (empty string) | Type description |
Returns: error if the value does not conform to the type.
The value %DEFAULT% conforms to all types
::Simple::Type::cget
Synopsis: gets the package options.
Access mode: public.
Arguments: none.
Returns: the requested option value or the whole list of options if none specified.
::Simple::Type::configure
Synopsis: configures the package options.
Access mode: public.
Arguments: none.
Returns: the "package with no options" error is thrown.
::Simple::Type::convert binary
integerSynopsis: converts an integer in any base to binary.
Access mode: public.
Keywords: decimal, hexadecimal, binary, octal, base and convert.
Converts a decimal, hexadecimal, binary or octal integer to binary base. The resulting binary constant is of the form 0bbinary-digits. where binary-digits are a sequence of 0s and 1s.
Arguments:
Argument | Type | Default value/ choices | Description |
integer | anybase | (n/a) | Positive integer |
Returns: the converted integer.
::Simple::Type::convert boolean
extBooleanSynopsis: converts an extended boolean to boolean.
Access mode: public.
Keywords: boolean and convert.
This procedure converts from extended booleans (true/false, yes/no or on/off) to 1/0 because the Tcl expr
and if
commands can't use non-numeric string as operand of "!" (sic).
# A robust negation test if {![::Simple::Type::convert boolean $extbool]} { puts "$extbool is false" }
Arguments:
Argument | Type | Default value/ choices | Description |
extBoolean | extbool | (n/a) | Extended boolean |
Returns: the converted boolean.
::Simple::Type::convert decimal
integerSynopsis: converts an integer in any base to decimal.
Access mode: public.
Keywords: decimal, hexadecimal, binary, octal, base and convert.
Converts a decimal, hexadecimal, binary or octal integer to decimal base.
Arguments:
Argument | Type | Default value/ choices | Description |
integer | anybase | (n/a) | Positive integer |
Returns: the converted integer.
::Simple::Type::convert flag
flagSynopsis: converts a flag to an unqualified name.
Access mode: public.
Arguments:
Argument | Type | Default value/ choices | Description |
flag | flag | (n/a) | Flag |
Returns: the flag name.
::Simple::Type::convert hexadecimal
integerSynopsis: converts an integer in any base to hexadecimal.
Access mode: public.
Keywords: decimal, hexadecimal, binary, octal, base and convert.
Converts a decimal, hexadecimal, binary or octal integer to hexadecimal base. The resulting hexadecimal constant is of the form 0xhexadecimal-digits where hexadecimal-digits are a sequence of uppercase hexadecimal digits, that is, the "0x" prefix contains a lowercase "x" but the actual digits are uppercase. This is different from the result of the "%#X" format
specifier which returns an uppercase "X".
Arguments:
Argument | Type | Default value/ choices | Description |
integer | anybase | (n/a) | Positive integer |
Returns: the converted integer.
::Simple::Type::convert octal
integerSynopsis: converts an integer in any base to octal.
Access mode: public.
Keywords: decimal, hexadecimal, binary, octal, base and convert.
Converts a decimal, hexadecimal, binary or octal integer to octal base.
Arguments:
Argument | Type | Default value/ choices | Description |
integer | anybase | (n/a) | Positive integer |
Returns: the converted integer.
::Simple::Type::convert optional
optionalSynopsis: converts an optional value to an unqualified name.
Access mode: public.
Arguments:
Argument | Type | Default value/ choices | Description |
optional | optional | (n/a) | Optional value |
Returns: the optional value name.
::Simple::Type::declare
type ?-description string? ?-matchingscript script?Synopsis: declares a type.
Access mode: public.
This procedure is used to declare a new type.
A type is made of three elements:
the type name,
the type description and
type matching script.
The type name is an all-lowercase string. The type matching script is a Tcl script used to check whether a value conforms to the type. It shall assume that the value to be checked is passed in the value variable, and shall return either 1 or 0 depending on whether the value conforms to the type or not; throwing an error is also a valid action for non-conforming values. It gets evaluated as a procedure, so use upvar
and uplevel
to access the current stack level if needed.
A type with no empty matching script may hold any value.
# Declare a type "foo" which may hold any value ::Simple::Type::declare foo # Declare a type bar which can only hold either bar or BAR ::Simple::Type::declare -matchingscript { return [expr {![string compare $value bar] || ![string compare $value BAR]}] }
Arguments:
Argument | Type | Default value/ choices | Description |
type | type | (n/a) | Type name |
?-description? | string | (empty string) | Type description |
?-matchingscript? | script | return 1 | Type matching script |
Returns: the empty string.
Effects:
Creates the type matching procedure named ::Simple::Type::Priv::%MATCHING%-type
.
The order of the flags is irrelevant but their parameters can not start by an hyphen.
::Simple::Type::delete
typeSynopsis: deletes a type.
Access mode: public.
Arguments:
Argument | Type | Default value/ choices | Description |
type | type | (n/a) | Type name |
Returns: the empty string.
Effects:
Deletes the type matching procedure named ::Simple::Type::Priv::%MATCHING%-type
.
::Simple::Type::information declared
?typePattern?Synopsis: returns the list of declared types.
Access mode: public.
This procedure returns the list of declared types matching the given pattern. This includes native The Simple Development Library types as well as others declared via the ::Simple::Type::declare
procedure.
Arguments:
Argument | Type | Default value/ choices | Description |
?typePattern? | pattern | (empty string) | Pattern |
Returns: the list of types matching the given pattern.
Use no pattern to obtain the complete list of types.
::Simple::Type::information description
typeSynopsis: returns a type description.
Access mode: public.
Arguments:
Argument | Type | Default value/ choices | Description |
type | type | (n/a) | Type name |
Returns: the type description.
::Simple::Type::information exists
typeSynopsis: returns whether a type exists.
Access mode: public.
This procedure returns whether a type exists. This includes native The Simple Development Library types as well as others declared via the ::Simple::Type::declare
procedure. For derived types, the procedure returns whether the basic type exists.
Arguments:
Argument | Type | Default value/ choices | Description |
type | type | (n/a) | Type name |
Returns: whether the type exists.
::Simple::Type::information matchingscript
typeSynopsis: returns a type matching script.
Access mode: public.
Arguments:
Argument | Type | Default value/ choices | Description |
type | type | (n/a) | Type name |
Returns: the type matching script.
::Simple::Type::is
type value ?extra?Synopsis: returns whether a value conforms to a type.
Access mode: public.
Keywords: type.
This procedure returns whether a value conforms to a type.
If the type is a derived list type, the value is considered a list of values, and the procedure returns whether all of them conform to the basic type. Empty lists conform to all types.
If the type is a derived array type, the value is considered the name of an array of values in the calling scope, and the procedure returns whether all of them conform to the basic type. Non-existing arrays conform to all types.
If the type is a derived range type, the value is considered a range whose limits are of the basic type.
Arguments:
Argument | Type | Default value/ choices | Description |
type | type | (n/a) | Type name |
value | any | (n/a) | Value or list of values |
?extra? | string | (empty string) | Extra data required to check the conformation |
Returns: whether the value conforms to the type.
The value %DEFAULT% conforms to all types
::Simple::Type::modify description
type descriptionSynopsis: modifies a type description.
Access mode: public.
Arguments:
Argument | Type | Default value/ choices | Description |
type | type | (n/a) | Type name |
description | string | (n/a) | New description |
Returns: the empty string.
::Simple::Type::modify matchingscript
type matchingScriptSynopsis: modifies a type matching script.
Access mode: public.
Arguments:
Argument | Type | Default value/ choices | Description |
type | type | (n/a) | Type name |
matchingScript | script | (n/a) | New matching script |
Returns: the empty string.
Effects:
Recreates the type matching procedure named ::Simple::Type::Priv::%MATCHING%-type
.
::Simple::Type::outside-range
range valueSynopsis: returns whether a numeric value is outside a numeric range.
Access mode: public.
Arguments:
Argument | Type | Default value/ choices | Description |
range | number-range | (n/a) | Numeric range |
value | number | (n/a) | Numeric value |
Returns: -1, 0 or 1, depending on whether the value is lower than the lower range limit, within the range or greater than the upper range limit.