[gcalctool/vala] Port Arth's recent error reporting change



commit ec0aadf3e77bcdafb394ddd6bcfd45e76d33ba8d
Author: Robert Ancell <robert ancell canonical com>
Date:   Sun Oct 14 16:13:11 2012 +1300

    Port Arth's recent error reporting change

 src/equation-lexer.vala  |   20 +++++-----
 src/equation-parser.vala |   44 ++++++++++++++++-------
 src/equation.vala        |    4 +-
 src/math-display.vala    |   18 +++++++++
 src/math-equation.vala   |   91 ++++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 149 insertions(+), 28 deletions(-)
---
diff --git a/src/equation-lexer.vala b/src/equation-lexer.vala
index b3d9fc8..a14c83a 100644
--- a/src/equation-lexer.vala
+++ b/src/equation-lexer.vala
@@ -365,7 +365,7 @@ public class Lexer
             if ((type = prelexer.get_next_token ()) != LexerTokenType.PL_SUPER_DIGIT)
             {
                 /* ERROR: expected LexerTokenType.PL_SUP_DIGIT */
-                parser.set_error (ErrorCode.MP, prelexer.get_marked_substring ());
+                parser.set_error (ErrorCode.MP, prelexer.get_marked_substring (), prelexer.mark_index, prelexer.index);
                 return insert_token (LexerTokenType.UNKNOWN);
             }
 
@@ -414,7 +414,7 @@ public class Lexer
             return insert_token (LexerTokenType.PL_EOS);
 
         /* ERROR: Unexpected token */
-        parser.set_error (ErrorCode.INVALID, prelexer.get_marked_substring ());
+        parser.set_error (ErrorCode.INVALID, prelexer.get_marked_substring (), prelexer.mark_index, prelexer.index);
 
         return insert_token (LexerTokenType.UNKNOWN);
     }
@@ -455,7 +455,7 @@ public class Lexer
                         else
                         {
                             /* ERROR: expected LexerTokenType.PL_SECOND */
-                            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring ());
+                            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring (), prelexer.mark_index, prelexer.index);
                             return insert_token (LexerTokenType.UNKNOWN);
                         }
                     }
@@ -470,7 +470,7 @@ public class Lexer
                 else
                 {
                     /* ERROR: expected LexerTokenType.PL_MINUTE | LexerTokenType.PL_DIGIT */
-                    parser.set_error (ErrorCode.MP, prelexer.get_marked_substring ());
+                    parser.set_error (ErrorCode.MP, prelexer.get_marked_substring (), prelexer.mark_index, prelexer.index);
                     return insert_token (LexerTokenType.UNKNOWN);
                 }
             }
@@ -496,7 +496,7 @@ public class Lexer
         if (type != LexerTokenType.PL_DIGIT)
         {
             /* ERROR: expected LexerTokenType.PL_DIGIT */
-            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring ());
+            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring (), prelexer.mark_index, prelexer.index);
             return insert_token (LexerTokenType.UNKNOWN);
         }
 
@@ -508,7 +508,7 @@ public class Lexer
         else
         {
             /* ERROR: expected LexerTokenType.PL_MINUTE */
-            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring ());
+            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring (), prelexer.mark_index, prelexer.index);
             return insert_token (LexerTokenType.UNKNOWN);
         }
     }
@@ -519,7 +519,7 @@ public class Lexer
         if (type != LexerTokenType.PL_DIGIT)
         {
             /* ERROR: expected LexerTokenType.PL_DIGIT */
-            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring ());
+            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring (), prelexer.mark_index, prelexer.index);
             return insert_token (LexerTokenType.UNKNOWN);
         }
         while ((type = prelexer.get_next_token ()) == LexerTokenType.PL_DIGIT);
@@ -528,7 +528,7 @@ public class Lexer
         else
         {
             /* ERROR: expected LexerTokenType.PL_SECOND */
-            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring ());
+            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring (), prelexer.mark_index, prelexer.index);
             return insert_token (LexerTokenType.UNKNOWN);
         }
     }
@@ -560,7 +560,7 @@ public class Lexer
         else
         {
             /* ERROR: expected LexerTokenType.PL_DIGIT | LexerTokenType.PL_HEX */
-            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring ());
+            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring (), prelexer.mark_index, prelexer.index);
             return insert_token (LexerTokenType.UNKNOWN);
         }
     }
@@ -626,7 +626,7 @@ public class Lexer
             if (check_if_number ())
                 return insert_token (LexerTokenType.NUMBER);
             /* ERROR: expected LexerTokenType.PL_DECIMAL | LexerTokenType.PL_DIGIT | LexerTokenType.PL_HEX */
-            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring ());
+            parser.set_error (ErrorCode.MP, prelexer.get_marked_substring (), prelexer.mark_index, prelexer.index);
             return insert_token (LexerTokenType.UNKNOWN);
         }
     }
