aidl_language.cpp revision 8aa4d9f32dcfb37011d41417814c01bd2d7a473b
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  item_type = USER_DATA_TYPE;
132}
133
134std::string AidlParcelable::GetPackage() const {
135  return Join(package_, '.');
136}
137
138AidlInterface::AidlInterface(const std::string& name, unsigned line,
139                             const std::string& comments, bool oneway,
140                             std::vector<std::unique_ptr<AidlMethod>>* methods,
141                             const std::vector<std::string>& package)
142    : name_(name),
143      comments_(comments),
144      line_(line),
145      oneway_(oneway),
146      methods_(std::move(*methods)),
147      package_(package) {
148  item_type = INTERFACE_TYPE_BINDER;
149  delete methods;
150}
151
152std::string AidlInterface::GetPackage() const {
153  return Join(package_, '.');
154}
155
156std::string AidlInterface::GetCanonicalName() const {
157  if (package_.empty()) {
158    return GetName();
159  }
160  return GetPackage() + "." + GetName();
161}
162
163AidlQualifiedName::AidlQualifiedName(std::string term,
164                                     std::string comments)
165    : terms_({term}),
166      comments_(comments) {
167  if (term.find('.') != string::npos) {
168    terms_ = Split(term, ".");
169    for (const auto& term: terms_) {
170      if (term.empty()) {
171        LOG(FATAL) << "Malformed qualified identifier: '" << term << "'";
172      }
173    }
174  }
175}
176
177void AidlQualifiedName::AddTerm(std::string term) {
178  terms_.push_back(term);
179}
180
181AidlImport::AidlImport(const std::string& from,
182                       const std::string& needed_class, unsigned line)
183    : from_(from),
184      needed_class_(needed_class),
185      line_(line) {}
186
187Parser::~Parser() {
188  if (raw_buffer_) {
189    yy_delete_buffer(buffer_, scanner_);
190    raw_buffer_.reset();
191  }
192  yylex_destroy(scanner_);
193}
194
195bool Parser::ParseFile(const string& filename) {
196  // Make sure we can read the file first, before trashing previous state.
197  unique_ptr<string> new_buffer = io_delegate_.GetFileContents(filename);
198  if (!new_buffer) {
199    LOG(ERROR) << "Error while opening file for parsing: '" << filename << "'";
200    return false;
201  }
202
203  // Throw away old parsing state if we have any.
204  if (raw_buffer_) {
205    yy_delete_buffer(buffer_, scanner_);
206    raw_buffer_.reset();
207  }
208
209  raw_buffer_ = std::move(new_buffer);
210  // We're going to scan this buffer in place, and yacc demands we put two
211  // nulls at the end.
212  raw_buffer_->append(2u, '\0');
213  filename_ = filename;
214  package_.reset();
215  error_ = 0;
216  document_ = nullptr;
217
218  buffer_ = yy_scan_buffer(&(*raw_buffer_)[0], raw_buffer_->length(), scanner_);
219
220  int ret = yy::parser(this).parse();
221
222  return ret == 0 && error_ == 0;
223}
224
225void Parser::ReportError(const string& err, unsigned line) {
226  cerr << filename_ << ":" << line << ": " << err << endl;
227  error_ = 1;
228}
229
230std::vector<std::string> Parser::Package() const {
231  if (!package_) {
232    return {};
233  }
234  return package_->GetTerms();
235}
236
237void Parser::AddImport(AidlQualifiedName* name, unsigned line) {
238  imports_.emplace_back(new AidlImport(this->FileName(),
239                                       name->GetDotName(), line));
240  delete name;
241}
242