1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef ZIRCON_SYSTEM_UTEST_BANJO_COMPILER_TEST_LIBRARY_H_
6 #define ZIRCON_SYSTEM_UTEST_BANJO_COMPILER_TEST_LIBRARY_H_
7 
8 #include <banjo/flat_ast.h>
9 #include <banjo/json_generator.h>
10 #include <banjo/lexer.h>
11 #include <banjo/parser.h>
12 #include <banjo/source_file.h>
13 
MakeSourceFile(const std::string & filename,const std::string & raw_source_code)14 static banjo::SourceFile MakeSourceFile(const std::string& filename, const std::string& raw_source_code) {
15     std::string source_code(raw_source_code);
16     // NUL terminate the string.
17     source_code.resize(source_code.size() + 1);
18     return banjo::SourceFile(filename, source_code);
19 }
20 
21 class TestLibrary {
22 public:
TestLibrary(const std::string & raw_source_code)23     TestLibrary(const std::string& raw_source_code)
24         : TestLibrary("example.banjo", raw_source_code) {}
25 
TestLibrary(const std::string & filename,const std::string & raw_source_code)26     TestLibrary(const std::string& filename, const std::string& raw_source_code)
27         : source_file_(MakeSourceFile(filename, raw_source_code)),
28           lexer_(source_file_, &identifier_table_),
29           parser_(&lexer_, &error_reporter_),
30           library_(std::make_unique<banjo::flat::Library>(&all_libraries_, &error_reporter_)) {
31     }
32 
AddDependentLibrary(TestLibrary & dependent_library)33     bool AddDependentLibrary(TestLibrary& dependent_library) {
34         // For testing, we have conveniences to construct compiled test
35         // libraries, which we usurp here to move it into the current library
36         // under test. This would be made clearer with a helper object which
37         // owned all libraries under test.
38         if (!all_libraries_.Insert(std::unique_ptr<banjo::flat::Library>(dependent_library.library_.get()))) {
39             return false;
40         }
41         dependent_library.library_.release();
42         return true;
43     }
44 
Parse(std::unique_ptr<banjo::raw::File> & ast_ptr)45     bool Parse(std::unique_ptr<banjo::raw::File>& ast_ptr) {
46         ast_ptr.reset(parser_.Parse().release());
47         return parser_.Ok();
48     }
49 
Compile()50     bool Compile() {
51         auto ast = parser_.Parse();
52         return parser_.Ok() &&
53                library_->ConsumeFile(std::move(ast)) &&
54                library_->Compile();
55     }
56 
GenerateJSON()57     std::string GenerateJSON() {
58         auto json_generator = banjo::JSONGenerator(library_.get());
59         auto out = json_generator.Produce();
60         return out.str();
61     }
62 
AddSourceFile(const std::string & filename,const std::string & raw_source_code)63     bool AddSourceFile(const std::string& filename, const std::string& raw_source_code) {
64         auto source_file = MakeSourceFile(filename, raw_source_code);
65         banjo::IdentifierTable identifier_table;
66         banjo::Lexer lexer(source_file, &identifier_table);
67         banjo::Parser parser(&lexer, &error_reporter_);
68         auto ast = parser.Parse();
69         return parser.Ok() &&
70                library_->ConsumeFile(std::move(ast)) &&
71                library_->Compile();
72     }
73 
LookupStruct(const std::string & name)74     const banjo::flat::Struct* LookupStruct(const std::string& name) {
75         for (const auto& struct_decl : library_->struct_declarations_) {
76             if (struct_decl->GetName() == name) {
77                 return struct_decl.get();
78             }
79         }
80         return nullptr;
81     }
82 
LookupUnion(const std::string & name)83     const banjo::flat::Union* LookupUnion(const std::string& name) {
84         for (const auto& union_decl : library_->union_declarations_) {
85             if (union_decl->GetName() == name) {
86                 return union_decl.get();
87             }
88         }
89         return nullptr;
90     }
91 
LookupInterface(const std::string & name)92     const banjo::flat::Interface* LookupInterface(const std::string& name) {
93         for (const auto& interface_decl : library_->interface_declarations_) {
94             if (interface_decl->GetName() == name) {
95                 return interface_decl.get();
96             }
97         }
98         return nullptr;
99     }
100 
source_file()101     banjo::SourceFile source_file() {
102         return source_file_;
103     }
104 
errors()105     const std::vector<std::string>& errors() const {
106         return error_reporter_.errors();
107     }
108 
109 private:
110     banjo::SourceFile source_file_;
111     banjo::IdentifierTable identifier_table_;
112     banjo::ErrorReporter error_reporter_;
113     banjo::Lexer lexer_;
114     banjo::Parser parser_;
115     banjo::flat::Libraries all_libraries_;
116     std::unique_ptr<banjo::flat::Library> library_;
117 };
118 
119 #endif // ZIRCON_SYSTEM_UTEST_BANJO_COMPILER_TEST_LIBRARY_H_
120