diff --git a/src/equation-parser.vala b/src/equation-parser.vala
index 65ddb56..2410d7b 100644
--- a/src/equation-parser.vala
+++ b/src/equation-parser.vala
@@ -161,7 +161,7 @@ public class VariableNode : ParseNode
             var t = parser.get_variable (c.to_string ());
             if (t == null)
             {
-                parser.set_error (ErrorCode.UNKNOWN_VARIABLE, token.text);
+                parser.set_error (ErrorCode.UNKNOWN_VARIABLE, token.text, token.start_index, token.end_index);
                 return null;
             }
             value = value.multiply (t);
@@ -199,7 +199,7 @@ public class VariableWithPowerNode : ParseNode
             var t = parser.get_variable (c.to_string ());
             if (t == null)
             {
-                parser.set_error (ErrorCode.UNKNOWN_VARIABLE, token.text);
+                parser.set_error (ErrorCode.UNKNOWN_VARIABLE, token.text, token.start_index, token.end_index);
                 return null;
             }
 
@@ -226,7 +226,7 @@ public class FunctionNode : RNode
     {
         var ans = parser.get_function (token.text, r);
         if (ans == null)
-            parser.set_error (ErrorCode.UNKNOWN_FUNCTION, token.text);
+            parser.set_error (ErrorCode.UNKNOWN_FUNCTION, token.text, token.start_index, token.end_index);
 
         return ans;
     }
@@ -251,7 +251,7 @@ public class FunctionWithPowerNode : ParseNode
         if (tmp == null)
         {
             value = null;
-            parser.set_error (ErrorCode.UNKNOWN_FUNCTION, token.text);
+            parser.set_error (ErrorCode.UNKNOWN_FUNCTION, token.text, token.start_index, token.end_index);
             return null;
         }
 
@@ -282,7 +282,7 @@ public class FunctionWithNegativePowerNode : ParseNode
         if (tmp == null)
         {
             value = null;
-            parser.set_error (ErrorCode.UNKNOWN_FUNCTION, token.text);
+            parser.set_error (ErrorCode.UNKNOWN_FUNCTION, token.text, token.start_index, token.end_index);
             return null;
         }
 
@@ -538,7 +538,7 @@ public class NotNode : RNode
     {
         if (!mp_is_overflow (r, parser.wordlen))
         {
-            parser.set_error (ErrorCode.OVERFLOW, null);
+            parser.set_error (ErrorCode.OVERFLOW);
             return new Number.integer (0);
         }
 
@@ -616,7 +616,7 @@ public class ConvertNode : LRNode
 
         var ans = parser.convert (tmp, from, to);
         if (ans == null)
-            parser.set_error (ErrorCode.UNKNOWN_CONVERSION, null);
+            parser.set_error (ErrorCode.UNKNOWN_CONVERSION);
 
         return ans;
     }
@@ -655,7 +655,7 @@ public class ConvertNumberNode : ParseNode
 
         var ans = parser.convert (tmp, from, to);
         if (ans == null)
-            parser.set_error (ErrorCode.UNKNOWN_CONVERSION, null);
+            parser.set_error (ErrorCode.UNKNOWN_CONVERSION);
 
         return ans;
     }
@@ -663,6 +663,7 @@ public class ConvertNumberNode : ParseNode
 
 public class Parser
 {
+    private string input;
     private ParseNode root;
     private ParseNode right_most;
     private Lexer lexer;
@@ -671,9 +672,12 @@ public class Parser
     private uint depth_level;
     private ErrorCode error;
     private string error_token;
+    private int error_token_start;
+    private int error_token_end;
 
     public Parser (string input, int number_base, int wordlen)
     {
+        this.input = input;
         lexer = new Lexer (input, this, number_base);
         root = null;
         depth_level = 0;
@@ -682,12 +686,16 @@ public class Parser
         this.wordlen = wordlen;
         error = ErrorCode.NONE;
         error_token = null;
+        error_token_start = 0;
+        error_token_end = 0;
     }
 
-    public void set_error (ErrorCode errorno, string? token)
+    public void set_error (ErrorCode errorno, string? token = null, uint token_start = 0, uint token_end = 0)
     {
         error = errorno;
         error_token = token;
+        error_token_start = input.char_count (token_start);
+        error_token_end = input.char_count (token_end);
     }
 
     public virtual bool variable_is_defined (string name)
@@ -720,7 +728,7 @@ public class Parser
     }
 
     /* Start parsing input string. And call evaluate on success. */
