Просмотр исходного кода

Merge pull request #159 from tsoding/153

(#153) Improve error messages in log parsing
Alexey Kutepov 4 лет назад
Родитель
Сommit
02542318d2
2 измененных файлов с 100 добавлено и 31 удалено
  1. 25 2
      src/aids.hpp
  2. 75 29
      src/vodus_message.cpp

+ 25 - 2
src/aids.hpp

@@ -21,7 +21,7 @@
 //
 // ============================================================
 //
-// aids — 0.28.0 — std replacement for C++. Designed to aid developers
+// aids — 0.30.0 — std replacement for C++. Designed to aid developers
 // to a better programming experience.
 //
 // https://github.com/rexim/aids
@@ -30,6 +30,8 @@
 //
 // ChangeLog (https://semver.org/ is implied)
 //
+//   0.30.0 String_View String_View::chop_while(Predicate_Char predicate)
+//   0.29.0 void destroy(Dynamic_Array<T> dynamic_array)
 //   0.28.0 struct Hash_Map
 //   0.27.0 NEVER HAPPENED
 //   0.26.0 panic() is marked with [[noreturn]] attribute
@@ -273,6 +275,20 @@ namespace aids
             count += n;
         }
 
+        using Predicate_Char = bool (*)(char);
+
+        String_View chop_while(Predicate_Char predicate)
+        {
+            size_t size = 0;
+            while (size < count && predicate(data[size])) {
+                size += 1;
+            }
+
+            auto result = subview(0, size);
+            chop(size);
+            return result;
+        }
+
         String_View chop_by_delim(char delim)
         {
             assert(data);
@@ -504,6 +520,14 @@ namespace aids
         }
     };
 
+    template <typename T>
+    void destroy(Dynamic_Array<T> dynamic_array)
+    {
+        if (dynamic_array.data) {
+            free(dynamic_array.data);
+        }
+    }
+
     ////////////////////////////////////////////////////////////
     // STRETCHY BUFFER
     ////////////////////////////////////////////////////////////
@@ -1058,7 +1082,6 @@ namespace aids
             Value value;
         };
 
-        // TODO: Maybe<Bucket> *buckets
         Maybe<Bucket> *buckets;
         size_t capacity;
         size_t size;

+ 75 - 29
src/vodus_message.cpp

@@ -169,47 +169,92 @@ struct Message_Buffer
     }
 };
 
-Timestamp chop_timestamp(String_View *input)
+Timestamp chop_timestamp(const char *input_filepath,
+                         size_t line_number,
+                         String_View *input,
+                         String_View origin_input)
 {
-    input->chop_by_delim('[');
-    auto raw_timestamp = input->chop_by_delim(']').trim();
-
-    // TODO(#153): message parsing should give more precise position of the syntax errors
-    auto hours = unwrap_or_panic(
-        raw_timestamp.chop_by_delim(':').trim().as_integer<uint64_t>(),
-        "Incorrect timestamp. Hours must be a number.");
-
-    auto minutes = unwrap_or_panic(
-        raw_timestamp.chop_by_delim(':').trim().as_integer<uint64_t>(),
-        "Incorrect timestamp. Minutes must be a number.");
+    auto syntax_panic = [&] (auto ...args) {
+        panic(input_filepath, ":", line_number, ":", input->data - origin_input.data + 1, ": ",
+              args...);
+    };
+
+    auto unwrap_or_syntax_panic = [&] (auto maybe, auto ...args) {
+        if (!maybe.has_value) {
+            syntax_panic(args...);
+        }
 
-    auto seconds = unwrap_or_panic(
-        raw_timestamp.chop_by_delim('.').trim().as_integer<uint64_t>(),
-        "Incorrect timestamp. Seconds must be a number");
+        return maybe.unwrap;
+    };
 
-    auto mseconds = 0;
+    auto is_digit = [](char x) -> bool {
+        return isdigit(x);
+    };
 
-    if (raw_timestamp.count > 0) {
+    auto expect_char = [&](char x) {
+        if (input->count == 0 || *input->data != x) {
+            syntax_panic("Expected `", x, "`");
+        }
+        input->chop(1);
+    };
+
+    auto expect_number = [&]() -> uint64_t {
+        return unwrap_or_syntax_panic(
+            input->chop_while(is_digit).as_integer<uint64_t>(),
+            "Expected number");
+    };
+
+    *input = input->trim_begin();
+
+    expect_char('[');
+    auto hours = expect_number();
+    expect_char(':');
+    auto minutes = expect_number();
+    expect_char(':');
+    auto seconds = expect_number();
+
+    Timestamp mseconds = 0;
+    if (input->count > 0 && *input->data == '.') {
+        input->chop(1);
+        auto mseconds_str = input->chop_while(is_digit);
         for (size_t i = 0; i < 3; ++i) {
-            if (i < raw_timestamp.count) {
-                if (isdigit(raw_timestamp.data[i])) {
-                    mseconds = mseconds * 10 + raw_timestamp.data[i] - '0';
-                } else {
-                    panic("Incorrect timestamp. Milliseconds must be a number");
-                }
+            if (i < mseconds_str.count) {
+                mseconds = mseconds * 10 + mseconds_str.data[i] - '0';
             } else {
                 mseconds *= 10;
             }
         }
     }
 
+    expect_char(']');
+
     return (hours * 60 * 60 + minutes * 60 + seconds) * 1000 + mseconds;
 }
 
-String_View chop_nickname(String_View *input)
+String_View chop_nickname(const char *input_filepath,
+                          size_t line_number,
+                          String_View *input,
+                          String_View origin_input)
 {
-    input->chop_by_delim('<');
-    auto nickname = input->chop_by_delim('>');
+    auto syntax_panic = [&] (auto ...args) {
+        panic(input_filepath, ":", line_number, ":", input->data - origin_input.data + 1, ": ",
+              args...);
+    };
+
+    auto expect_char = [&](char x) {
+        if (input->count == 0 || *input->data != x) {
+            syntax_panic("Expected `", x, "`");
+        }
+        input->chop(1);
+    };
+
+    *input = input->trim_begin();
+    expect_char('<');
+    auto nickname = input->chop_while([](char x) -> bool {
+        return x != '>';
+    });
+    expect_char('>');
+
     return nickname;
 }
 
@@ -235,10 +280,11 @@ size_t parse_messages_from_string_view(String_View input,
          input.count > 0 && messages_size < expected_messages_size;
          ++line_number)
     {
-        String_View message = input.chop_by_delim('\n');
+        String_View origin_message = input.chop_by_delim('\n');
+        String_View message = origin_message;
 
-        (*messages)[messages_size].timestamp = chop_timestamp(&message);
-        (*messages)[messages_size].nickname  = chop_nickname(&message);
+        (*messages)[messages_size].timestamp = chop_timestamp(input_filepath, line_number, &message, origin_message);
+        (*messages)[messages_size].nickname  = chop_nickname(input_filepath, line_number, &message, origin_message);
         (*messages)[messages_size].message   = chop_message(&message);
         messages_size++;
     }