Author: mriou
Date: Tue Jan 20 17:31:33 2009
New Revision: 736186

URL: http://svn.apache.org/viewvc?rev=736186&view=rev
Log:
Improved parser error messages.

Added:
    
ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/util/ErrorMessageBuilder.java
Modified:
    ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPEL.g
    ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPELWalker.g
    ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/ErrorListener.java
    
ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/util/DefaultErrorListener.java
    
ode/sandbox/simpel/src/test/java/org/apache/ode/simpel/SimPELCompilerTest.java

Modified: ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPEL.g
URL: 
http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPEL.g?rev=736186&r1=736185&r2=736186&view=diff
==============================================================================
--- ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPEL.g 
(original)
+++ ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPEL.g Tue 
Jan 20 17:31:33 2009
@@ -14,6 +14,13 @@
     SIGNAL; JOIN; WITH; MAP;
     EXPR; EXT_EXPR; XML_LITERAL; CALL; NAMESPACE; NS; PATH;
 }
+
+...@lexer::header {
+package org.apache.ode.simpel.antlr;
+import org.apache.ode.simpel.ErrorListener;
+import org.apache.ode.simpel.util.ErrorMessageBuilder;
+}
+
 @parser::header {
 package org.apache.ode.simpel.antlr;
 
@@ -21,12 +28,9 @@
 import uk.co.badgersinfoil.e4x.antlr.LinkedListTree;
 import uk.co.badgersinfoil.e4x.E4XHelper;
 import org.apache.ode.simpel.ErrorListener;
+import org.apache.ode.simpel.util.ErrorMessageBuilder;
 import org.apache.ode.simpel.util.JSHelper;
 }
-...@lexer::header {
-package org.apache.ode.simpel.antlr;
-import org.apache.ode.simpel.ErrorListener;
-}
 
 @lexer::members {
     private ErrorListener el;
@@ -35,7 +39,12 @@
        this.el = el;
     }
     public void displayRecognitionError(String[] tokenNames, 
RecognitionException e) {
-       el.reportRecognitionError(tokenNames, e.line, getErrorMessage(e, 
tokenNames), e);
+       el.reportRecognitionError(e.line, e.charPositionInLine, 
getErrorMessage(e, tokenNames), e);
+    }
+    public String getErrorMessage(RecognitionException e, String[] tokenNames) 
{
+        String msg = ErrorMessageBuilder.msg(e, tokenNames, null);
+        if (msg == null) msg = super.getErrorMessage(e, tokenNames);
+        return msg;
     }
 }
 
@@ -45,6 +54,7 @@
     private SimPELLexer lexer;
     private CharStream cs;
     private ErrorListener el;
