[gcalctool] Error reporting and correction in ergonomic way.



commit ee76472d758098b8042c8f53ecafbe7ee54d6c72
Author: PioneerAxon <arth svnit gmail com>
Date:   Mon Oct 8 02:33:25 2012 +0530

    Error reporting and correction in ergonomic way.
    
    The error token is selected in the GUI, so user can just type in the
    correction to be replaced.

 src/gcalccmd.c         |    2 +-
 src/gcalctool.c        |    2 +-
 src/lexer.c            |   22 ++++----
 src/math-display.c     |   19 +++++++
 src/math-equation.c    |  138 ++++++++++++++++++++++++++++++++++++++++++++++--
 src/math-equation.h    |    6 ++
 src/mp-equation.c      |   15 ++++--
 src/mp-equation.h      |    2 +-
 src/parser.c           |    8 ++-
 src/parser.h           |    2 +
 src/parserfunc.c       |   30 ++++++-----
 src/parserfunc.h       |    2 +-
 src/test-mp-equation.c |    2 +-
 src/unit.c             |    2 +-
 14 files changed, 210 insertions(+), 42 deletions(-)
---
diff --git a/src/gcalccmd.c b/src/gcalccmd.c
index e65ac5a..91d29c2 100644
--- a/src/gcalccmd.c
+++ b/src/gcalccmd.c
@@ -35,7 +35,7 @@ solve(const char *equation)
     options.wordlen = 32;
     options.angle_units = MP_DEGREES;
     
-    ret = mp_equation_parse(equation, &options, &z, NULL);
+    ret = mp_equation_parse(equation, &options, &z, NULL, NULL, NULL);
 
     if (ret == PARSER_ERR_MP)
         fprintf(stderr, "Error %s\n", mp_get_error());
diff --git a/src/gcalctool.c b/src/gcalctool.c
index e481d37..e2d5c0c 100644
--- a/src/gcalctool.c
+++ b/src/gcalctool.c
@@ -54,7 +54,7 @@ solve(const char *equation)
     options.angle_units = MP_DEGREES;
     options.convert = do_convert;
 
-    error = mp_equation_parse(equation, &options, &result, NULL);
+    error = mp_equation_parse(equation, &options, &result, NULL, NULL, NULL);
     if(error == PARSER_ERR_MP) {
         fprintf(stderr, "Error: %s\n", mp_get_error());
         exit(1);
diff --git a/src/lexer.c b/src/lexer.c
index 176c773..0dabaa6 100644
--- a/src/lexer.c
+++ b/src/lexer.c
@@ -122,7 +122,7 @@ l_insert_next_token(LexerState* lstate)
         if((type = pl_get_next_token(state)) != PL_SUPER_DIGIT)
         {
             /* ERROR: expected PL_SUP_DIGIT */
-            set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring (state));
+            set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
             free(tmp);
             return l_insert_token(lstate, T_UNKNOWN);
         }
@@ -190,7 +190,7 @@ l_insert_next_token(LexerState* lstate)
                         else
                         {
                             /* ERROR: expected PL_SECOND */
-                            set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring (state));
+                            set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
                             free(tmp);
                             return l_insert_token(lstate, T_UNKNOWN);
                         }
@@ -201,7 +201,7 @@ ANGLE_NUM_DMS_STATE:
                         if((type = pl_get_next_token (state)) != PL_DIGIT)
                         {
                             /* ERROR: expected PL_DIGIT */
-                            set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state));
+                            set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
                             free(tmp);
                             return l_insert_token(lstate, T_UNKNOWN);
                         }
@@ -213,7 +213,7 @@ ANGLE_NUM_DMS_STATE:
                         else
                         {
                             /* ERROR: expected PL_SECOND */
-                            set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state));
+                            set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
                             free(tmp);
                             return l_insert_token(lstate, T_UNKNOWN);
                         }
@@ -227,7 +227,7 @@ ANGLE_NUM_DMS_STATE:
                 else
                 {
                     /* ERROR: expected PL_MINUTE | PL_DIGIT */
-                    set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state));
+                    set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
                     free(tmp);
                     return l_insert_token(lstate, T_UNKNOWN);
                 }
