libgimpwidgets: use struct, not parameters, to pass eevl options

Pass the evaluation options to gimp_eevl_evaluate() using a single
parameter of type GimpEevlOptions, instead of using individual
parameters for each option.  Add a GIMP_EEVL_OPTIONS_INIT macro,
used to initialize a GimpEevlOptions struct to the default set of
options.  This would allow us to add evaluation options more
easily.
This commit is contained in:
Ell 2017-10-04 08:41:16 -04:00
parent 0ae7acd594
commit 7362d47922
4 changed files with 104 additions and 87 deletions

View File

@ -105,62 +105,58 @@ typedef struct
typedef struct typedef struct
{ {
const gchar *string; const gchar *string;
GimpEevlUnitResolverProc unit_resolver_proc; GimpEevlOptions options;
gpointer data;
GimpEevlToken current_token; GimpEevlToken current_token;
const gchar *start_of_current_token; const gchar *start_of_current_token;
jmp_buf catcher;
jmp_buf catcher; const gchar *error_message;
const gchar *error_message;
} GimpEevl; } GimpEevl;
static void gimp_eevl_init (GimpEevl *eva, static void gimp_eevl_init (GimpEevl *eva,
const gchar *string, const gchar *string,
GimpEevlUnitResolverProc unit_resolver_proc, const GimpEevlOptions *options);
gpointer data); static GimpEevlQuantity gimp_eevl_complete (GimpEevl *eva);
static GimpEevlQuantity gimp_eevl_complete (GimpEevl *eva); static GimpEevlQuantity gimp_eevl_expression (GimpEevl *eva);
static GimpEevlQuantity gimp_eevl_expression (GimpEevl *eva); static GimpEevlQuantity gimp_eevl_term (GimpEevl *eva);
static GimpEevlQuantity gimp_eevl_term (GimpEevl *eva); static GimpEevlQuantity gimp_eevl_signed_factor (GimpEevl *eva);
static GimpEevlQuantity gimp_eevl_signed_factor (GimpEevl *eva); static GimpEevlQuantity gimp_eevl_factor (GimpEevl *eva);
static GimpEevlQuantity gimp_eevl_factor (GimpEevl *eva); static gboolean gimp_eevl_accept (GimpEevl *eva,
static gboolean gimp_eevl_accept (GimpEevl *eva, GimpEevlTokenType token_type,
GimpEevlTokenType token_type, GimpEevlToken *consumed_token);
GimpEevlToken *consumed_token); static void gimp_eevl_lex (GimpEevl *eva);
static void gimp_eevl_lex (GimpEevl *eva); static void gimp_eevl_lex_accept_count (GimpEevl *eva,
static void gimp_eevl_lex_accept_count (GimpEevl *eva, gint count,
gint count, GimpEevlTokenType token_type);
GimpEevlTokenType token_type); static void gimp_eevl_lex_accept_to (GimpEevl *eva,
static void gimp_eevl_lex_accept_to (GimpEevl *eva, gchar *to,
gchar *to, GimpEevlTokenType token_type);
GimpEevlTokenType token_type); static void gimp_eevl_move_past_whitespace (GimpEevl *eva);
static void gimp_eevl_move_past_whitespace (GimpEevl *eva); static gboolean gimp_eevl_unit_identifier_start (gunichar c);
static gboolean gimp_eevl_unit_identifier_start (gunichar c); static gboolean gimp_eevl_unit_identifier_continue (gunichar c);
static gboolean gimp_eevl_unit_identifier_continue (gunichar c); static gint gimp_eevl_unit_identifier_size (const gchar *s,
static gint gimp_eevl_unit_identifier_size (const gchar *s, gint start);
gint start); static void gimp_eevl_expect (GimpEevl *eva,
static void gimp_eevl_expect (GimpEevl *eva, GimpEevlTokenType token_type,
GimpEevlTokenType token_type, GimpEevlToken *value);
GimpEevlToken *value); static void gimp_eevl_error (GimpEevl *eva,
static void gimp_eevl_error (GimpEevl *eva, gchar *msg);
gchar *msg);
/** /**
* gimp_eevl_evaluate: * gimp_eevl_evaluate:
* @string: The NULL-terminated string to be evaluated. * @string: The NULL-terminated string to be evaluated.
* @unit_resolver_proc: Unit resolver callback. * @options: Evaluations options.
* @result: Result of evaluation. * @result: Result of evaluation.
* @data: Data passed to unit resolver. * @error_pos: Will point to the positon within the string,
* @error_pos: Will point to the positon within the string, * before which the parse / evaluation error
* before which the parse / evaluation error * occurred. Will be set to null of no error occurred.
* occurred. Will be set to null of no error occurred. * @error_message: Will point to a static string with a semi-descriptive
* @error_message: Will point to a static string with a semi-descriptive * error message if parsing / evaluation failed.
* error message if parsing / evaluation failed.
* *
* Evaluates the given arithmetic expression, along with an optional dimension * Evaluates the given arithmetic expression, along with an optional dimension
* analysis, and basic unit conversions. * analysis, and basic unit conversions.
@ -174,24 +170,23 @@ static void gimp_eevl_error (GimpEevl
* order of two means in^2). * order of two means in^2).
**/ **/
gboolean gboolean
gimp_eevl_evaluate (const gchar *string, gimp_eevl_evaluate (const gchar *string,
GimpEevlUnitResolverProc unit_resolver_proc, const GimpEevlOptions *options,
GimpEevlQuantity *result, GimpEevlQuantity *result,
gpointer data, const gchar **error_pos,
const gchar **error_pos, GError **error)
GError **error)
{ {
GimpEevl eva; GimpEevl eva;
g_return_val_if_fail (g_utf8_validate (string, -1, NULL), FALSE); g_return_val_if_fail (g_utf8_validate (string, -1, NULL), FALSE);
g_return_val_if_fail (unit_resolver_proc != NULL, FALSE); g_return_val_if_fail (options != NULL, FALSE);
g_return_val_if_fail (options->unit_resolver_proc != NULL, FALSE);
g_return_val_if_fail (result != NULL, FALSE); g_return_val_if_fail (result != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
gimp_eevl_init (&eva, gimp_eevl_init (&eva,
string, string,
unit_resolver_proc, options);
data);
if (!setjmp (eva.catcher)) /* try... */ if (!setjmp (eva.catcher)) /* try... */
{ {
@ -214,14 +209,12 @@ gimp_eevl_evaluate (const gchar *string,
} }
static void static void
gimp_eevl_init (GimpEevl *eva, gimp_eevl_init (GimpEevl *eva,
const gchar *string, const gchar *string,
GimpEevlUnitResolverProc unit_resolver_proc, const GimpEevlOptions *options)
gpointer data)
{ {
eva->string = string; eva->string = string;
eva->unit_resolver_proc = unit_resolver_proc; eva->options = *options;
eva->data = data;
eva->current_token.type = GIMP_EEVL_TOKEN_END; eva->current_token.type = GIMP_EEVL_TOKEN_END;
@ -246,9 +239,9 @@ gimp_eevl_complete (GimpEevl *eva)
/* There should be nothing left to parse by now */ /* There should be nothing left to parse by now */
gimp_eevl_expect (eva, GIMP_EEVL_TOKEN_END, 0); gimp_eevl_expect (eva, GIMP_EEVL_TOKEN_END, 0);
eva->unit_resolver_proc (NULL, eva->options.unit_resolver_proc (NULL,
&default_unit_factor, &default_unit_factor,
eva->data); eva->options.data);
/* Entire expression is dimensionless, apply default unit if /* Entire expression is dimensionless, apply default unit if
* applicable * applicable
@ -282,9 +275,9 @@ gimp_eevl_expression (GimpEevl *eva)
{ {
GimpEevlQuantity default_unit_factor; GimpEevlQuantity default_unit_factor;
eva->unit_resolver_proc (NULL, eva->options.unit_resolver_proc (NULL,
&default_unit_factor, &default_unit_factor,
eva->data); eva->options.data);
if (new_term.dimension == 0 && if (new_term.dimension == 0 &&
evaluated_terms.dimension == default_unit_factor.dimension) evaluated_terms.dimension == default_unit_factor.dimension)
@ -393,9 +386,9 @@ gimp_eevl_factor (GimpEevl *eva)
strncpy (identifier, consumed_token.value.c, consumed_token.value.size); strncpy (identifier, consumed_token.value.c, consumed_token.value.size);
identifier[consumed_token.value.size] = '\0'; identifier[consumed_token.value.size] = '\0';
if (eva->unit_resolver_proc (identifier, if (eva->options.unit_resolver_proc (identifier,
&result, &result,
eva->data)) eva->options.data))
{ {
evaluated_factor.value /= result.value; evaluated_factor.value /= result.value;
evaluated_factor.dimension += result.dimension; evaluated_factor.dimension += result.dimension;

View File

@ -54,12 +54,31 @@ typedef gboolean (* GimpEevlUnitResolverProc) (const gchar *identifier,
GimpEevlQuantity *result, GimpEevlQuantity *result,
gpointer data); gpointer data);
gboolean gimp_eevl_evaluate (const gchar *string,
GimpEevlUnitResolverProc unit_resolver_proc, /**
GimpEevlQuantity *result, * GimpEevlOptions:
gpointer data, * @unit_resolver_proc: Unit resolver callback.
const gchar **error_pos, * @data: Data passed to unit resolver.
GError **error); */
typedef struct
{
GimpEevlUnitResolverProc unit_resolver_proc;
gpointer data;
} GimpEevlOptions;
#define GIMP_EEVL_OPTIONS_INIT \
((const GimpEevlOptions) \
{ \
.unit_resolver_proc = NULL, \
.data = NULL \
})
gboolean gimp_eevl_evaluate (const gchar *string,
const GimpEevlOptions *options,
GimpEevlQuantity *result,
const gchar **error_pos,
GError **error);
G_END_DECLS G_END_DECLS

View File

@ -1270,6 +1270,7 @@ gimp_size_entry_eevl_input_callback (GtkSpinButton *spinner,
gpointer *data) gpointer *data)
{ {
GimpSizeEntryField *gsef = (GimpSizeEntryField *) data; GimpSizeEntryField *gsef = (GimpSizeEntryField *) data;
GimpEevlOptions options = GIMP_EEVL_OPTIONS_INIT;
gboolean success = FALSE; gboolean success = FALSE;
const gchar *error_pos = 0; const gchar *error_pos = 0;
GError *error = NULL; GError *error = NULL;
@ -1278,10 +1279,12 @@ gimp_size_entry_eevl_input_callback (GtkSpinButton *spinner,
g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spinner), FALSE); g_return_val_if_fail (GTK_IS_SPIN_BUTTON (spinner), FALSE);
g_return_val_if_fail (GIMP_IS_SIZE_ENTRY (gsef->gse), FALSE); g_return_val_if_fail (GIMP_IS_SIZE_ENTRY (gsef->gse), FALSE);
options.unit_resolver_proc = gimp_size_entry_eevl_unit_resolver;
options.data = data;
success = gimp_eevl_evaluate (gtk_entry_get_text (GTK_ENTRY (spinner)), success = gimp_eevl_evaluate (gtk_entry_get_text (GTK_ENTRY (spinner)),
gimp_size_entry_eevl_unit_resolver, &options,
&result, &result,
data,
&error_pos, &error_pos,
&error); &error);
if (! success) if (! success)

View File

@ -112,17 +112,19 @@ main(void)
for (i = 0; cases[i].string; i++) for (i = 0; cases[i].string; i++)
{ {
const gchar *test = cases[i].string; const gchar *test = cases[i].string;
GimpEevlQuantity should = cases[i].result; GimpEevlOptions options = GIMP_EEVL_OPTIONS_INIT;
GimpEevlQuantity result = { 0, -1 }; GimpEevlQuantity should = cases[i].result;
gboolean should_succeed = cases[i].should_succeed; GimpEevlQuantity result = { 0, -1 };
GError *error = NULL; gboolean should_succeed = cases[i].should_succeed;
const gchar *error_pos = 0; GError *error = NULL;
const gchar *error_pos = 0;
options.unit_resolver_proc = test_units;
gimp_eevl_evaluate (test, gimp_eevl_evaluate (test,
test_units, &options,
&result, &result,
NULL,
&error_pos, &error_pos,
&error); &error);