aidl_language.cpp revision b696437d842d59c0cc26411fa3d71cb91897c572
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 <base/strings.h>
10
11#include "aidl_language_y.hpp"
12#include "logging.h"
13
14#ifdef _WIN32
15int isatty(int  fd)
16{
17    return (fd == 0);
18}
19#endif
20
21using android::aidl::IoDelegate;
22using android::base::Join;
23using android::base::Split;
24using std::cerr;
25using std::endl;
26using std::string;
27using std::unique_ptr;
28
29void yylex_init(void **);
30void yylex_destroy(void *);
31void yyset_in(FILE *f, void *);
32int yyparse(Parser*);
33YY_BUFFER_STATE yy_scan_buffer(char *, size_t, void *);
34void yy_delete_buffer(YY_BUFFER_STATE, void *);
35
36AidlToken::AidlToken(const std::string& text, const std::string& comments)
37    : text_(text),
38      comments_(comments) {}
39
40AidlType::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
47string AidlType::ToString() const {
48  return name_ + (is_array_ ? "[]" : "");
49}
50
51AidlArgument::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
59AidlArgument::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
66string 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
90AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name,
91                       std::vector<std::unique_ptr<AidlArgument>>* args,
92                       unsigned line, const std::string& comments, int id)
93    : oneway_(oneway),
94      comments_(comments),
95      type_(type),
96      name_(name),
97      line_(line),
98      arguments_(std::move(*args)),
99      id_(id) {
100  has_id_ = true;
101  delete args;
102  for (const unique_ptr<AidlArgument>& a : arguments_) {
103    if (a->IsIn()) { in_arguments_.push_back(a.get()); }
104    if (a->IsOut()) { out_arguments_.push_back(a.get()); }
105  }
106}
107
108AidlMethod::AidlMethod(bool oneway, AidlType* type, std::string name,
109                       std::vector<std::unique_ptr<AidlArgument>>* args,
110                       unsigned line, const std::string& comments)
111    : AidlMethod(oneway, type, name, args, line, comments, 0) {
112  has_id_ = false;
113}
114
115Parser::Parser(const IoDelegate& io_delegate)
116    : io_delegate_(io_delegate) {
117  yylex_init(&scanner_);
118}
119
120AidlParcelable::AidlParcelable(AidlQualifiedName* name, unsigned line,
121                               const std::vector<std::string>& package,
122                               const std::string& cpp_header)
123    : name_(name),
124      line_(line),
125      package_(package),
126      cpp_header_(cpp_header) {
127  // Strip off quotation marks if we actually have a cpp header.
128  if (cpp_header_.length() >= 2) {
129    cpp_header_ = cpp_header_.substr(1, cpp_header_.length() - 2);
130  }
131}
132
133std::string AidlParcelable::GetPackage() const {
134  return Join(package_, '.');
135}
136
137std::string AidlParcelable::GetCanonicalName() const {
138  if (package_.empty()) {
139    return GetName();
140  }
141  return GetPackage() + "." + GetName();
142}
143
144AidlInterface::AidlInterface(const std::string& name, unsigned line,
145                             const std::string& comments, bool oneway,
146                             std::vector<std::unique_ptr<AidlMethod>>* methods,
147                             const std::vector<std::string>& package)
148    : name_(name),
149      comments_(comments),
150      line_(line),
151      oneway_(oneway),
152      methods_(std::move(*methods)),
153      package_(package) {
154  delete methods;
155}
156
157std::string AidlInterface::GetPackage() const {
158  return Join(package_, '.');
159}
160
161std::string AidlInterface::GetCanonicalName() const {
162  if (package_.empty()) {
163    return GetName();
164  }
165  return GetPackage() + "." + GetName();
166}
167
168AidlDocument::AidlDocument(AidlInterface* interface)
169    : interface_(interface) {}
170
171AidlQualifiedName::AidlQualifiedName(std::string term,
172                                     std::string comments)
173    : terms_({term}),
174      comments_(comments) {
175  if (term.find('.') != string::npos) {
176    terms_ = Split(term, ".");
177    for (const auto& term: terms_) {
178      if (term.empty()) {
179        LOG(FATAL) << "Malformed qualified identifier: '" << term << "'";
180      }
181    }
182  }
183}
184
185void AidlQualifiedName::AddTerm(std::string term) {
186  terms_.push_back(term);
187}
188
189AidlImport::AidlImport(const std::string& from,
190                       const std::string& needed_class, unsigned line)
191    : from_(from),
192      needed_class_(needed_class),
193      line_(line) {}
194
195Parser::~Parser() {
196  if (raw_buffer_) {
197    yy_delete_buffer(buffer_, scanner_);
198    raw_buffer_.reset();
199  }
200  yylex_destroy(scanner_);
201}
202
203bool Parser::ParseFile(const string& filename) {
204  // Make sure we can read the file first, before trashing previous state.
205  unique_ptr<string> new_buffer = io_delegate_.GetFileContents(filename);
206  if (!new_buffer) {
207    LOG(ERROR) << "Error while opening file for parsing: '" << filename << "'";
208    return false;
209  }
210
211  // Throw away old parsing state if we have any.
212  if (raw_buffer_) {
213    yy_delete_buffer(buffer_, scanner_);
214    raw_buffer_.reset();
215  }
216
217  raw_buffer_ = std::move(new_buffer);
218  // We're going to scan this buffer in place, and yacc demands we put two
219  // nulls at the end.
220  raw_buffer_->append(2u, '\0');
221  filename_ = filename;
222  package_.reset();
223  error_ = 0;
224  document_.reset();
225
226  buffer_ = yy_scan_buffer(&(*raw_buffer_)[0], raw_buffer_->length(), scanner_);
227
228  if (yy::parser(this).parse() != 0 || error_ != 0) {
229    return false;}
230
231  if (document_.get() != nullptr)
232    return true;
233
234  LOG(ERROR) << "Parser succeeded but yielded no document!";
235  return false;
236}
237
238void Parser::ReportError(const string& err, unsigned line) {
239  cerr << filename_ << ":" << line << ": " << err << endl;
240  error_ = 1;
241}
242
243std::vector<std::string> Parser::Package() const {
244  if (!package_) {
245    return {};
246  }
247  return package_->GetTerms();
248}
249
250void Parser::AddImport(AidlQualifiedName* name, unsigned line) {
251  imports_.emplace_back(new AidlImport(this->FileName(),
252                                       name->GetDotName(), line));
253  delete name;
254}
255