@@ -238,7 +238,7 @@ ANGLE_NUM_DM_STATE:
                 if((type = pl_get_next_token(state)) != PL_DIGIT)
                 {
                     /* ERROR: expected PL_DIGIT */
-                    set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state));
+                    set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
                     free(tmp);
                     return l_insert_token(lstate, T_UNKNOWN);
                 }
@@ -250,7 +250,7 @@ ANGLE_NUM_DM_STATE:
                 else
                 {
                     /* ERROR: expected PL_MINUTE */
-                    set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state));
+                    set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
                     free(tmp);
                     return l_insert_token(lstate, T_UNKNOWN);
                 }
@@ -308,7 +308,7 @@ DECIMAL_STATE:
         else
         {
             /* ERROR: expected PL_DIGIT | PL_HEX */
-            set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state));
+            set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
             free(tmp);
             return l_insert_token(lstate, T_UNKNOWN);
         }
@@ -341,7 +341,7 @@ HEX_DEC_STATE:
                     if(l_check_if_number(lstate))
                         return l_insert_token(lstate, T_NUMBER);
                     /* ERROR: expected PL_DECIMAL | PL_DIGIT | PL_HEX */
-                    set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state));
+                    set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
                     free(tmp);
                     return l_insert_token(lstate, T_UNKNOWN);
                 }
@@ -354,7 +354,7 @@ DECIMAL_HEX_STATE:
             if(!(type == PL_DIGIT || type == PL_HEX))
             {
                 /* ERROR: expected PL_DIGIT | PL_HEX */
-                set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state));
+                set_error(lstate->parent, PARSER_ERR_MP, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
                 free(tmp);
                 return l_insert_token(lstate, T_UNKNOWN);
             }
@@ -518,7 +518,7 @@ LETTER_STATE:
         return l_insert_token(lstate, PL_EOS);
     }
     /* ERROR: Unexpected token.. X( */
-    set_error(lstate->parent, PARSER_ERR_INVALID, tmp = pl_get_marked_substring(state));
+    set_error(lstate->parent, PARSER_ERR_INVALID, tmp = pl_get_marked_substring(state), state->mark_index, state->next_index);
     free(tmp);
     return l_insert_token(lstate, T_UNKNOWN);
 }
diff --git a/src/math-display.c b/src/math-display.c
index 6718665..9fb2374 100644
--- a/src/math-display.c
+++ b/src/math-display.c
@@ -319,6 +319,24 @@ status_changed_cb(MathEquation *equation, GParamSpec *spec, MathDisplay *display
 
 
 static void
+error_status_changed_cb(MathEquation *equation, GParamSpec *spec, MathDisplay *display)
+{
+    GtkTextIter start, end;
+    /* If both start and end locatoin of error token are the same, no need to select anything. */
+    if(math_equation_get_error_token_end(equation) - math_equation_get_error_token_start(equation) != 0)
+    {
+        gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(display->priv->equation), &start);
+        gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(display->priv->equation), &end);
+
+        gtk_text_iter_set_offset(&start, math_equation_get_error_token_start(equation));
+        gtk_text_iter_set_offset(&end, math_equation_get_error_token_end(equation));
+
+        gtk_text_buffer_select_range(GTK_TEXT_BUFFER(display->priv->equation), &start, &end);
+    }
+}
+
+
+static void
 create_gui(MathDisplay *display)
 {
     GtkWidget *info_view, *info_box, *main_box;
@@ -377,6 +395,7 @@ create_gui(MathDisplay *display)
     gtk_widget_show(main_box);
 
     g_signal_connect(display->priv->equation, "notify::status", G_CALLBACK(status_changed_cb), display);
+    g_signal_connect(display->priv->equation, "notify::error-token-end", G_CALLBACK(error_status_changed_cb), display);
     status_changed_cb(display->priv->equation, NULL, display);
 }
 
diff --git a/src/math-equation.c b/src/math-equation.c
index 5bcae64..bdfd026 100644
--- a/src/math-equation.c
+++ b/src/math-equation.c
@@ -44,7 +44,9 @@ enum {
     PROP_TARGET_CURRENCY,
     PROP_SOURCE_UNITS,
     PROP_TARGET_UNITS,  
-    PROP_SERIALIZER
+    PROP_SERIALIZER,
+    PROP_ERROR_TOKEN_START,
+    PROP_ERROR_TOKEN_END
 };
 
 static GType number_mode_type, number_format_type, angle_unit_type;
