b2af95094f4c — Danielle Hutzley 2 years ago
Implement error position handling
7 files changed, 80 insertions(+), 20 deletions(-)

M README.md
M include/laal.h
M include/meson.build
M meson.build
M src/laal.c
M src/laal_parser.c
M test/interface.c
M README.md +5 -4
@@ 14,12 14,10 @@ LAAL is a simple syntax for expressing p
 
 - [ ] Stage 1: bootstrap
   - [x] A. LibLAAL parser in C99
-  - [ ] B. LibLAAG code generator in C99
-  - [ ] C. Systems LAAL in C99
+  - [ ] B. Systems LAAL in C99 emitting C
 - [ ] Stage 2: self-hosted
   - [ ] A. LibLAAL parser in Systems LAAL
-  - [ ] B. LibLAAG code generator in Systems LAAL
-  - [ ] C. Systems LAAL in itself
+  - [ ] B. Systems LAAL in itself
 - [ ] Stage 3: scripting implementation
   - [ ] A. LibLAARS scripting runtime/VM in Systems LAAL
   - [ ] B. Scripting LAAL in Systems LAAL

          
@@ 27,6 25,9 @@ LAAL is a simple syntax for expressing p
   - [ ] A. LAAB build system (supersceding Muon for building LAAL)
   - [ ] B. LAAD markup (supersceding POD for docs)
   - [ ] C. LibTAAL editor tooling (supersceding handwritten tooling for LAAL)
+- [ ] Unknown
+  - [ ] LibLAAG code generator (possible backends: QBE, C, WASM)
+    - Postponed until further understanding is gained and Systems LAAL is self-hosted
 
 ## Requirements
 

          
M include/laal.h +5 -2
@@ 35,6 35,7 @@ extern "C"
   } laal_position_t;
 
   extern const laal_position_t LAAL_DEFAULT_POSITION;
+  extern const laal_position_t LAAL_INVALID_POSITION;
 
   __LAAL_PURE
   bool laal_position_equal (laal_position_t x, laal_position_t y);

          
@@ 81,12 82,14 @@ extern "C"
 
   /// Parse a LAAL source file into a laal_value (always of type LAAL_MAP)
   __LAAL_MUST_USE
-  laal_error_t laal_parse_file (FILE *stream, laal_value_t *result);
+  laal_error_t laal_parse_file (FILE *stream, laal_value_t *result,
+                                laal_position_t *error_pos);
 
   /// Parse LAAL source from a given string, make sure there is a null
   /// terminator!
   __LAAL_MUST_USE
-  laal_error_t laal_parse_string (const char *string, laal_value_t *result);
+  laal_error_t laal_parse_string (const char *string, laal_value_t *result,
+                                  laal_position_t *error_pos);
 
   /// Output the LAAL source representation of a given value to a file
   /// This consumes the value, so it should be copied beforehand if needed

          
M include/meson.build +1 -1
@@ 21,4 21,4 @@ configure_file(input : 'laal_config.h.in
                configuration : config)
 
 include = include_directories('.')