-    public Number? parse (out ErrorCode error_code, out string? error_token)
+    public Number? parse (out ErrorCode error_code, out string? error_token, out uint error_start, out uint error_end)
     {
         /* Scan string and split into tokens */
         lexer.scan ();
@@ -736,10 +744,12 @@ public class Parser
             {
                 /* Full string is not parsed. */
                 if (error == 0)
-                    set_error (ErrorCode.INVALID, token.text);
+                    set_error (ErrorCode.INVALID, token.text, token.start_index, token.end_index);
 
                 error_code = error;
                 error_token = this.error_token;
+                error_start = error_token_start;
+                error_end = error_token_end;
                 return null;
             }
         }
@@ -747,10 +757,12 @@ public class Parser
         {
             /* Full string is not parsed. */
             if (error == 0)
-                set_error (ErrorCode.INVALID, token.text);
+                set_error (ErrorCode.INVALID, token.text, token.start_index, token.end_index);
 
             error_code = error;
             error_token = this.error_token;
+            error_start = error_token_start;
+            error_end = error_token_end;
             return null;
         }
 
@@ -759,6 +771,8 @@ public class Parser
         {
             error_code = error;
             error_token = this.error_token;
+            error_start = error_token_start;
+            error_end = error_token_end;
             return null;
         }
         var ans = root.solve ();
@@ -766,11 +780,15 @@ public class Parser
         {
             error_code = ErrorCode.INVALID;
             error_token = null;
+            error_start = error_token_start;
+            error_end = error_token_end;
             return null;
         }
 
         error_code = ErrorCode.NONE;
         error_token = null;
+        error_start = 0;
+        error_end = 0;
         return ans;
     }
 
@@ -1658,7 +1676,7 @@ public class Parser
             /* Check if the token is a valid variable or not. */
             if (!check_variable (token.text))
             {
-                set_error (ErrorCode.UNKNOWN_VARIABLE, token.text);
+                set_error (ErrorCode.UNKNOWN_VARIABLE, token.text, token.start_index, token.end_index);
                 return false;
             }
             token = lexer.get_next_token ();
diff --git a/src/equation.vala b/src/equation.vala
index fa327ea..d2a4465 100644
--- a/src/equation.vala
+++ b/src/equation.vala
@@ -114,12 +114,12 @@ public class Equation
         this.expression = expression;
     }
 
-    public new Number? parse (out ErrorCode error_code = null, out string error_token = null)
+    public new Number? parse (out ErrorCode error_code = null, out string error_token = null, out uint error_start = null, out uint error_end = null)
     {
         var parser = new EquationParser (this, expression);
         mp_clear_error ();
 
-        var z = parser.parse (out error_code, out error_token);
+        var z = parser.parse (out error_code, out error_token, out error_start, out error_end);
 
         /* Error during parsing */
         if (error_code != ErrorCode.NONE)
diff --git a/src/math-display.vala b/src/math-display.vala
index 5c2884d..a466f26 100644
--- a/src/math-display.vala
+++ b/src/math-display.vala
@@ -76,6 +76,8 @@ public class MathDisplay : Gtk.Viewport
 
         equation.notify["status"].connect ((pspec) => { status_changed_cb (); });
         status_changed_cb ();
+
+        equation.notify["error-token-end"].connect ((pspec) => { error_status_changed_cb (); });
     }
 
     protected override bool key_press_event (Gdk.EventKey event)
@@ -334,4 +336,20 @@ public class MathDisplay : Gtk.Viewport
             spinner.stop ();
         }
     }
+
+    private void error_status_changed_cb ()
+    {
+        /* If both start and end location of error token are the same, no need to select anything. */
+        if (equation.error_token_end - equation.error_token_start == 0)
+            return;
+
+        Gtk.TextIter start, end;
+        equation.get_start_iter (out start);
+        equation.get_start_iter (out end);
+
+        start.set_offset ((int) equation.error_token_start);
+        end.set_offset ((int) equation.error_token_end);
+
+        equation.select_range (start, end);
+    }
 }
diff --git a/src/math-equation.vala b/src/math-equation.vala
index 6a94b0f..5163909 100644
--- a/src/math-equation.vala
+++ b/src/math-equation.vala
@@ -28,6 +28,8 @@ private class MathEquationState
     public bool can_super_minus;   /* true if entering minus can generate a superscript minus */
     public bool entered_multiply;  /* Last insert was a multiply character */
     public string status;          /* Equation status */
+    public uint error_token_start; /* Start offset of error token */
+    public uint error_token_end;   /* End offset of error token */
 }
 
 private class SolveData
@@ -35,6 +37,8 @@ private class SolveData
     public Number? number_result;
     public string text_result;
     public string error;
+    public uint error_start;
+    public uint error_end;
 }
 
 public class MathEquation : Gtk.TextBuffer
@@ -602,6 +606,36 @@ public class MathEquation : Gtk.TextBuffer
         }
     }
 