@@ -61,6 +63,8 @@ typedef struct {
     gboolean can_super_minus;  /* TRUE if entering minus can generate a superscript minus */
     gboolean entered_multiply; /* Last insert was a multiply character */
     gchar *status;             /* Equation status */
+    glong error_token_start;   /* Start offset of error token */
+    glong error_token_end;     /* End offset of error token */
 } MathEquationState;
 
 struct MathEquationPrivate
@@ -101,6 +105,8 @@ typedef struct {
     MPNumber *number_result;
     gchar *text_result;
     gchar *error;
+    glong error_start;
+    glong error_end;
 } SolveData;
 
 G_DEFINE_TYPE (MathEquation, math_equation, GTK_TYPE_TEXT_BUFFER);
@@ -761,7 +767,7 @@ math_equation_set_status(MathEquation *equation, const gchar *status)
 
     g_free(equation->priv->state.status);
     equation->priv->state.status = g_strdup(status);
-    g_object_notify(G_OBJECT(equation), "status");    
+    g_object_notify(G_OBJECT(equation), "status");
 }
 
 
@@ -773,6 +779,92 @@ math_equation_get_status(MathEquation *equation)
 }
 
 
+void
+math_equation_set_error_token_start(MathEquation *equation, glong error_start)
+{
+    equation->priv->state.error_token_start = error_start;
+}
+
+
+void
+math_equation_set_error_token_end(MathEquation *equation, glong error_end)
+{
+    equation->priv->state.error_token_end = error_end;
+}
+
+
+/* Fix the offsets to consider thousand separators inserted by the gui. */
+static void
+math_equation_error_token_fix_thousands_separator(MathEquation *equation)
+{
+    GtkTextIter start, end, temp;
+    gunichar ch = mp_serializer_get_thousands_separator(equation->priv->serializer);
+    gchar* str = g_ucs4_to_utf8(&ch, 1, NULL, NULL, NULL);
+    glong length = g_utf8_strlen(str, -1);
+
+    gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(equation), &start);
+    temp = end = start;
+
+    gtk_text_iter_set_offset(&start, math_equation_get_error_token_start(equation));
+    gtk_text_iter_set_offset(&end, math_equation_get_error_token_end(equation));
+
+    /* Move both start and end offsets for each thousand separator till the start of error token. */
+    while(gtk_text_iter_forward_search(&temp, str, GTK_TEXT_SEARCH_TEXT_ONLY, NULL, &temp, &start))
+    {
+        equation->priv->state.error_token_start += length;
+        equation->priv->state.error_token_end += length;
+        gtk_text_iter_forward_chars(&start, length);
+        gtk_text_iter_forward_chars(&end, length);
+    }
+
+    /* Starting from start, move only end offset for each thousand separator till the end of error token. */
+    temp = start;
+    while(gtk_text_iter_forward_search(&temp, str, GTK_TEXT_SEARCH_TEXT_ONLY, NULL, &temp, &end))
+    {
+        equation->priv->state.error_token_end += length;
+        gtk_text_iter_forward_chars(&end, length);
+    }
+}
+
+
+void
+math_equation_set_error(MathEquation *equation, glong error_start, glong error_end)
+{
+    math_equation_set_error_token_start(equation, error_start);
+    math_equation_set_error_token_end(equation, error_end);
+    /* Fix thousand separator offsets in the start and end offsets of error token. */
+    math_equation_error_token_fix_thousands_separator(equation);
+    /* Notify the GUI about the change in error token locations. */
+    g_object_notify (G_OBJECT(equation), "error_token_end");
+}
+
+
+glong
+math_equation_get_error_token_start(MathEquation *equation)
+{
+    gint ans_start, ans_end;
+    get_ans_offsets(equation, &ans_start, &ans_end);
+    /* Check if the previous answer is before start of error token.
+     * If so, subtract 3 (the length of string "ans") and add actual answer length (ans_end - ans_start) into it. */
+    if(ans_start != -1 && ans_start < equation->priv->state.error_token_start)
+        return equation->priv->state.error_token_start + ans_end - ans_start - 3;
+    return equation->priv->state.error_token_start;
+}
+
+
+glong
+math_equation_get_error_token_end(MathEquation *equation)
+{
+    gint ans_start, ans_end;
+    get_ans_offsets(equation, &ans_start, &ans_end);
+    /* Check if the previous answer is before end of error token.
+     * If so, subtract 3 (the length of string "ans") and add actual answer length (ans_end - ans_start) into it. */
+    if(ans_start != -1 && ans_start < equation->priv->state.error_token_end)
+        return equation->priv->state.error_token_end + ans_end - ans_start - 3;
+    return equation->priv->state.error_token_end;
+}
+
+
 gboolean
 math_equation_is_empty(MathEquation *equation)
 {
@@ -1163,7 +1255,7 @@ convert(const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z
 
 
 static int
-parse(MathEquation *equation, const char *text, MPNumber *z, char **error_token)
+parse(MathEquation *equation, const char *text, MPNumber *z, char **error_token, glong *error_start, glong *error_end)
 {
     MPEquationOptions options;
 
@@ -1177,7 +1269,7 @@ parse(MathEquation *equation, const char *text, MPNumber *z, char **error_token)
     options.convert = convert;
     options.callback_data = equation;
 
-    return mp_equation_parse(text, &options, z, error_token);
+    return mp_equation_parse(text, &options, z, error_token, error_start, error_end);
 }
 
 
@@ -1193,6 +1285,7 @@ math_equation_solve_real(gpointer data)
 
     gint n_brackets = 0, result;
     gchar *c, *text, *error_token;
+    glong error_start = 0, error_end = 0;
     GString *equation_text;
     MPNumber z;
 
@@ -1212,7 +1305,7 @@ math_equation_solve_real(gpointer data)
     }
 
 
-    result = parse(equation, equation_text->str, &z, &error_token);
+    result = parse(equation, equation_text->str, &z, &error_token, &error_start, &error_end);
     g_string_free(equation_text, TRUE);
 
     switch (result) {
@@ -1229,11 +1322,15 @@ math_equation_solve_real(gpointer data)
         case PARSER_ERR_UNKNOWN_VARIABLE:
             solvedata->error = g_strdup_printf(/* Error displayed to user when they an unknown variable is entered */
                                       _("Unknown variable '%s'"), error_token);
+            solvedata->error_start = error_start;
+            solvedata->error_end = error_end;
             break;
 
         case PARSER_ERR_UNKNOWN_FUNCTION:
             solvedata->error = g_strdup_printf(/* Error displayed to user when an unknown function is entered */
                                       _("Function '%s' is not defined"), error_token);
+            solvedata->error_start = error_start;
+            solvedata->error_end = error_end;
             break;
 
         case PARSER_ERR_UNKNOWN_CONVERSION:
@@ -1245,8 +1342,12 @@ math_equation_solve_real(gpointer data)
             if (mp_get_error())
                 solvedata->error = g_strdup(mp_get_error());
             else if (error_token)
+            {
                 solvedata->error = g_strdup_printf(/* Uncategorized error. Show error token to user*/
                                     _("Malformed expression at token '%s'"), error_token);
+                solvedata->error_start = error_start;
+                solvedata->error_end = error_end;
+            }
             else
                 solvedata->error = g_strdup (/* Unknown error. */
                                     _("Malformed expression"));
@@ -1289,6 +1390,7 @@ math_equation_look_for_answer(gpointer data)
 
     if (result->error != NULL) {
         math_equation_set_status(equation, result->error);
+        math_equation_set_error(equation, result->error_start, result->error_end);
         g_free(result->error);
     }
     else if (result->number_result != NULL) {
@@ -1553,6 +1655,12 @@ math_equation_set_property(GObject      *object,
     case PROP_TARGET_UNITS:
         math_equation_set_target_units(self, g_value_get_string(value));
         break;
+    case PROP_ERROR_TOKEN_START:
+        math_equation_set_error_token_start(self, g_value_get_long(value));
+        break;
+    case PROP_ERROR_TOKEN_END:
+        math_equation_set_error_token_end(self, g_value_get_long(value));
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -1624,6 +1732,12 @@ math_equation_get_property(GObject    *object,
     case PROP_SERIALIZER:
         g_value_set_object(value, self->priv->serializer);
         break;
+    case PROP_ERROR_TOKEN_START:
+        g_value_set_long(value, math_equation_get_error_token_start(self));
+        break;
+    case PROP_ERROR_TOKEN_END:
+        g_value_set_long(value, math_equation_get_error_token_end(self));
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
         break;
@@ -1787,6 +1901,20 @@ math_equation_class_init(MathEquationClass *klass)
                                                         "Serializer",
                                                         MP_TYPE_SERIALIZER,
                                                         G_PARAM_READABLE));
+    g_object_class_install_property(object_class,
+                                    PROP_ERROR_TOKEN_START,
+                                    g_param_spec_long("error-token-start",
+                                                      "error-token-start",
+                                                      "Error token start offset",
+                                                      G_MINLONG, G_MAXLONG, 0,
+                                                      G_PARAM_READWRITE));
+    g_object_class_install_property(object_class,
+                                    PROP_ERROR_TOKEN_END,
+                                    g_param_spec_long("error-token-end",
+                                                      "error-token-end",
+                                                      "Error token end offset",
+                                                      G_MINLONG, G_MAXLONG, 0,
+                                                      G_PARAM_READWRITE));
 }
 
 
diff --git a/src/math-equation.h b/src/math-equation.h
index 954334c..066f3f1 100644
--- a/src/math-equation.h
+++ b/src/math-equation.h
@@ -54,6 +54,12 @@ gunichar math_equation_get_digit_text(MathEquation *equation, guint digit);
 void math_equation_set_status(MathEquation *equation, const gchar *status);
 const gchar *math_equation_get_status(MathEquation *equation);
 
+void math_equation_set_error_token_start(MathEquation *equation, glong error_start);
+void math_equation_set_error_token_end(MathEquation *equation, glong error_end);
+void math_equation_set_error(MathEquation *equation, glong error_start, glong error_end);
+glong math_equation_get_error_token_start(MathEquation *equation);
+glong math_equation_get_error_token_end(MathEquation *equation);
+
 gboolean math_equation_is_empty(MathEquation *equation);
 gboolean math_equation_is_result(MathEquation *equation);
 gchar *math_equation_get_display(MathEquation *equation);
diff --git a/src/mp-equation.c b/src/mp-equation.c
index 9b6a195..0724fd3 100644
--- a/src/mp-equation.c
+++ b/src/mp-equation.c
@@ -245,7 +245,7 @@ convert(ParserState *state, const MPNumber *x, const char *x_units, const char *
 
 
 MPErrorCode
-mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result, char **error_token)
+mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result, char **error_token, glong *error_start, glong *error_end)
 {
     int ret;
     int err;
@@ -262,14 +262,21 @@ mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *
     state->get_function = get_function;
     state->convert = convert;
     state->error = 0;
+    state->error_token_start = 0;
+    state->error_token_end = 0;
     mp_clear_error();
     ret = p_parse (state);
-    if (state->error_token != NULL && error_token != NULL) {
-        *error_token = state->error_token;
+    if (state->error_token != NULL) {
+        if (error_token)
+            *error_token = state->error_token;
+        if (error_start)
+            *error_start = state->error_token_start;
+        if (error_end)
+            *error_end = state->error_token_end;
     }
     /* Error during parsing */
     if (state->error) {
-	err = state->error;
+        err = state->error;
         p_destroy_parser (state);
         return err;
     }
diff --git a/src/mp-equation.h b/src/mp-equation.h
index d6c0f24..cc1ff55 100644
--- a/src/mp-equation.h
+++ b/src/mp-equation.h
@@ -61,7 +61,7 @@ typedef struct {
     int (*convert)(const MPNumber *x, const char *x_units, const char *z_units, MPNumber *z, void *data);
 } MPEquationOptions;
 
-MPErrorCode mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result, char **error_token);
+MPErrorCode mp_equation_parse(const char *expression, MPEquationOptions *options, MPNumber *result, char **error_token, glong *error_start, glong *error_end);
 const char *mp_error_code_to_string(MPErrorCode error_code);
 
 int sub_atoi(const char *data);
diff --git a/src/parser.c b/src/parser.c
index fb4fd12..da61bc6 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -238,6 +238,8 @@ p_create_parser(const gchar* input, MPEquationOptions* options)
     state->options = options;
     state->error = 0;
     state->error_token = NULL;
+    state->error_token_start = 0;
+    state->error_token_end = 0;
     return state;
 }
 
@@ -259,7 +261,7 @@ p_parse(ParserState* state)
         {
         /* Full string is not parsed. */
             if(!state->error)
-                set_error(state, PARSER_ERR_INVALID, token->string);
+                set_error(state, PARSER_ERR_INVALID, token->string, token->start_index, token->end_index);
             return PARSER_ERR_INVALID;
         }
     }