-install_headers(headers, subdir : 'laal')
+install_headers(headers)

          
M meson.build +2 -2
@@ 5,9 5,9 @@ 
 #
 # Project info
 project(
-  'laal', 
+  'liblaal',
   ['c'], 
-  version : '0.0.2',
+  version : '0.0.3',
   license : 'MPL-2.0',
   default_options : [
     'c_std=c99',

          
M src/laal.c +43 -6
@@ 40,6 40,11 @@ const laal_position_t LAAL_DEFAULT_POSIT
   .col = 0,
 };
 
+const laal_position_t LAAL_INVALID_POSITION = {
+  .row = UINTPTR_MAX,
+  .col = UINTPTR_MAX,
+};
+
 bool
 laal_position_equal (laal_position_t x, laal_position_t y)
 {

          
@@ 269,30 274,62 @@ laal_value_compare (const laal_value_t x
 }
 
 laal_error_t
-laal_parse_file (FILE *stream, laal_value_t *output)
+laal_parse_file (FILE *stream, laal_value_t *output,
+                 laal_position_t *error_pos)
 {
   laal_tokens_t tokens = laal_tokens_create ();
   laal_position_t pos = LAAL_DEFAULT_POSITION;
+  memcpy (error_pos, &LAAL_INVALID_POSITION, sizeof (laal_position_t));
 
   char buffer[LAAL_IO_BUFFER_SIZE];
   while (!feof (stream))
     {
       fgets (buffer, LAAL_IO_BUFFER_SIZE, stream);
-      laal_try (laal_lexer_lex, tokens, buffer, &pos);
+
+      laal_error_t res = laal_lexer_lex (tokens, buffer, &pos);
+      if (res != LAAL_SUCCESS)
+        {
+          memcpy (error_pos, &pos, sizeof (laal_position_t));
+          return res;
+        }
     }
-  laal_try (laal_parse_tokens, output, tokens);
+
+  laal_error_t res = laal_parse_tokens (output, tokens);
+  if (res != LAAL_SUCCESS)
+    {
+      if (laal_tokens_get (tokens) != NULL)
+        memcpy (error_pos, &laal_tokens_get (tokens)->position,
+                sizeof (laal_position_t));
+      return res;
+    }
 
   laal_tokens_destroy (tokens);
   return LAAL_SUCCESS;
 }
 
 laal_error_t
-laal_parse_string (const char *source, laal_value_t *output)
+laal_parse_string (const char *source, laal_value_t *output,
+                   laal_position_t *error_pos)
 {
   laal_tokens_t tokens = laal_tokens_create ();
   laal_position_t pos = LAAL_DEFAULT_POSITION;
-  laal_try (laal_lexer_lex, tokens, source, &pos);
-  laal_try (laal_parse_tokens, output, tokens);
+  memcpy (error_pos, &LAAL_INVALID_POSITION, sizeof (laal_position_t));
+
+  laal_error_t lex_res = laal_lexer_lex (tokens, source, &pos);
+  if (lex_res != LAAL_SUCCESS)
+    {
+      memcpy (error_pos, &pos, sizeof (laal_position_t));
+      return lex_res;
+    }
+
+  laal_error_t parse_res = laal_parse_tokens (output, tokens);
+  if (parse_res != LAAL_SUCCESS)
+    {
+      if (laal_tokens_get (tokens) != NULL)
+        memcpy (error_pos, &laal_tokens_get (tokens)->position,
+                sizeof (laal_position_t));
+      return parse_res;
+    }
 
   laal_tokens_destroy (tokens);
   return LAAL_SUCCESS;

          
M src/laal_parser.c +1 -1
@@ 109,7 109,7 @@ parse_character (laal_tokens_t tokens, l
   // String to print output to
   char *out_text = malloc (res_len + 1);
   laal_check_alloc (out_text);
-  sprintf (out_text, "%d", data);
+  snprintf (out_text, res_len, "%d", data);
 
   *output = laal_value_from (out_text, LAAL_NUMBER, token->position);
   laal_check_alloc (*output);

          
M test/interface.c +23 -4
@@ 7,6 7,7 @@ 
 #include <laal.h>
 #include <laal_lexer.h>
 #include <laal_parser.h>
+#include <string.h>
 
 static void
 ensure_correct (const char *programme, const laal_value_t output)

          
@@ 44,10 45,13 @@ TEST ("Parse String")
 {
   const char *programme = "greeting := string \"Hello, world!\";";
   laal_value_t res = NULL;
-  laal_error_t err = laal_parse_string (programme, &res);
+  laal_position_t err_pos = LAAL_INVALID_POSITION;
+  laal_error_t err = laal_parse_string (programme, &res, &err_pos);
   if (err != LAAL_SUCCESS)
     {
       fprintf (stderr, "\nError code: %d", err);
+      if (memcmp (&err_pos, &LAAL_INVALID_POSITION, sizeof (laal_position_t)))
+        fprintf (stderr, "\nAt position: (%lu,%lu)", err_pos.row, err_pos.col);
       TEST_FAIL ("Parsing error while parsing string")
     }
 

          
@@ 66,12 70,15 @@ TEST ("Parse File")
   rewind (src);
 
   laal_value_t res = NULL;
-  laal_error_t err = laal_parse_file (src, &res);
+  laal_position_t err_pos = LAAL_DEFAULT_POSITION;
+  laal_error_t err = laal_parse_file (src, &res, &err_pos);
   fclose (src);
 
   if (err != LAAL_SUCCESS)
     {
       fprintf (stderr, "\nError code: %d", err);
+      if (memcmp (&err_pos, &LAAL_INVALID_POSITION, sizeof (laal_position_t)))
+        fprintf (stderr, "\nAt position: (%lu,%lu)", err_pos.row, err_pos.col);
       TEST_FAIL ("Parsing error while parsing from file")
     }
 

          
@@ 85,10 92,16 @@ TEST ("Write File")
       = "@<A simple greeting@>\n"
         "greeting := format \"Hello, ${who}!\" {who := \"world\"};";
   laal_value_t res_initial = NULL;
-  laal_error_t parse_initial_err = laal_parse_string (programme, &res_initial);
+  laal_position_t parse_initial_err_pos = LAAL_INVALID_POSITION;
+  laal_error_t parse_initial_err
+      = laal_parse_string (programme, &res_initial, &parse_initial_err_pos);
   if (parse_initial_err != LAAL_SUCCESS)
     {
       fprintf (stderr, "\nError code: %d", parse_initial_err);
+      if (memcmp (&parse_initial_err_pos, &LAAL_INVALID_POSITION,
+                  sizeof (laal_position_t)))
+        fprintf (stderr, "\nAt position: (%lu,%lu)", parse_initial_err_pos.row,
+                 parse_initial_err_pos.col);
       TEST_FAIL ("Parsing error while parsing initial data")
     }
 

          
@@ 104,12 117,18 @@ TEST ("Write File")
 
   rewind (out);
   laal_value_t res_final = NULL;
-  laal_error_t parse_final_err = laal_parse_file (out, &res_final);
+  laal_position_t parse_final_err_pos = LAAL_INVALID_POSITION;
+  laal_error_t parse_final_err
+      = laal_parse_file (out, &res_final, &parse_final_err_pos);
   fclose (out);
 
   if (parse_final_err != LAAL_SUCCESS)
     {
       fprintf (stderr, "\nError code: %d", parse_final_err);
+      if (memcmp (&parse_final_err_pos, &LAAL_INVALID_POSITION,
+                  sizeof (laal_position_t)))
+        fprintf (stderr, "\nAt position: (%lu,%lu)", parse_final_err_pos.row,
+                 parse_final_err_pos.col);
       TEST_FAIL ("Parsing error while parsing generated data")
     }