From 5a7687e1b5685ee8edcee6768a967b43a7fd5570 Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Mon, 3 Sep 2018 00:10:13 +0200
Subject: [PATCH] Simple grammar tests

- read integer and real numbers
- numbers must be followed by semi-column (instructions)
- spaces and comments are consumed silently
- test error message improvements (rang)
---
 src/language/PastisParser.cpp | 136 +++++++++++++++++++++++++++++++---
 1 file changed, 124 insertions(+), 12 deletions(-)

diff --git a/src/language/PastisParser.cpp b/src/language/PastisParser.cpp
index 5752c11ae..703894b2d 100644
--- a/src/language/PastisParser.cpp
+++ b/src/language/PastisParser.cpp
@@ -1,46 +1,158 @@
 #include <PastisParser.hpp>
 #include <iostream>
 
+#include <rang.hpp>
+
 #define TAO_PEGTL_NAMESPACE language
 #include <pegtl.hpp>
+#include <pegtl/analyze.hpp>
+
 namespace language
 {
 using namespace tao::language;
 
 // clang-format off
-//struct prefix : string< 'H', 'e', 'l', 'l', 'o', ',', ' ' > {};
-struct prefix : TAO_PEGTL_STRING("Hello, ") {};
-struct name : plus< alpha > {};
+
+struct comment
+    : sor< if_must<
+             string< '/', '/' >,
+             until< eolf >
+             >,
+           if_must<
+             string< '/', '*' >,
+             until< string< '*', '/' > >
+             >
+           > {};
+
+struct ignored
+    : star< sor< space, comment>  >{};
+
+// struct ignored : star< space >{};
+
+struct integer
+    : seq< opt< one< '+', '-' > >, plus< digit > >{};
+struct INTEGER : seq< integer, ignored >{};
+
+struct real
+    : seq< opt< one< '+',
+                     '-' >
+                >,
+           sor< seq<
+                  plus< digit >,
+                  one < '.' >,
+                  star< digit >
+                  >,
+                seq<
+                  one < '.' >,
+                  plus< digit >
+                  >
+                >,
+           opt<
+             seq<
+               one< 'E',
+                    'e' >,
+               opt< one< '+',
+                         '-' >
+                    >,
+               plus<digit>
+               >
+             >
+           >{};
+
+struct REAL : seq< real, ignored >{};
+
+struct expression : sor< REAL, INTEGER > {};
+
+struct semicol : one< ';' >{};
+struct SEMICOL : seq< semicol , ignored > {};
+
+struct instruction
+    : sor<seq< expression , SEMICOL>,
+          SEMICOL>
+{};
+
 struct grammar
-    : must< prefix, name, star< sor< space, digit, string < '+' >, string < '-' >, string < '/' >, string < '*' > > >, one< '!' >, eof >
-{
-};
+    : must<star<instruction>,eof>{};
 // clang-format on
 
 template< typename Rule >
-struct action
-    : nothing< Rule >
+struct action : nothing< Rule > {};
+
+template<>
+struct action< integer >
 {
+  template< typename Input >
+  static void apply( const Input& in, std::string& v )
+  {
+    if (v.size() > 0) {
+      v += std::string(", I:") + in.string();
+    } else {
+      v = std::string("I:") + in.string();
+    }
+  }
 };
 
 template<>
-struct action< name >
+struct action< real >
 {
   template< typename Input >
   static void apply( const Input& in, std::string& v )
   {
-    v = in.string();
+    if (v.size() > 0) {
+      v += std::string(", R:") + in.string();
+    } else {
+      v = std::string("R:") + in.string();
+    }
+  }
+};
+
+
+template< typename Rule >
+struct errors
+    : public normal< Rule >
+{
+  static const std::string error_message;
+
+  template< typename Input, typename... States >
+  static void raise( const Input& in, States&&... /*unused*/ )
+  {
+    throw parse_error(error_message, std::vector{in.position()} );
   }
 };
+
+template <typename Rule>
+const std::string errors<Rule>::error_message = "parse error...";
+
+template <>
+const std::string errors<eolf>::error_message = "parse error expecting expression";
+
 }
 
 void parser(const std::string& filename) {
     std::string name;
 
+    const size_t grammar_issues = language::analyze< language::grammar >();
+
+    std::cout << "grammar_issues=" << grammar_issues << '\n';
     language::read_input in(filename);
-    language::parse< language::grammar, language::action >( in, name );
+    try {
+      language::parse< language::grammar, language::action//, language::errors
+                       >( in, name );
+    }
+    catch(const language::parse_error& e) {
+      const auto p = e.positions.front();
+      std::cerr << rang::style::bold
+                << p.source << ':' << p.line << ':' << p.byte_in_line<< ": "
+                << rang::style::reset
+                << rang::fgB::red << "error: " << rang::fg::reset
+                << rang::style::bold << e.what() << rang::style::reset << '\n'
+                << in.line_as_string( p ) << '\n'
+                << std::string( p.byte_in_line, ' ' )
+                << rang::fgB::yellow << '^' << rang::fg::reset
+                << std::endl;
+      std::exit(1);
+    }
 
-    std::cout << name << " -> ";
     std::cout << "Good bye, " << name << "!" << std::endl;
     std::exit(0);
 }
-- 
GitLab