@@ -267,7 +269,7 @@ p_parse(ParserState* state)
     {
         /* Full string is not parsed. */
         if(!state->error)
-            set_error(state, PARSER_ERR_INVALID, token->string);
+            set_error(state, PARSER_ERR_INVALID, token->string, token->start_index, token->end_index);
         return PARSER_ERR_INVALID;
     }
     if(ret == 0)
@@ -1166,7 +1168,7 @@ term(ParserState* state)
         /* Check if the token is a valid variable or not. */
         if(!p_check_variable(state, token->string))
         {
-            set_error(state, PARSER_ERR_UNKNOWN_VARIABLE, token->string);
+            set_error(state, PARSER_ERR_UNKNOWN_VARIABLE, token->string, token->start_index, token->end_index);
             return 0;
         }
         token = l_get_next_token(state->lexer);
diff --git a/src/parser.h b/src/parser.h
index 3efaa03..6599622 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -58,6 +58,8 @@ typedef struct parser_state
     MPEquationOptions *options;
     int error;
     char *error_token;
+    glong error_token_start;
+    glong error_token_end;
     MPNumber ret;
     int (*variable_is_defined)(struct parser_state *state, const char *name);
     int (*get_variable)(struct parser_state *state, const char *name, MPNumber *z);
diff --git a/src/parserfunc.c b/src/parserfunc.c
index edd34f6..4c8fb66 100644
--- a/src/parserfunc.c
+++ b/src/parserfunc.c
@@ -8,11 +8,15 @@
 
 /* Register error variables in ParserState structure. */
 void
