mirror of
https://gitlab.com/c3d/db48x.git
synced 2024-09-29 05:36:58 +02:00
Replace range-based tests for is_XYZ with flag-based tests
This gives us much more flexibility in rearranging IDs, and makes the code overall much more readable. Fixes: #234 Signed-off-by: Christophe de Dinechin <christophe@dinechin.org>
This commit is contained in:
parent
684ab0fb7d
commit
7451edfccc
8 changed files with 217 additions and 89 deletions
|
@ -119,7 +119,7 @@ fraction_p arithmetic::fraction_promotion(algebraic_g &x)
|
|||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
id ty = x->type();
|
||||
if (ty >= FIRST_FRACTION_TYPE && ty <= LAST_FRACTION_TYPE)
|
||||
if (is_fraction(ty))
|
||||
return fraction_g((fraction *) object_p(x));
|
||||
if (ty >= ID_integer && ty <= ID_neg_integer)
|
||||
{
|
||||
|
|
|
@ -294,7 +294,7 @@ inline size_t bignum::wordsize(id type)
|
|||
// Return the word size for an bignum type in bits
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
if (type >= FIRST_BASED_TYPE && type <= LAST_BASED_TYPE)
|
||||
if (is_based(type))
|
||||
return Settings.wordsize;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -48,10 +48,10 @@ MENU_BODY(Catalog)
|
|||
}
|
||||
|
||||
|
||||
#define NUM_COMMANDS (object::LAST_COMMAND - object::FIRST_COMMAND + 1)
|
||||
static object::id sorted_ids[object::NUM_IDS];
|
||||
|
||||
static object::id sorted_ids[NUM_COMMANDS];
|
||||
|
||||
static uint NUM_COMMANDS = 0;
|
||||
|
||||
static int sort_ids(const void *left, const void *right)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -69,9 +69,12 @@ static void initialize_sorted_ids()
|
|||
// Sort IDs alphabetically
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
for (uint i = 0; i < NUM_COMMANDS; i++)
|
||||
sorted_ids[i] = object::id(i + object::FIRST_COMMAND);
|
||||
qsort(sorted_ids, NUM_COMMANDS, sizeof(sorted_ids[0]), sort_ids);
|
||||
uint count = 0;
|
||||
for (uint i = 0; i < object::NUM_IDS; i++)
|
||||
if (object::is_command(object::id(i)))
|
||||
sorted_ids[count++] = object::id(i);
|
||||
qsort(sorted_ids, count, sizeof(sorted_ids[0]), sort_ids);
|
||||
NUM_COMMANDS = count;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ PARSE_BODY(command)
|
|||
bool eq = p.precedence;
|
||||
|
||||
// If we are parsing an equation, only accept algebraic command
|
||||
if (eq && (i < FIRST_ALGEBRAIC || i > LAST_ALGEBRAIC))
|
||||
if (eq && !is_algebraic_function(i))
|
||||
return SKIP;
|
||||
|
||||
id found = id(0);
|
||||
|
|
65
src/ids.tbl
65
src/ids.tbl
|
@ -48,16 +48,44 @@
|
|||
#define ALIAS(op, name)
|
||||
#endif
|
||||
|
||||
#ifndef OPCODE
|
||||
#define OPCODE(id) ID(id)
|
||||
#endif
|
||||
|
||||
#ifndef MENU
|
||||
#define MENU(id) ID(id)
|
||||
#endif
|
||||
|
||||
#ifndef FLAGS
|
||||
#define FLAGS(name, ...)
|
||||
#endif
|
||||
|
||||
// ============================================================================
|
||||
//
|
||||
// Range of types for attributes
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
FLAGS(is_type, directory, decimal128)
|
||||
FLAGS(is_integer, hex_integer, neg_integer)
|
||||
FLAGS(is_based, hex_integer, based_integer, hex_bignum, based_bignum)
|
||||
FLAGS(is_bignum, hex_bignum, neg_bignum)
|
||||
FLAGS(is_fraction, fraction, neg_big_fraction)
|
||||
FLAGS(is_decimal, decimal32, decimal128)
|
||||
FLAGS(is_real, bignum, decimal128)
|
||||
FLAGS(is_complex, rectangular, polar)
|
||||
FLAGS(is_command, Drop, Unimplemented)
|
||||
FLAGS(is_symbolic, local, equation, pi, ImaginaryUnit)
|
||||
FLAGS(is_algebraic, add, det)
|
||||
FLAGS(is_immediate, MainMenu, LastMenu)
|
||||
|
||||
|
||||
|
||||
// ============================================================================
|
||||
//
|
||||
// Definition of types
|
||||
//
|
||||
// ============================================================================
|
||||
|
||||
ID(object) // Value 0 is reserved for "not implemented"
|
||||
|
||||
|
||||
ID(directory)
|
||||
ID(text)
|
||||
ID(list)
|
||||
|
@ -72,53 +100,36 @@ ID(symbol)
|
|||
ID(equation)
|
||||
|
||||
// Complex types must be parsed before numbers
|
||||
#define FIRST_COMPLEX_TYPE ID_rectangular
|
||||
ID(rectangular)
|
||||
ID(polar)
|
||||
#define LAST_COMPLEX_TYPE ID_polar
|
||||
|
||||
#define FIRST_INTEGER_TYPE ID_hex_integer
|
||||
#define FIRST_BASED_TYPE ID_hex_integer
|
||||
ID(hex_integer)
|
||||
ID(dec_integer)
|
||||
ID(oct_integer)
|
||||
ID(bin_integer)
|
||||
ID(based_integer)
|
||||
|
||||
#define FIRST_BIGNUM_TYPE ID_hex_bignum
|
||||
ID(hex_bignum)
|
||||
ID(dec_bignum)
|
||||
ID(oct_bignum)
|
||||
ID(bin_bignum)
|
||||
ID(based_bignum)
|
||||
#define LAST_BASED_TYPE ID_based_bignum
|
||||
|
||||
#define FIRST_REAL_TYPE ID_bignum
|
||||
#define FIRST_SYMBOLIC_TYPE ID_bignum
|
||||
ID(bignum)
|
||||
ID(neg_bignum)
|
||||
#define LAST_BIGNUM_TYPE ID_neg_bignum
|
||||
|
||||
ID(integer)
|
||||
ID(neg_integer)
|
||||
#define LAST_INTEGER_TYPE ID_neg_integer
|
||||
|
||||
#define FIRST_FRACTION_TYPE ID_fraction
|
||||
ID(fraction)
|
||||
ID(neg_fraction)
|
||||
ID(big_fraction)
|
||||
ID(neg_big_fraction)
|
||||
#define LAST_FRACTION_TYPE ID_neg_big_fraction
|
||||
|
||||
#define FIRST_DECIMAL_TYPE ID_decimal32
|
||||
ID(decimal32)
|
||||
ID(decimal64)
|
||||
ID(decimal128)
|
||||
#define LAST_DECIMAL_TYPE ID_decimal128
|
||||
#define LAST_REAL_TYPE ID_decimal128
|
||||
#define LAST_SYMBOLIC_TYPE ID_decimal128
|
||||
|
||||
#define FIRST_COMMAND ID_Drop
|
||||
CMD(Drop)
|
||||
CMD(Drop2)
|
||||
CMD(DropN)
|
||||
|
@ -141,12 +152,8 @@ CMD(False)
|
|||
NAMED(ToText, "→Text")
|
||||
ALIAS(ToText, "→Str")
|
||||
|
||||
#define FIRST_SYMBOLIC_CONSTANT ID_pi
|
||||
NAMED(pi, "π")
|
||||
NAMED(ImaginaryUnit, "ⅈ")
|
||||
#define LAST_SYMBOLIC_CONSTANT ID_ImaginaryUnit
|
||||
|
||||
#define FIRST_ALGEBRAIC ID_add
|
||||
|
||||
OP(add, "+")
|
||||
OP(sub, "-")
|
||||
|
@ -231,7 +238,6 @@ CMD(arg)
|
|||
CMD(conj)
|
||||
NAMED(det, "Determinant")
|
||||
|
||||
#define LAST_ALGEBRAIC ID_det
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
@ -354,8 +360,6 @@ CMD(Version)
|
|||
//
|
||||
// ============================================================================
|
||||
|
||||
#define FIRST_IMMEDIATE ID_MainMenu
|
||||
|
||||
MENU(MainMenu)
|
||||
MENU(HomeMenu)
|
||||
|
||||
|
@ -416,15 +420,15 @@ MENU(TextMenu)
|
|||
|
||||
CMD(VariablesMenu)
|
||||
CMD(ToolsMenu)
|
||||
CMD(LastMenu)
|
||||
CMD(Catalog)
|
||||
CMD(LastMenu) // Last immediate command
|
||||
|
||||
NAMED(Off, "PowerOff")
|
||||
CMD(SaveState)
|
||||
CMD(SystemSetup)
|
||||
CMD(Help)
|
||||
|
||||
CMD(Unimplemented)
|
||||
#define LAST_COMMAND ID_Unimplemented
|
||||
|
||||
|
||||
// ============================================================================
|
||||
|
@ -462,3 +466,4 @@ ID(dmcp_font)
|
|||
#undef MENU
|
||||
#undef NAMED
|
||||
#undef ALIAS
|
||||
#undef FLAGS
|
||||
|
|
|
@ -73,6 +73,32 @@ RECORDER(object_errors, 16, "Runtime errors on objects");
|
|||
RECORDER(assert_error, 16, "Assertion failures");
|
||||
|
||||
|
||||
template <typename first, typename last, typename ...rest>
|
||||
struct handler_flag
|
||||
{
|
||||
static constexpr bool set(object::id id)
|
||||
{
|
||||
return (id >= first::static_id && id <= last::static_id)
|
||||
|| handler_flag<rest...>::set(id);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename first, typename last>
|
||||
struct handler_flag<first, last>
|
||||
{
|
||||
static constexpr bool set(object::id id)
|
||||
{
|
||||
return id >= first::static_id && id <= last::static_id;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define ID(id)
|
||||
#define FLAGS(name, ...) \
|
||||
static constexpr auto name = handler_flag<__VA_ARGS__>();
|
||||
#include "ids.tbl"
|
||||
|
||||
|
||||
const object::dispatch object::handler[NUM_IDS] =
|
||||
// ----------------------------------------------------------------------------
|
||||
// Table of handlers for each object type
|
||||
|
@ -80,21 +106,33 @@ const object::dispatch object::handler[NUM_IDS] =
|
|||
{
|
||||
#define ID(id) NAMED(id,#id)
|
||||
#define CMD(id) ID(id)
|
||||
#define NAMED(id, label) \
|
||||
[ID_##id] = { \
|
||||
.name = #id, \
|
||||
.fancy = label, \
|
||||
.size = (size_fn) id::do_size, \
|
||||
.parse = (parse_fn) id::do_parse, \
|
||||
.help = (help_fn) id::do_help, \
|
||||
.evaluate = (evaluate_fn) id::do_evaluate, \
|
||||
.execute = (execute_fn) id::do_execute, \
|
||||
.render = (render_fn) id::do_render, \
|
||||
.insert = (insert_fn) id::do_insert, \
|
||||
.menu = (menu_fn) id::do_menu, \
|
||||
.menu_marker = (menu_marker_fn) id::do_menu_marker, \
|
||||
.arity = id::ARITY, \
|
||||
.precedence = id::PRECEDENCE \
|
||||
#define NAMED(id, label) \
|
||||
[ID_##id] = { \
|
||||
.name = #id, \
|
||||
.fancy = label, \
|
||||
.size = (size_fn) id::do_size, \
|
||||
.parse = (parse_fn) id::do_parse, \
|
||||
.help = (help_fn) id::do_help, \
|
||||
.evaluate = (evaluate_fn) id::do_evaluate, \
|
||||
.execute = (execute_fn) id::do_execute, \
|
||||
.render = (render_fn) id::do_render, \
|
||||
.insert = (insert_fn) id::do_insert, \
|
||||
.menu = (menu_fn) id::do_menu, \
|
||||
.menu_marker = (menu_marker_fn) id::do_menu_marker, \
|
||||
.arity = id::ARITY, \
|
||||
.precedence = id::PRECEDENCE, \
|
||||
.is_type = ::is_type.set(ID_##id), \
|
||||
.is_integer = ::is_integer.set(ID_##id), \
|
||||
.is_based = ::is_based.set(ID_##id), \
|
||||
.is_bignum = ::is_bignum.set(ID_##id), \
|
||||
.is_fraction = ::is_fraction.set(ID_##id), \
|
||||
.is_real = ::is_real.set(ID_##id), \
|
||||
.is_decimal = ::is_decimal.set(ID_##id), \
|
||||
.is_complex = ::is_complex.set(ID_##id), \
|
||||
.is_command = ::is_command.set(ID_##id), \
|
||||
.is_symbolic = ::is_symbolic.set(ID_##id), \
|
||||
.is_algebraic = ::is_algebraic.set(ID_##id), \
|
||||
.is_immediate = ::is_immediate.set(ID_##id), \
|
||||
},
|
||||
#include "ids.tbl"
|
||||
};
|
||||
|
|
152
src/object.h
152
src/object.h
|
@ -189,19 +189,31 @@ struct object
|
|||
// Operations that can be run on an object
|
||||
// ----------------------------------------------------------------------------
|
||||
{
|
||||
cstring name; // Basic (compatibility) name
|
||||
cstring fancy; // Fancy name
|
||||
size_fn size; // Compute object size in bytes
|
||||
parse_fn parse; // Parse an object
|
||||
help_fn help; // Return help topic
|
||||
evaluate_fn evaluate; // Evaluate the object
|
||||
execute_fn execute; // Execute the object
|
||||
render_fn render; // Render the object as text
|
||||
insert_fn insert; // Insert object in editor
|
||||
menu_fn menu; // Build menu entries
|
||||
menu_marker_fn menu_marker; // Show marker
|
||||
uint arity; // Number of input arguments
|
||||
uint precedence; // Precedence in equations
|
||||
cstring name; // Basic (compatibility) name
|
||||
cstring fancy; // Fancy name
|
||||
size_fn size; // Compute object size in bytes
|
||||
parse_fn parse; // Parse an object
|
||||
help_fn help; // Return help topic
|
||||
evaluate_fn evaluate; // Evaluate the object
|
||||
execute_fn execute; // Execute the object
|
||||
render_fn render; // Render the object as text
|
||||
insert_fn insert; // Insert object in editor
|
||||
menu_fn menu; // Build menu entries
|
||||
menu_marker_fn menu_marker; // Show marker
|
||||
uint arity; // Number of input arguments
|
||||
uint precedence; // Precedence in equations
|
||||
bool is_type :1; // Is a data type
|
||||
bool is_integer :1; // Is an integer type
|
||||
bool is_based :1; // Is a based integer type
|
||||
bool is_bignum :1; // Is a bignum type
|
||||
bool is_fraction :1; // Is a fraction type
|
||||
bool is_real :1; // Is a real type (excludes based ints)
|
||||
bool is_decimal :1; // Is a decimal type
|
||||
bool is_complex :1; // Is a complex (but not real) type
|
||||
bool is_command :1; // Is an RPL command
|
||||
bool is_symbolic :1; // Is a symbol or an equation
|
||||
bool is_algebraic :1; // Algebraic functions (in equations)
|
||||
bool is_immediate :1; // Commands that execute immediately
|
||||
};
|
||||
|
||||
|
||||
|
@ -460,12 +472,30 @@ struct object
|
|||
//
|
||||
// ========================================================================
|
||||
|
||||
static bool is_type(id ty)
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if a type is for an RPL data type
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return handler[ty].is_type;
|
||||
}
|
||||
|
||||
|
||||
bool is_type() const
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if an object is an integer
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return is_type(type());
|
||||
}
|
||||
|
||||
|
||||
static bool is_integer(id ty)
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if a type is an integer
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return ty >= FIRST_INTEGER_TYPE && ty <= LAST_INTEGER_TYPE;
|
||||
return handler[ty].is_integer;
|
||||
}
|
||||
|
||||
|
||||
|
@ -478,12 +508,30 @@ struct object
|
|||
}
|
||||
|
||||
|
||||
static bool is_based(id ty)
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if a type is a based integer
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return handler[ty].is_based;
|
||||
}
|
||||
|
||||
|
||||
bool is_based() const
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if an object is a based integer
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return is_based(type());
|
||||
}
|
||||
|
||||
|
||||
static bool is_bignum(id ty)
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if a type is a big integer
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return ty >= FIRST_BIGNUM_TYPE && ty <= LAST_BIGNUM_TYPE;
|
||||
return handler[ty].is_bignum;
|
||||
}
|
||||
|
||||
|
||||
|
@ -501,7 +549,7 @@ struct object
|
|||
// Check if a type is a fraction
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return ty >= FIRST_FRACTION_TYPE && ty <= LAST_FRACTION_TYPE;
|
||||
return handler[ty].is_fraction;
|
||||
}
|
||||
|
||||
|
||||
|
@ -514,6 +562,16 @@ struct object
|
|||
}
|
||||
|
||||
|
||||
static bool is_fractionable(id ty)
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if a type is a fraction or a non-based integer
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return handler[ty].is_fraction ||
|
||||
(handler[ty].is_integer && handler[ty].is_real);
|
||||
}
|
||||
|
||||
|
||||
bool is_fractionable() const
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if an object is a fraction or an integer
|
||||
|
@ -523,21 +581,12 @@ struct object
|
|||
}
|
||||
|
||||
|
||||
static bool is_fractionable(id ty)
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if a type is a fraction or a non-based integer
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return ty >= FIRST_REAL_TYPE && ty <= LAST_FRACTION_TYPE;
|
||||
}
|
||||
|
||||
|
||||
static bool is_decimal(id ty)
|
||||
// -------------------------------------------------------------------------
|
||||
// Check if a type is a decimal
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return ty >= FIRST_DECIMAL_TYPE && ty <= LAST_DECIMAL_TYPE;
|
||||
return handler[ty].is_decimal;
|
||||
}
|
||||
|
||||
|
||||
|
@ -555,7 +604,7 @@ struct object
|
|||
// Check if a type is a real number
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return ty >= FIRST_REAL_TYPE && ty <= LAST_REAL_TYPE;
|
||||
return handler[ty].is_real;
|
||||
}
|
||||
|
||||
|
||||
|
@ -573,7 +622,7 @@ struct object
|
|||
// Check if a type is a complex number
|
||||
// -------------------------------------------------------------------------
|
||||
{
|
||||
return ty >= FIRST_COMPLEX_TYPE && ty <= LAST_COMPLEX_TYPE;
|
||||
return handler[ty].is_complex;
|
||||
}
|
||||
|
||||
|
||||
|
@ -591,7 +640,7 @@ struct object
|
|||
// Check if a type denotes a command
|
||||
// ------------------------------------------------------------------------
|
||||
{
|
||||
return ty >= FIRST_COMMAND && ty <= LAST_COMMAND;
|
||||
return handler[ty].is_command;
|
||||
}
|
||||
|
||||
|
||||
|
@ -604,15 +653,48 @@ struct object
|
|||
}
|
||||
|
||||
|
||||
static bool is_immediate(id ty)
|
||||
// ------------------------------------------------------------------------
|
||||
// Check if a type denotes an immediate command (e.g. menus)
|
||||
// ------------------------------------------------------------------------
|
||||
{
|
||||
return handler[ty].is_immediate;
|
||||
}
|
||||
|
||||
|
||||
bool is_immediate() const
|
||||
// ------------------------------------------------------------------------
|
||||
// Check if an object is an immediate command (e.g. menus)
|
||||
// ------------------------------------------------------------------------
|
||||
{
|
||||
return is_immediate(type());
|
||||
}
|
||||
|
||||
|
||||
static bool is_algebraic_number(id ty)
|
||||
// ------------------------------------------------------------------------
|
||||
// Check if something is a number (real or complex)
|
||||
// ------------------------------------------------------------------------
|
||||
{
|
||||
return is_real(ty) || is_complex(ty);
|
||||
}
|
||||
|
||||
|
||||
bool is_algebraic_number() const
|
||||
// ------------------------------------------------------------------------
|
||||
// Check if something is a number (real or complex)
|
||||
// ------------------------------------------------------------------------
|
||||
{
|
||||
return is_algebraic_number(type());
|
||||
}
|
||||
|
||||
|
||||
static bool is_symbolic(id ty)
|
||||
// ------------------------------------------------------------------------
|
||||
// Check if a type denotes a symbolic argument (symbol, equation, number)
|
||||
// ------------------------------------------------------------------------
|
||||
{
|
||||
return (is_strictly_symbolic(ty) ||
|
||||
(ty >= FIRST_SYMBOLIC_TYPE && ty <= LAST_SYMBOLIC_TYPE) ||
|
||||
(ty >= FIRST_COMPLEX_TYPE && ty <= LAST_COMPLEX_TYPE) ||
|
||||
(ty >= FIRST_SYMBOLIC_CONSTANT && ty <= LAST_SYMBOLIC_CONSTANT));
|
||||
return handler[ty].is_symbolic || is_algebraic_number(ty);
|
||||
}
|
||||
|
||||
|
||||
|
@ -630,7 +712,7 @@ struct object
|
|||
// Check if a type denotes a symbol or equation
|
||||
// ------------------------------------------------------------------------
|
||||
{
|
||||
return ty == ID_symbol || ty == ID_equation || ty == ID_local;
|
||||
return handler[ty].is_symbolic;
|
||||
}
|
||||
|
||||
|
||||
|
@ -648,7 +730,7 @@ struct object
|
|||
// Check if a type denotes an algebraic function
|
||||
// ------------------------------------------------------------------------
|
||||
{
|
||||
return ty >= FIRST_ALGEBRAIC && ty <= LAST_ALGEBRAIC;
|
||||
return handler[ty].is_algebraic;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3385,7 +3385,7 @@ bool user_interface::handle_functions(int key)
|
|||
{
|
||||
evaluating = key;
|
||||
object::id ty = obj->type();
|
||||
bool imm = ty >= object::FIRST_IMMEDIATE && ty <= object::LAST_COMMAND;
|
||||
bool imm = object::is_immediate(ty);
|
||||
if (rt.editing() && !imm)
|
||||
{
|
||||
if (key == KEY_ENTER || key == KEY_BSP)
|
||||
|
|
Loading…
Reference in a new issue