From 0813b6995d344af14f8f2e7ed5042f30f99cdfd6 Mon Sep 17 00:00:00 2001
From: "Sven M. Hallberg" <pesco@khjk.org>
Date: Sun, 9 Feb 2020 18:09:20 +0100
Subject: [PATCH] differantiate error codes from h_compile() and update
 documentation

the regex backend already returned 2 for an internal failure, contrary to
documentation, so this mainly brings the latter in line with existing behavior.

at the same time, fix a bug: h_compile would previously return "false" (0) on
exceptions (longjmp).

make use of our new freedom to signal different error conditions from the
context-free backends, notably "incompatible combinator" vs. "unresolvable
conflict".
---
 src/backends/glr.c   |  2 +-
 src/backends/lalr.c  | 10 +++++-----
 src/backends/llk.c   |  2 +-
 src/backends/regex.c |  3 ++-
 src/benchmark.c      |  2 +-
 src/hammer.h         |  8 +++++++-
 6 files changed, 17 insertions(+), 10 deletions(-)

diff --git a/src/backends/glr.c b/src/backends/glr.c
index 535dc286..44b0c50c 100644
--- a/src/backends/glr.c
+++ b/src/backends/glr.c
@@ -14,7 +14,7 @@ int h_glr_compile(HAllocator* mm__, HParser* parser, const void* params)
   }
   int result = h_lalr_compile(mm__, parser, params);
 
-  if(result == -1 && parser->backend_data) {
+  if(result == -2 && parser->backend_data) {
     // table is there, just has conflicts? nevermind, that's okay.
     result = 0;
   }
diff --git a/src/backends/lalr.c b/src/backends/lalr.c
index b82ef71c..db9b88ae 100644
--- a/src/backends/lalr.c
+++ b/src/backends/lalr.c
@@ -279,18 +279,18 @@ int h_lalr_compile(HAllocator* mm__, HParser* parser, const void* params)
   }
   HCFGrammar *g = h_cfgrammar_(mm__, h_desugar_augmented(mm__, parser));
   if(g == NULL)     // backend not suitable (language not context-free)
-    return -1;
+    return 2;
 
   HLRDFA *dfa = h_lr0_dfa(g);
   if (dfa == NULL) {     // this should normally not happen
     h_cfgrammar_free(g);
-    return -1;
+    return 3;
   }
 
   HLRTable *table = h_lr0_table(g, dfa);
   if (table == NULL) {   // this should normally not happen
     h_cfgrammar_free(g);
-    return -1;
+    return 4;
   }
 
   if(has_conflicts(table)) {
@@ -300,7 +300,7 @@ int h_lalr_compile(HAllocator* mm__, HParser* parser, const void* params)
     if(eg == NULL) {    // this should normally not happen
       h_cfgrammar_free(g);
       h_lrtable_free(table);
-      return -1;
+      return 5;
     }
 
     // go through the inadequate states; replace inadeq with a new list
@@ -349,7 +349,7 @@ int h_lalr_compile(HAllocator* mm__, HParser* parser, const void* params)
 
   h_cfgrammar_free(g);
   parser->backend_data = table;
-  return has_conflicts(table)? -1 : 0;
+  return has_conflicts(table)? -2 : 0;
 }
 
 void h_lalr_free(HParser *parser)
diff --git a/src/backends/llk.c b/src/backends/llk.c
index 4e8209b3..19944a20 100644
--- a/src/backends/llk.c
+++ b/src/backends/llk.c
@@ -238,7 +238,7 @@ int h_llk_compile(HAllocator* mm__, HParser* parser, const void* params)
     // the table was ambiguous
     h_cfgrammar_free(grammar);
     h_llktable_free(table);
-    return -1;
+    return -2;
   }
   parser->backend_data = table;
 
diff --git a/src/backends/regex.c b/src/backends/regex.c
index f26abfda..0337949f 100644
--- a/src/backends/regex.c
+++ b/src/backends/regex.c
@@ -430,9 +430,10 @@ static int h_regex_compile(HAllocator *mm__, HParser* parser, const void* params
   prog->actions = NULL;
   prog->allocator = mm__;
   if (setjmp(prog->except)) {
-    return false;
+    return 3;
   }
   if (!h_compile_regex(prog, parser)) {
+    // this shouldn't normally fail when isValidRegular() returned true
     h_free(prog->insns);
     h_free(prog->actions);
     h_free(prog);
diff --git a/src/benchmark.c b/src/benchmark.c
index b6a2876f..7d56c32e 100644
--- a/src/benchmark.c
+++ b/src/benchmark.c
@@ -46,7 +46,7 @@ HBenchmarkResults *h_benchmark__m(HAllocator* mm__, HParser* parser, HParserTest
   for (backend = PB_MIN; backend <= PB_MAX; backend++) {
     ret->results[backend].backend = backend;
     // Step 1: Compile grammar for given parser...
-    if (h_compile(parser, backend, NULL) == -1) {
+    if (h_compile(parser, backend, NULL)) {
       // backend inappropriate for grammar...
       fprintf(stderr, "Compiling for %s failed\n", HParserBackendNames[backend]);
       ret->results[backend].compile_success = false;
diff --git a/src/hammer.h b/src/hammer.h
index c8a1074c..6cd2660d 100644
--- a/src/hammer.h
+++ b/src/hammer.h
@@ -785,7 +785,13 @@ void h_pprintln(FILE* stream, const HParsedToken* tok);
  * documentation for the parser backend in question for information
  * about the [params] parameter, or just pass in NULL for the defaults.
  *
- * Returns -1 if grammar cannot be compiled with the specified options; 0 otherwise.
+ * Returns a nonzero value on error; 0 otherwise. Common return codes include:
+ *
+ *  -1: parser uses a combinator that is incompatible with the chosen backend.
+ *  -2: parser could not be compiled with the chosen parameters.
+ *  >0: unexpected internal errors.
+ *
+ * Consult each backend for details.
  */
 HAMMER_FN_DECL(int, h_compile, HParser* parser, HParserBackend backend, const void* params);
 
-- 
GitLab