-set_error(ParserState* state, gint errorno, const gchar *token)
+set_error(ParserState* state, gint errorno, const gchar *token, const gint token_start, const gint token_end)
 {
     state->error = errorno;
     if(token)
+    {
         state->error_token = strdup(token);
+        state->error_token_start = g_utf8_pointer_to_offset(state->lexer->prelexer->stream, state->lexer->prelexer->stream + token_start);
+        state->error_token_end = g_utf8_pointer_to_offset(state->lexer->prelexer->stream, state->lexer->prelexer->stream + token_end);
+    }
 }
 
 /* Unused function pointer. This won't be called anytime. */
@@ -78,7 +82,7 @@ pf_convert_number(ParseNode* self)
     }
     if(!(*(self->state->convert))(self->state, &tmp, from, to, ans))
     {
-        set_error(self->state, PARSER_ERR_UNKNOWN_CONVERSION, NULL);
+        set_error(self->state, PARSER_ERR_UNKNOWN_CONVERSION, NULL, 0, 0);
         free(ans);
         ans = NULL;
     }
@@ -129,7 +133,7 @@ pf_convert_1(ParseNode* self )
     }
     if(!(*(self->state->convert))(self->state, &tmp, from, to, ans))
     {
-        set_error(self->state, PARSER_ERR_UNKNOWN_CONVERSION, NULL);
+        set_error(self->state, PARSER_ERR_UNKNOWN_CONVERSION, NULL, 0, 0);
         free(ans);
         ans = NULL;
     }