+    public uint error_token_start
+    {
+        get
+        {
+            /* 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. */
+            int ans_start, ans_end;
+            get_ans_offsets (out ans_start, out ans_end);
+            if (ans_start != -1 && ans_start < state.error_token_start)
+                return state.error_token_start + ans_end - ans_start - 3;
+
+            return state.error_token_start;
+        }
+    }
+
+    public uint error_token_end
+    {
+        get
+        {
+            /* 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. */
+            int ans_start, ans_end;
+            get_ans_offsets (out ans_start, out ans_end);
+            if (ans_start != -1 && ans_start < state.error_token_end)
+                return state.error_token_end + ans_end - ans_start - 3;
+
+            return state.error_token_end;
+        }
+    }
+
     public bool is_empty
     {
         get { return get_char_count () == 0; }
@@ -790,14 +824,14 @@ public class MathEquation : Gtk.TextBuffer
         }
     }
 
-    private Number? parse (string text, out ErrorCode error_code = null, out string error_token = null)
+    private Number? parse (string text, out ErrorCode error_code = null, out string error_token = null, out uint error_start, out uint error_end)
     {
         var equation = new MEquation (this, text);
         equation.base = serializer.get_base ();
         equation.wordlen = word_size;
         equation.angle_units = angle_units;
 
-        return equation.parse (out error_code, out error_token);
+        return equation.parse (out error_code, out error_token, out error_start, out error_end);
     }
 
     /*
@@ -826,7 +860,8 @@ public class MathEquation : Gtk.TextBuffer
 
         ErrorCode error_code;
         string error_token;
-        var z = parse (text, out error_code, out error_token);
+        uint error_start, error_end;
+        var z = parse (text, out error_code, out error_token, out error_start, out error_end);
         switch (error_code)
         {
             case ErrorCode.NONE:
@@ -841,11 +876,15 @@ public class MathEquation : Gtk.TextBuffer
             case ErrorCode.UNKNOWN_VARIABLE:
                 solvedata.error = /* Error displayed to user when they an unknown variable is entered */
                                   _("Unknown variable '%s'").printf (error_token);
+                solvedata.error_start = error_start;
+                solvedata.error_end = error_end;
                 break;
 
             case ErrorCode.UNKNOWN_FUNCTION:
                 solvedata.error = /* Error displayed to user when an unknown function is entered */
                                   _("Function '%s' is not defined").printf (error_token);
+                solvedata.error_start = error_start;
+                solvedata.error_end = error_end;
                 break;
 
             case ErrorCode.UNKNOWN_CONVERSION:
@@ -857,7 +896,11 @@ public class MathEquation : Gtk.TextBuffer
                 if (mp_get_error () != null)
                     solvedata.error = mp_get_error ();
                 else if (error_token != null) /* Uncategorized error. Show error token to user */
+                {
                     solvedata.error = _("Malformed expression at token '%s'").printf (error_token);
+                    solvedata.error_start = error_start;
+                    solvedata.error_end = error_end;
+                }
                 else /* Unknown error. */
                     solvedata.error = _("Malformed expression");
                 break;
@@ -892,7 +935,17 @@ public class MathEquation : Gtk.TextBuffer
             status = "";
 
         if (result.error != null)
+        {
             status = result.error;
+            state.error_token_start = result.error_start;
+            state.error_token_end = result.error_end;
+
+            /* Fix thousand separator offsets in the start and end offsets of error token. */
+            error_token_fix_thousands_separator ();
+
+            /* Notify the GUI about the change in error token locations. */
+            notify_property ("error-token-end");
+        }
         else if (result.number_result != null)
             set_number (result.number_result);
         else if (result.text_result != null)
@@ -928,6 +981,38 @@ public class MathEquation : Gtk.TextBuffer
         Timeout.add (100, show_in_progress);
     }
 
+    /* Fix the offsets to consider thousand separators inserted by the gui. */
+    private void error_token_fix_thousands_separator ()
+    {
+        Gtk.TextIter start;
+        get_start_iter (out start);
+        var temp = start;
+        var end = start;
+
+        start.set_offset ((int) error_token_start);
+        end.set_offset ((int) error_token_end);
+
+        var str = serializer.get_thousands_separator ().to_string ();
+        var length = str.char_count ();
+
+        /* Move both start and end offsets for each thousand separator till the start of error token. */
+        while (temp.forward_search (str, Gtk.TextSearchFlags.TEXT_ONLY, null, out temp, start))
+        {
+            state.error_token_start += length;
+            state.error_token_end += length;
+            start.forward_chars (length);
+            start.forward_chars (length);
+        }
+
+        /* Starting from start, move only end offset for each thousand separator till the end of error token. */
+        temp = start;
+        while (temp.forward_search (str, Gtk.TextSearchFlags.TEXT_ONLY, null, out temp, end))
+        {
+            state.error_token_end += length;
+            end.forward_chars (length);
+        }
+    }
+
     private void* factorize_real ()
     {
         var x = number;



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