1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <initializer_list>
20 #include <iostream>
21 #include <sstream>
22 #include <vector>
23 
24 #include "parse_location.h"
25 
26 class Loggable {
27 public:
28   virtual ~Loggable() = default;
29   virtual std::string GetDebugName() const = 0;
30   virtual ParseLocation GetLocation() const = 0;
31 };
32 
33 class LogMessage {
34 public:
LogMessage(ParseLocation loc,std::initializer_list<const Loggable * > tokens)35   LogMessage(ParseLocation loc, std::initializer_list<const Loggable*> tokens)
36       : debug_(false), loc_(loc), tokens_(tokens) {
37     Init();
38   }
39 
LogMessage(bool debug,std::initializer_list<const Loggable * > tokens)40   LogMessage(bool debug, std::initializer_list<const Loggable*> tokens)
41       : debug_(debug), tokens_(tokens) {
42     Init();
43   }
44 
Init()45   void Init() {
46     if (loc_.GetLine() != -1) {
47       stream_ << "\033[1mLine " << loc_.GetLine() << ": ";
48     }
49 
50     if (!debug_) {
51       stream_ << "\033[1;31m";
52       stream_ << "ERROR: ";
53       stream_ << "\033[0m";
54     } else {
55       stream_ << "\033[1;m";
56       stream_ << "DEBUG: ";
57       stream_ << "\033[0m";
58     }
59   }
60 
~LogMessage()61   ~LogMessage() {
62     if (debug_ && suppress_debug_) {
63       return;
64     }
65 
66     std::cerr << stream_.str() << "\n";
67     for (const auto& token : tokens_) {
68       // Bold line number
69       std::cerr << "\033[1m";
70       std::cerr << "  Line " << token->GetLocation().GetLine() << ": ";
71       std::cerr << "\033[0m";
72       std::cerr << token->GetDebugName() << "\n";
73     }
74 
75     if (!debug_) {
76       abort();
77     }
78   }
79 
stream()80   std::ostream& stream() { return stream_; }
81 
82 private:
83   std::ostringstream stream_;
84   bool debug_;
85   bool suppress_debug_{true};
86   ParseLocation loc_;
87   std::vector<const Loggable*> tokens_;
88 };
89 
90 // Error Log stream. Aborts the program after the message is printed.
91 // The arguments to the macro is a list of Loggable objects that are printed when the error is
92 // printed.
93 #define ERROR(...) LogMessage(false, {__VA_ARGS__}).stream()
94 
95 // ParseLocation error log, the first argument is a location.
96 #define ERRORLOC(_1, ...) LogMessage(_1, {__VA_ARGS__}).stream()
97 
98 #define DEBUG(...) LogMessage(true, {__VA_ARGS__}).stream()
99