+    private Stack paraphrases = new Stack();
     
     public void setInput(SimPELLexer lexer, CharStream cs) {
         this.lexer = lexer;
@@ -64,20 +74,14 @@
     }
     
     public void displayRecognitionError(String[] tokenNames, 
RecognitionException e) {
-         el.reportRecognitionError(tokenNames, e.line, getErrorMessage(e, 
tokenNames), e);
+        el.reportRecognitionError(e.line, e.charPositionInLine, 
getErrorMessage(e, tokenNames), e);
     }
     
     public String getErrorMessage(RecognitionException e, String[] tokenNames) 
{
-             List stack = getRuleInvocationStack(e, this.getClass().getName());
-         String msg = null;
-         if ( e instanceof NoViableAltException ) {
-                   NoViableAltException nvae = (NoViableAltException)e;
-                   msg = " no viable alt; token="+e.token+" 
(decision="+nvae.decisionNumber+" state "+nvae.stateNumber+")"+
-                  " decision=<<"+nvae.grammarDecisionDescription+">>";
-        } else {
-            msg = super.getErrorMessage(e, tokenNames);
-        }
-        return stack+" "+msg;
+//       List stack = getRuleInvocationStack(e, this.getClass().getName());
+        String msg = ErrorMessageBuilder.msg(e, tokenNames, (String) 
paraphrases.peek());
+        if (msg == null) msg = super.getErrorMessage(e, tokenNames);
+        return msg;
     }
     
     public String getTokenErrorDisplay(Token t) {
@@ -95,102 +99,193 @@
 process        :       'process' ns_id body -> ^(PROCESS ns_id body);
 
 proc_stmt
+...@init { paraphrases.push("in a process"); }
+...@after { paraphrases.pop(); }
        :       pick | flow | if_ex | while_ex | until_ex | foreach | forall | 
try_ex | scope_ex | with_ex
                | receive | request | invoke | ((reply | assign | throw_ex | 
wait_ex | exit | signal | join
                | variables | partner_link) SEMI!);
 
-block  :       '{' proc_stmt+ '}' -> ^(SEQUENCE proc_stmt+);
+block
+...@init { paraphrases.push("in a block of statements"); }
+...@after { paraphrases.pop(); }
+        :      '{' proc_stmt+ '}' -> ^(SEQUENCE proc_stmt+);
+
 param_block
+...@init { paraphrases.push("in a parameterized block of statements"); }
+...@after { paraphrases.pop(); }
        :       '{' ('|' in+=ID (',' in+=ID)* '|')? proc_stmt+ '}' -> 
^(SEQUENCE $in* proc_stmt+);
+
 body   :       block | proc_stmt;
 
 // Structured activities
-pick   :       'pick' '{' receive* timeout* '}' -> ^(PICK receive* timeout*);
-timeout        :       'timeout' '(' expr ')' block -> ^(TIMEOUT expr block); 
-
-flow   :       'parallel' b+=body ('and' b+=body)* -> ^(FLOW $b*);
+pick
+...@init { paraphrases.push("in a pick"); }
+...@after { paraphrases.pop(); }
+        :      'pick' '{' receive* timeout* '}' -> ^(PICK receive* timeout*);
+
+timeout
+...@init { paraphrases.push("in a timeout"); }
+...@after { paraphrases.pop(); }
+        :      'timeout' '(' expr ')' block -> ^(TIMEOUT expr block);
+
+flow
+...@init { paraphrases.push("in a flow"); }
+...@after { paraphrases.pop(); }
+        :      'parallel' b+=body ('and' b+=body)* -> ^(FLOW $b*);
 signal :       'signal' '('ID (',' expr)? ')' -> ^(SIGNAL ID expr?);
 join   :       'join' '(' k+=ID (',' k+=ID)* (',' expr)? ')' -> ^(JOIN $k+ 
expr?);
 
-if_ex  :       'if' '(' expr ')' ifb=body ('else' eb=body)? -> ^(IF expr $ifb 
(^(ELSE $eb))?);
-
-while_ex:      'while' '(' expr ')' body -> ^(WHILE expr body);
-
-until_ex:      'do' body 'until' '(' expr ')' -> ^(UNTIL expr body);
-
-foreach        :       'for' '(' ID '=' init=expr ';' cond=expr ';' assign ')' 
body -> ^(FOREACH ID $init $cond assign body);
-forall :       'forall' '(' ID '=' from=expr 'to' to=expr ')' body -> ^(FORALL 
ID $from $to body);
-
-try_ex :       'try' body catch_ex* -> ^(TRY body catch_ex*);          
-catch_ex:      'catch' '(' ns_id ')' param_block -> ^(CATCH ns_id param_block);
-
-scope_ex:      'scope' ('(' ID ')')? body scope_stmt* -> ^(SCOPE ID? body 
scope_stmt*);
+if_ex
+...@init { paraphrases.push("in a if expression"); }
+...@after { paraphrases.pop(); }
+        :      'if' '(' expr ')' ifb=body ('else' eb=body)? -> ^(IF expr $ifb 
(^(ELSE $eb))?);
+
+while_ex
+...@init { paraphrases.push("in a while"); }
+...@after { paraphrases.pop(); }
+        :      'while' '(' expr ')' body -> ^(WHILE expr body);
+
+until_ex
+...@init { paraphrases.push("in an until"); }
+...@after { paraphrases.pop(); }
+        :      'do' body 'until' '(' expr ')' -> ^(UNTIL expr body);
+
+foreach
+...@init { paraphrases.push("in a foreach loop"); }
+...@after { paraphrases.pop(); }
+        :      'for' '(' ID '=' init=expr ';' cond=expr ';' assign ')' body -> 
^(FOREACH ID $init $cond assign body);
+forall
+...@init { paraphrases.push("in a forall loop"); }
+...@after { paraphrases.pop(); }
+        :      'forall' '(' ID '=' from=expr 'to' to=expr ')' body -> ^(FORALL 
ID $from $to body);
+
+try_ex
+...@init { paraphrases.push("in a try block"); }
+...@after { paraphrases.pop(); }
+        :      'try' body catch_ex* -> ^(TRY body catch_ex*);
+catch_ex
+...@init { paraphrases.push("in a catch block"); }
+...@after { paraphrases.pop(); }
+        :      'catch' '(' ns_id ')' param_block -> ^(CATCH ns_id param_block);
+
+scope_ex
+...@init { paraphrases.push("in a scope declaration"); }
+...@after { paraphrases.pop(); }
+        :      'scope' ('(' ID ')')? body scope_stmt* -> ^(SCOPE ID? body 
scope_stmt*);
 scope_stmt
-       :       onevent | onalarm | compensation | onquery | onrec | onupd;
+       :       onevent | onalarm | compensation | onquery | onrec | onupd;
+
+onevent
+...@init { paraphrases.push("in an onEvent"); }
+...@after { paraphrases.pop(); }
+        :      'onEvent' '(' p=ID ',' o=ID ')' param_block -> ^(ONEVENT $p $o 
param_block);
+onalarm
+...@init { paraphrases.push("in an onAlarm"); }
+...@after { paraphrases.pop(); }
+        :      'onAlarm' '(' expr ')' body -> ^(ONALARM expr body);
+onquery
+...@init { paraphrases.push("in an onQuery"); }
+...@after { paraphrases.pop(); }
+        :      'onQuery' '(' r=ID ')' body -> ^(ONQUERY $r body);
+onrec
+...@init { paraphrases.push("in an onReceive"); }
+...@after { paraphrases.pop(); }
+        :      'onReceive' '(' r=ID ')' body -> ^(ONRECEIVE $r body);
+onupd
+...@init { paraphrases.push("in an onUpdate"); }
+...@after { paraphrases.pop(); }
+        :      'onUpdate' '(' r=ID ')' body -> ^(ONUPDATE $r body);
 
-onevent        :       'onEvent' '(' p=ID ',' o=ID ')' param_block -> 
^(ONEVENT $p $o param_block);
-onalarm        :       'onAlarm' '(' expr ')' body -> ^(ONALARM expr body);
-onquery        :       'onQuery' '(' r=ID ')' body -> ^(ONQUERY $r body);
-onrec  :       'onReceive' '(' r=ID ')' body -> ^(ONRECEIVE $r body);
-onupd  :       'onUpdate' '(' r=ID ')' body -> ^(ONUPDATE $r body);
 compensation
+...@init { paraphrases.push("in an compensation"); }
+...@after { paraphrases.pop(); }
        :       'compensation' body -> ^(COMPENSATION body);
 
-with_ex :
-                'with' '(' wm+=with_map (',' wm+=with_map)* ')' body -> ^(WITH 
$wm+ body);
+with_ex
+...@init { paraphrases.push("in a with expression"); }
+...@after { paraphrases.pop(); }
+        : 'with' '(' wm+=with_map (',' wm+=with_map)* ')' body -> ^(WITH $wm+ 
body);
 with_map:       ID ':' path_expr -> ^(MAP ID path_expr);
 
 // Simple activities
 
-invoke
-        :      invoke_base param_block -> ^(INVOKE invoke_base) param_block
+invoke : invoke_base param_block -> ^(INVOKE invoke_base) param_block
           | invoke_base SEMI -> ^(INVOKE invoke_base);
 invoke_base
+...@init { paraphrases.push("in an invoke"); }
+...@after { paraphrases.pop(); }
         :      'invoke' '(' p=ID ',' o=ID (',' in=ID)? ')' -> ^($p $o $in?);
 
-receive        
-        :      receive_base param_block -> ^(RECEIVE receive_base) param_block
+receive        : receive_base param_block -> ^(RECEIVE receive_base) 
param_block
           | receive_base SEMI -> ^(RECEIVE receive_base);
 receive_base
-             : 'receive' '(' p=ID (',' o=ID (',' correlation)? )? ')' -> ^($p 
$o? correlation?);
+...@init { paraphrases.push("in a receive"); }
+...@after { paraphrases.pop(); }
+        : 'receive' '(' p=ID (',' o=ID (',' correlation)? )? ')' -> ^($p $o? 
correlation?);
 
 request
 options {backtrack=true;}
         :      request_base param_block -> ^(REQUEST request_base) param_block
           | request_base SEMI -> ^(REQUEST request_base);
+
 request_base
+...@init { paraphrases.push("in a request"); }
+...@after { paraphrases.pop(); }
         :      'request' '(' expr (',' meth=STRING (',' msg=ID)?)? ')' -> 
^(REQ_BASE expr $meth? $msg?);
 
-reply    :     'reply' '(' ID (',' ID (',' ID)?)? ')' -> ^(REPLY ID (ID ID?)?);
-
-assign :       path_expr '=' rvalue -> ^(ASSIGN path_expr rvalue);
+reply
+...@init { paraphrases.push("in a reply"); }
+...@after { paraphrases.pop(); }
+        : 'reply' '(' ID (',' ID (',' ID)?)? ')' -> ^(REPLY ID (ID ID?)?);
+
+assign
+...@init { paraphrases.push("in an assignment"); }
+...@after { paraphrases.pop(); }
+        : path_expr '=' rvalue -> ^(ASSIGN path_expr rvalue);
 rvalue
-           :   receive_base -> ^(RECEIVE receive_base)
-                   | invoke_base -> ^(INVOKE invoke_base)
-        | request_base -> ^(REQUEST request_base)
-        | resource | expr | xml_literal;
+...@init { paraphrases.push("in an assignment right value"); }
+...@after { paraphrases.pop(); }
+           : receive_base -> ^(RECEIVE receive_base)
+                 | invoke_base -> ^(INVOKE invoke_base)
+          | request_base -> ^(REQUEST request_base)
+          | resource | expr | xml_literal;
        
-throw_ex:      'throw' '('? ns_id ')'? -> ^(THROW ns_id);
+throw_ex
+...@init { paraphrases.push("in a throw"); }
+...@after { paraphrases.pop(); }
+        : 'throw' '('? ns_id ')'? -> ^(THROW ns_id);
+
+wait_ex
+...@init { paraphrases.push("in a wait"); }
+...@after { paraphrases.pop(); }
 
-wait_ex        :       'wait' '('expr')' -> ^(WAIT expr);
+        : 'wait' '('expr')' -> ^(WAIT expr);
 
 compensate
-       :       'compensate' ('(' ID ')')? -> ^(COMPENSATE ID?);
+...@init { paraphrases.push("in a compensate"); }
+...@after { paraphrases.pop(); }
+           : 'compensate' ('(' ID ')')? -> ^(COMPENSATE ID?);
 
 exit   :       'exit' -> ^(EXIT);
 
 // Others
 namespace
-       :       'namespace' ID '=' STRING SEMI -> ^(NAMESPACE ID STRING);
+        : 'namespace' ID '=' STRING SEMI -> ^(NAMESPACE ID STRING);
 
 resource
-    :   'resource' '(' expr? (',' ID)? ')' -> ^(RESOURCE expr? ID?);
+...@init { paraphrases.push("in a resource declaration"); }
+...@after { paraphrases.pop(); }
+        : 'resource' '(' expr? (',' ID)? ')' -> ^(RESOURCE expr? ID?);
 
 variables
-       :       'var'! v+=variable (','! v+=variable)*;
+...@init { paraphrases.push("in variable declaration"); }
+...@after { paraphrases.pop(); }
+        : 'var'! v+=variable (','! v+=variable)*;
 variable:      ID VAR_MODS* -> ^(VARIABLE ID VAR_MODS*);
 
 partner_link
+...@init { paraphrases.push("in a partner link declaration"); }
+...@after { paraphrases.pop(); }
        :       'partnerLink' pl+=ID (',' pl+=ID)* -> ^(PARTNERLINK $pl+);
 
 correlation

Modified: 
ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPELWalker.g
URL: 
http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPELWalker.g?rev=736186&r1=736185&r2=736186&view=diff
==============================================================================
--- 
ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPELWalker.g 
(original)
+++ 
ode/sandbox/simpel/src/main/antlr/org/apache/ode/simpel/antlr/SimPELWalker.g 
Tue Jan 20 17:31:33 2009
@@ -31,7 +31,7 @@
          this.el = el;
     }
     public void displayRecognitionError(String[] tokenNames, 
RecognitionException e) {
-         el.reportRecognitionError(tokenNames, e.line, getErrorMessage(e, 
tokenNames), e);
+         el.reportRecognitionError(e.line, e.charPositionInLine, 
getErrorMessage(e, tokenNames), e);
     }
     
     public String getErrorMessage(RecognitionException e, String[] tokenNames) 
{

Modified: 
ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/ErrorListener.java
URL: 
http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/ErrorListener.java?rev=736186&r1=736185&r2=736186&view=diff
==============================================================================
--- ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/ErrorListener.java 
(original)
+++ ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/ErrorListener.java 
Tue Jan 20 17:31:33 2009
@@ -7,5 +7,5 @@
  */
 public interface ErrorListener {
 
-    public void reportRecognitionError(String[] tokens, int line, String 
message, RecognitionException e);
+    public void reportRecognitionError(int line, int column, String message, 
RecognitionException e);
 }

Modified: 
ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/util/DefaultErrorListener.java
URL: 
http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/util/DefaultErrorListener.java?rev=736186&r1=736185&r2=736186&view=diff
==============================================================================
--- 
ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/util/DefaultErrorListener.java
 (original)
+++ 
ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/util/DefaultErrorListener.java
 Tue Jan 20 17:31:33 2009
@@ -17,20 +17,20 @@
         return _errors;
     }
 
