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
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
90AidlConstant::AidlConstant(std::string name, int32_t value)
91    : name_(name),
92      value_(value) {}
93
94AidlMethod::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
112AidlMethod::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
119Parser::Parser(const IoDelegate& io_delegate)
120    : io_delegate_(io_delegate) {
121  yylex_init(&scanner_);
122}
123
124AidlParcelable::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
137std::string AidlParcelable::GetPackage() const {
138  return Join(package_, '.');
139}
140
141std::string AidlParcelable::GetCanonicalName() const {
142  if (package_.empty()) {
143    return GetName();
144  }
145  return GetPackage() + "." + GetName();
146}
147
148AidlInterface::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
174std::string AidlInterface::GetPackage() const {
175  return Join(package_, '.');
176}
177
178std::string AidlInterface::GetCanonicalName() const {
179  if (package_.empty()) {
180    return GetName();
181  }
182  return GetPackage() + "." + GetName();
183}
184
185AidlDocument::AidlDocument(AidlInterface* interface)
186    : interface_(interface) {}
187
188AidlQualifiedName::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
202void AidlQualifiedName::AddTerm(std::string term) {
203  terms_.push_back(term);
204}
205
206AidlImport::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
212Parser::~Parser() {
213  if (raw_buffer_) {
214    yy_delete_buffer(buffer_, scanner_);
215    raw_buffer_.reset();
216  }
217  yylex_destroy(scanner_);
218}
219
220bool 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
255void Parser::ReportError(const string& err, unsigned line) {
256  cerr << filename_ << ":" << line << ": " << err << endl;
257  error_ = 1;
258}
259
260std::vector<std::string> Parser::Package() const {
261  if (!package_) {
262    return {};
263  }
264  return package_->GetTerms();
265}
266
267void Parser::AddImport(AidlQualifiedName* name, unsigned line) {
268  imports_.emplace_back(new AidlImport(this->FileName(),
269                                       name->GetDotName(), line));
270  delete name;
271}
272