@@ -211,9 +215,9 @@ pf_get_variable(ParseNode* self)
     }
     if(!result)
     {
-        free (ans);
+        free(ans);
         ans = NULL;
-        set_error(self->state, PARSER_ERR_UNKNOWN_VARIABLE, self->token->string);
+        set_error(self->state, PARSER_ERR_UNKNOWN_VARIABLE, self->token->string, self->token->start_index, self->token->end_index);
     }
     return ans;
 }
@@ -279,7 +283,7 @@ pf_get_variable_with_power(ParseNode* self)
     {
         free(ans);
         ans = NULL;
-        set_error(self->state, PARSER_ERR_UNKNOWN_VARIABLE, self->token->string);
+        set_error(self->state, PARSER_ERR_UNKNOWN_VARIABLE, self->token->string, self->token->start_index, self->token->end_index);
     }
     return ans;
 }
@@ -307,7 +311,7 @@ pf_apply_func(ParseNode* self)
     {
         free(val);
         free(ans);
-        set_error(self->state, PARSER_ERR_UNKNOWN_FUNCTION, self->token->string);
+        set_error(self->state, PARSER_ERR_UNKNOWN_FUNCTION, self->token->string, self->token->start_index, self->token->end_index);
         return NULL;
     }
     free(val);
@@ -346,7 +350,7 @@ pf_apply_func_with_power(ParseNode* self)
         free(ans);
         free(val);
         self->value = NULL;