-    public void reportRecognitionError(String[] tokens, int line, String 
message, RecognitionException e) {
-        _errors.add(new Error(tokens, line, message, e));
-        System.err.println("line " + line + ": " +  message);
+    public void reportRecognitionError(int line, int column, String message, 
RecognitionException e) {
+        _errors.add(new Error(line, column, message, e));
+        System.err.println(line + ":" + column + " " +  message);
     }
 
     public class Error {
-        public String tokens[];
         public int line;
+        public int column;
         public String message;
         public RecognitionException e;
 
-        public Error(String[] tokens, int line, String message, 
RecognitionException e) {
-            this.tokens = tokens;
+        public Error(int line, int column, String message, 
RecognitionException e) {
             this.line = line;
+            this.column = column;
             this.message = message;
             this.e = e;
         }

Added: 
ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/util/ErrorMessageBuilder.java
URL: 
http://svn.apache.org/viewvc/ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/util/ErrorMessageBuilder.java?rev=736186&view=auto
==============================================================================
--- 
ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/util/ErrorMessageBuilder.java
 (added)
+++ 
ode/sandbox/simpel/src/main/java/org/apache/ode/simpel/util/ErrorMessageBuilder.java
 Tue Jan 20 17:31:33 2009
@@ -0,0 +1,27 @@
+package org.apache.ode.simpel.util;
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.NoViableAltException;
+import org.antlr.runtime.MismatchedTokenException;
+import org.antlr.runtime.EarlyExitException;
+
+/**
+ * ANTLR-specific error message builder. Analyzes parser exceptions raised by 
ANTLR and
+ * produces a user-friendly error message for SimPEL.
+ */
+public class ErrorMessageBuilder {
+
+    public static String msg(RecognitionException e, String[] tokenNames, 
String paraphrase) {
+        String msg = null;
+        if (e instanceof NoViableAltException) {
+            msg = "Syntax error, unexpected token " + 
tokenNames[e.token.getType()];
+        } else if (e instanceof MismatchedTokenException) {
+            MismatchedTokenException mte = (MismatchedTokenException) e;
+            msg = "Syntax error, unexpected token " + 
tokenNames[e.token.getType()] + ", expecting " + tokenNames[mte.expecting];
+        } else if (e instanceof EarlyExitException) {
+            msg = "At least one element is required at " + 
tokenNames[e.token.getType()];
+        }
+        if (msg != null && paraphrase != null) msg = msg + " " + paraphrase;
+        return msg;
+    }
+}

Modified: 
ode/sandbox/simpel/src/test/java/org/apache/ode/simpel/SimPELCompilerTest.java
URL: 
http://svn.apache.org/viewvc/ode/sandbox/simpel/src/test/java/org/apache/ode/simpel/SimPELCompilerTest.java?rev=736186&r1=736185&r2=736186&view=diff
==============================================================================
--- 
ode/sandbox/simpel/src/test/java/org/apache/ode/simpel/SimPELCompilerTest.java 
(original)
+++ 
ode/sandbox/simpel/src/test/java/org/apache/ode/simpel/SimPELCompilerTest.java 
Tue Jan 20 17:31:33 2009
@@ -137,7 +137,7 @@
     private static class TestErrorListener implements ErrorListener {
         public StringBuffer messages = new StringBuffer();
 
-        public void reportRecognitionError(String[] tokens, int line, String 
message, RecognitionException e) {
+        public void reportRecognitionError(int line, int column, String 
message, RecognitionException e) {
             messages.append(" - line ").append(line).append(": 
").append(message).append("\n");
         }
     }


Reply via email to