1 #include "aidl_language.h"
2
3 #include <iostream>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <string>
8
9 #include <android-base/strings.h>
10
11 #include "aidl_language_y.h"
12 #include "logging.h"
13
14 #ifdef _WIN32
isatty(int fd)15 int isatty(int fd)
16 {
17 return (fd == 0);
18 }
19 #endif
20
21 using android::aidl::IoDelegate;
22 using android::base::Join;
23 using android::base::Split;
24 using std::cerr;
25 using std::endl;
26 using std::string;
27 using std::unique_ptr;
28
29 void yylex_init(void **);
30 void yylex_destroy(void *);
31 void yyset_in(FILE *f, void *);
32 int yyparse(Parser*);
33 YY_BUFFER_STATE yy_scan_buffer(char *, size_t, void *);
34 void yy_delete_buffer(YY_BUFFER_STATE, void *);
35
AidlToken(const std::string & text,const std::string & comments)36 AidlToken::AidlToken(const std::string& text, const std::string& comments)
37 : text_(text),
38 comments_(comments) {}
39
AidlType(const std::string & name,unsigned line,const std::string & comments,bool is_array)40 AidlType::AidlType(const std::string& name, unsigned line,
41 const std::string& comments, bool is_array)
42 : name_(name),
43 line_(line),
44 is_array_(is_array),
45 comments_(comments) {}
46
ToString() const47 string AidlType::ToString() const {
48 return name_ + (is_array_ ? "[]" : "");
49 }
50
AidlArgument(AidlArgument::Direction direction,AidlType * type,std::string name,unsigned line)51 AidlArgument::AidlArgument(AidlArgument::Direction direction, AidlType* type,
52 std::string name, unsigned line)
53 : type_(type),
54 direction_(direction),
55 direction_specified_(true),
56 name_(name),
57 line_(line) {}
58
AidlArgument(AidlType * type,std::string name,unsigned line)59 AidlArgument::AidlArgument(AidlType* type, std::string name, unsigned line)
60 : type_(type),
61 direction_(AidlArgument::IN_DIR),
62 direction_specified_(false),
63 name_(name),
64 line_(line) {}
65
ToString() const66 string AidlArgument::ToString() const {
67 string ret;
68
69 if (direction_specified_) {
70 switch(direction_) {
71 case AidlArgument::IN_DIR:
72 ret += "in ";
73 break;
74 case AidlArgument::OUT_DIR:
75 ret += "out ";
76 break;
77 case AidlArgument::INOUT_DIR:
78 ret += "inout ";
79 break;
80 }
81 }
82
83 ret += type_->ToString();
84 ret += " ";
85 ret += name_;
86
87 return ret;
88 }
89
AidlConstant(std::string name,int32_t value)90 AidlConstant::AidlConstant(std::string name, int32_t value)
91 : name_(name),
92 value_(value) {}
93
AidlMethod(bool oneway,AidlType * type,std::string name,std::vector<std::unique_ptr<AidlArgument>> * args,unsigned line,const std::string & comments,int id)94 AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name,
95 std::vector<std::unique_ptr<AidlArgument>>* args,
96 unsigned line, const std::string& comments, int id)
97 : oneway_(oneway),
98 comments_(comments),
99 type_(type),
100 name_(name),
101 line_(line),
102 arguments_(std::move(*args)),
103 id_(id) {
104 has_id_ = true;
105 delete args;
106 for (const unique_ptr<AidlArgument>& a : arguments_) {
107 if (a->IsIn()) { in_arguments_.push_back(a.get()); }
108 if (a->IsOut()) { out_arguments_.push_back(a.get()); }
109 }
110 }
111
AidlMethod(bool oneway,AidlType * type,std::string name,std::vector<std::unique_ptr<AidlArgument>> * args,unsigned line,const std::string & comments)112 AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name,
113 std::vector<std::unique_ptr<AidlArgument>>* args,
114 unsigned line, const std::string& comments)
115 : AidlMethod(oneway, type, name, args, line, comments, 0) {
116 has_id_ = false;
117 }
118
Parser(const IoDelegate & io_delegate)119 Parser::Parser(const IoDelegate& io_delegate)
120 : io_delegate_(io_delegate) {
121 yylex_init(&scanner_);
122 }
123
AidlParcelable(AidlQualifiedName * name,unsigned line,const std::vector<std::string> & package,const std::string & cpp_header)124 AidlParcelable::AidlParcelable(AidlQualifiedName* name, unsigned line,
125 const std::vector<std::string>& package,
126 const std::string& cpp_header)
127 : name_(name),
128 line_(line),
129 package_(package),
130 cpp_header_(cpp_header) {
131 // Strip off quotation marks if we actually have a cpp header.
132 if (cpp_header_.length() >= 2) {
133 cpp_header_ = cpp_header_.substr(1, cpp_header_.length() - 2);
134 }
135 }
136
GetPackage() const137 std::string AidlParcelable::GetPackage() const {
138 return Join(package_, '.');
139 }
140
GetCanonicalName() const141 std::string AidlParcelable::GetCanonicalName() const {
142 if (package_.empty()) {
143 return GetName();
144 }
145 return GetPackage() + "." + GetName();
146 }
147
AidlInterface(const std::string & name,unsigned line,const std::string & comments,bool oneway,std::vector<std::unique_ptr<AidlMember>> * members,const std::vector<std::string> & package)148 AidlInterface::AidlInterface(const std::string& name, unsigned line,
149 const std::string& comments, bool oneway,
150 std::vector<std::unique_ptr<AidlMember>>* members,
151 const std::vector<std::string>& package)
152 : name_(name),
153 comments_(comments),
154 line_(line),
155 oneway_(oneway),
156 package_(package) {
157 for (auto& member : *members) {
158 AidlMember* local = member.release();
159 AidlMethod* method = local->AsMethod();
160 AidlConstant* constant = local->AsConstant();
161
162 if (method) {
163 methods_.emplace_back(method);
164 } else if (constant) {
165 constants_.emplace_back(constant);
166 } else {
167 LOG(FATAL) << "Member is neither method nor constant!";
168 }
169 }
170
171 delete members;
172 }
173
GetPackage() const174 std::string AidlInterface::GetPackage() const {
175 return Join(package_, '.');
176 }
177
GetCanonicalName() const178 std::string AidlInterface::GetCanonicalName() const {
179 if (package_.empty()) {
180 return GetName();
181 }
182 return GetPackage() + "." + GetName();
183 }
184
AidlDocument(AidlInterface * interface)185 AidlDocument::AidlDocument(AidlInterface* interface)
186 : interface_(interface) {}
187
AidlQualifiedName(std::string term,std::string comments)188 AidlQualifiedName::AidlQualifiedName(std::string term,
189 std::string comments)
190 : terms_({term}),
191 comments_(comments) {
192 if (term.find('.') != string::npos) {
193 terms_ = Split(term, ".");
194 for (const auto& term: terms_) {
195 if (term.empty()) {
196 LOG(FATAL) << "Malformed qualified identifier: '" << term << "'";
197 }
198 }
199 }
200 }
201
AddTerm(std::string term)202 void AidlQualifiedName::AddTerm(std::string term) {
203 terms_.push_back(term);
204 }
205
AidlImport(const std::string & from,const std::string & needed_class,unsigned line)206 AidlImport::AidlImport(const std::string& from,
207 const std::string& needed_class, unsigned line)
208 : from_(from),
209 needed_class_(needed_class),
210 line_(line) {}
211
~Parser()212 Parser::~Parser() {
213 if (raw_buffer_) {
214 yy_delete_buffer(buffer_, scanner_);
215 raw_buffer_.reset();
216 }
217 yylex_destroy(scanner_);
218 }
219
ParseFile(const string & filename)220 bool Parser::ParseFile(const string& filename) {
221 // Make sure we can read the file first, before trashing previous state.
222 unique_ptr<string> new_buffer = io_delegate_.GetFileContents(filename);
223 if (!new_buffer) {
224 LOG(ERROR) << "Error while opening file for parsing: '" << filename << "'";
225 return false;
226 }
227
228 // Throw away old parsing state if we have any.
229 if (raw_buffer_) {
230 yy_delete_buffer(buffer_, scanner_);
231 raw_buffer_.reset();
232 }
233
234 raw_buffer_ = std::move(new_buffer);
235 // We're going to scan this buffer in place, and yacc demands we put two
236 // nulls at the end.
237 raw_buffer_->append(2u, '\0');
238 filename_ = filename;
239 package_.reset();
240 error_ = 0;
241 document_.reset();
242
243 buffer_ = yy_scan_buffer(&(*raw_buffer_)[0], raw_buffer_->length(), scanner_);
244
245 if (yy::parser(this).parse() != 0 || error_ != 0) {
246 return false;}
247
248 if (document_.get() != nullptr)
249 return true;
250
251 LOG(ERROR) << "Parser succeeded but yielded no document!";
252 return false;
253 }
254
ReportError(const string & err,unsigned line)255 void Parser::ReportError(const string& err, unsigned line) {
256 cerr << filename_ << ":" << line << ": " << err << endl;
257 error_ = 1;
258 }
259
Package() const260 std::vector<std::string> Parser::Package() const {
261 if (!package_) {
262 return {};
263 }
264 return package_->GetTerms();
265 }
266
AddImport(AidlQualifiedName * name,unsigned line)267 void Parser::AddImport(AidlQualifiedName* name, unsigned line) {
268 imports_.emplace_back(new AidlImport(this->FileName(),
269 name->GetDotName(), line));
270 delete name;
271 }
272