-        set_error(self->state, PARSER_ERR_UNKNOWN_FUNCTION, self->token->string);
+        set_error(self->state, PARSER_ERR_UNKNOWN_FUNCTION, self->token->string, self->token->start_index, self->token->end_index);
         return NULL;
     }
     pow = super_atoi(((LexerToken*) self->value)->string);
@@ -395,7 +399,7 @@ pf_apply_func_with_npower(ParseNode* self)
         free(val);
         free(inv_name);
         self->value = NULL;
-        set_error(self->state, PARSER_ERR_UNKNOWN_FUNCTION, self->token->string);
+        set_error(self->state, PARSER_ERR_UNKNOWN_FUNCTION, self->token->string, self->token->start_index, self->token->end_index);
         return NULL;
     }
     pow = super_atoi(((LexerToken*) self->value)->string);
@@ -501,7 +505,7 @@ pf_do_floor(ParseNode* self)
 }
 
 /* Apply ceiling function. */
-void* pf_do_ceiling (ParseNode* self)
+void* pf_do_ceiling(ParseNode* self)
 {
     MPNumber* val;
     MPNumber* ans;
@@ -742,7 +746,7 @@ pf_do_subtract(ParseNode* self)
         if(left)
             free(left);
         if(right)
-            free (right);
+            free(right);
         free(ans);
         return NULL;
     }
@@ -864,7 +868,7 @@ pf_do_not(ParseNode* self)
     }
     if(!mp_is_overflow(val, self->state->options->wordlen))
     {
-        set_error(self->state, PARSER_ERR_OVERFLOW, NULL);
+        set_error(self->state, PARSER_ERR_OVERFLOW, NULL, 0, 0);
         free(ans);
         ans = NULL;
     }
@@ -959,7 +963,7 @@ pf_constant(ParseNode* self)
         /* This should never happen, as l_check_if_number() has already passed the string once. */
         /* If the code reaches this point, something is really wrong. X( */
         free(ans);
-        set_error(self->state, PARSER_ERR_INVALID, self->token->string);
+        set_error(self->state, PARSER_ERR_INVALID, self->token->string, self->token->start_index, self->token->end_index);
         return NULL;
     }
     return ans;
diff --git a/src/parserfunc.h b/src/parserfunc.h
index cf049b0..fd637a5 100644
--- a/src/parserfunc.h
+++ b/src/parserfunc.h
@@ -3,7 +3,7 @@
 
 #include "parser.h"
 
-void set_error(ParserState*, gint, const gchar*);
+void set_error(ParserState*, gint, const gchar*, const gint, const gint);
 
 void* pf_none(ParseNode*);
 
diff --git a/src/test-mp-equation.c b/src/test-mp-equation.c
index 95bb4a8..84aeb0d 100644
--- a/src/test-mp-equation.c
+++ b/src/test-mp-equation.c
@@ -77,7 +77,7 @@ test(char *expression, char *expected, int expected_error)
     MPErrorCode error;
     MPNumber result;
 
-    error = mp_equation_parse(expression, &options, &result, NULL);
+    error = mp_equation_parse(expression, &options, &result, NULL, NULL, NULL);
 
     if (error == 0) {
         char *result_str;
diff --git a/src/unit.c b/src/unit.c
index f7c0277..eda80fa 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -126,7 +126,7 @@ solve_function(const gchar *function, const MPNumber *x, MPNumber *z)
     options.variable_is_defined = variable_is_defined;
     options.get_variable = get_variable;
     options.callback_data = (void *)x;
-    ret = mp_equation_parse(function, &options, z, NULL);
+    ret = mp_equation_parse(function, &options, z, NULL, NULL, NULL);
     if (ret) {
         g_warning("Failed to convert value: %s", function);
         return FALSE;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]