• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2015 PLUMgrid, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <set>
18 #include <algorithm>
19 #include "bcc_exception.h"
20 #include "type_check.h"
21 #include "lexer.h"
22 
23 namespace ebpf {
24 namespace cc {
25 
26 using std::for_each;
27 using std::set;
28 
visit_block_stmt_node(BlockStmtNode * n)29 StatusTuple TypeCheck::visit_block_stmt_node(BlockStmtNode *n) {
30   // enter scope
31   if (n->scope_)
32     scopes_->push_var(n->scope_);
33   if (!n->stmts_.empty()) {
34     for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it)
35       TRY2((*it)->accept(this));
36   }
37 
38   if (n->scope_)
39     scopes_->pop_var();
40   return StatusTuple(0);
41 }
42 
visit_if_stmt_node(IfStmtNode * n)43 StatusTuple TypeCheck::visit_if_stmt_node(IfStmtNode *n) {
44   TRY2(n->cond_->accept(this));
45   //if (n->cond_->typeof_ != ExprNode::INTEGER)
46   //  return mkstatus_(n, "If condition must be a numeric type");
47   TRY2(n->true_block_->accept(this));
48   if (n->false_block_) {
49     TRY2(n->false_block_->accept(this));
50   }
51   return StatusTuple(0);
52 }
53 
visit_onvalid_stmt_node(OnValidStmtNode * n)54 StatusTuple TypeCheck::visit_onvalid_stmt_node(OnValidStmtNode *n) {
55   TRY2(n->cond_->accept(this));
56   auto sdecl = static_cast<StructVariableDeclStmtNode*>(n->cond_->decl_);
57   if (sdecl->storage_type_ != StructVariableDeclStmtNode::STRUCT_REFERENCE)
58     return mkstatus_(n, "on_valid condition must be a reference type");
59   TRY2(n->block_->accept(this));
60   if (n->else_block_) {
61     TRY2(n->else_block_->accept(this));
62   }
63   return StatusTuple(0);
64 }
65 
visit_switch_stmt_node(SwitchStmtNode * n)66 StatusTuple TypeCheck::visit_switch_stmt_node(SwitchStmtNode *n) {
67   TRY2(n->cond_->accept(this));
68   if (n->cond_->typeof_ != ExprNode::INTEGER)
69     return mkstatus_(n, "Switch condition must be a numeric type");
70   TRY2(n->block_->accept(this));
71   for (auto it = n->block_->stmts_.begin(); it != n->block_->stmts_.end(); ++it) {
72     /// @todo check for duplicates
73   }
74   return StatusTuple(0);
75 }
76 
visit_case_stmt_node(CaseStmtNode * n)77 StatusTuple TypeCheck::visit_case_stmt_node(CaseStmtNode *n) {
78   if (n->value_) {
79     TRY2(n->value_->accept(this));
80     if (n->value_->typeof_ != ExprNode::INTEGER)
81       return mkstatus_(n, "Switch condition must be a numeric type");
82   }
83   TRY2(n->block_->accept(this));
84   return StatusTuple(0);
85 }
86 
visit_ident_expr_node(IdentExprNode * n)87 StatusTuple TypeCheck::visit_ident_expr_node(IdentExprNode *n) {
88   n->decl_ = scopes_->current_var()->lookup(n->name_, SCOPE_GLOBAL);
89   if (!n->decl_)
90     return mkstatus_(n, "Variable %s lookup failed", n->c_str());
91 
92   n->typeof_ = ExprNode::UNKNOWN;
93   if (n->sub_name_.empty()) {
94     if (n->decl_->storage_type_ == VariableDeclStmtNode::INTEGER) {
95       n->typeof_ = ExprNode::INTEGER;
96       n->bit_width_ = n->decl_->bit_width_;
97       n->flags_[ExprNode::WRITE] = true;
98     } else if (n->decl_->is_struct()) {
99       n->typeof_ = ExprNode::STRUCT;
100       auto sdecl = static_cast<StructVariableDeclStmtNode*>(n->decl_);
101       if (sdecl->struct_id_->scope_name_ == "proto") {
102         n->struct_type_ = proto_scopes_->top_struct()->lookup(sdecl->struct_id_->name_, true);
103         n->flags_[ExprNode::PROTO] = true;
104       } else {
105         n->struct_type_ = scopes_->top_struct()->lookup(sdecl->struct_id_->name_, true);
106       }
107       if (!n->struct_type_)
108         return mkstatus_(n, "Type %s has not been declared", sdecl->struct_id_->full_name().c_str());
109       n->bit_width_ = n->struct_type_->bit_width_;
110     }
111   } else {
112     if (n->decl_->storage_type_ == VariableDeclStmtNode::INTEGER)
113       return mkstatus_(n, "Subfield access not valid for numeric types");
114     auto sdecl = static_cast<StructVariableDeclStmtNode*>(n->decl_);
115     if (sdecl->struct_id_->scope_name_ == "proto") {
116       n->struct_type_ = proto_scopes_->top_struct()->lookup(sdecl->struct_id_->name_, true);
117       n->flags_[ExprNode::PROTO] = true;
118     } else {
119       n->struct_type_ = scopes_->top_struct()->lookup(sdecl->struct_id_->name_, true);
120     }
121     if (!n->struct_type_)
122       return mkstatus_(n, "Type %s has not been declared", sdecl->struct_id_->full_name().c_str());
123     n->sub_decl_ = n->struct_type_->field(n->sub_name_);
124 
125     if (!n->sub_decl_)
126       return mkstatus_(n, "Access to invalid subfield %s.%s", n->c_str(), n->sub_name_.c_str());
127     if (n->sub_decl_->storage_type_ != VariableDeclStmtNode::INTEGER)
128       return mkstatus_(n, "Accessing non-numeric subfield %s.%s", n->c_str(), n->sub_name_.c_str());
129 
130     n->typeof_ = ExprNode::INTEGER;
131     n->bit_width_ = n->sub_decl_->bit_width_;
132     n->flags_[ExprNode::WRITE] = true;
133   }
134   return StatusTuple(0);
135 }
136 
visit_assign_expr_node(AssignExprNode * n)137 StatusTuple TypeCheck::visit_assign_expr_node(AssignExprNode *n) {
138   /// @todo check lhs is assignable
139   TRY2(n->lhs_->accept(this));
140   if (n->lhs_->typeof_ == ExprNode::STRUCT) {
141     TRY2(n->rhs_->accept(this));
142     if (n->rhs_->typeof_ != ExprNode::STRUCT)
143       return mkstatus_(n, "Right-hand side of assignment must be a struct");
144   } else {
145     if (n->lhs_->typeof_ != ExprNode::INTEGER)
146       return mkstatus_(n, "Left-hand side of assignment must be a numeric type");
147     if (!n->lhs_->flags_[ExprNode::WRITE])
148       return mkstatus_(n, "Left-hand side of assignment is read-only");
149     TRY2(n->rhs_->accept(this));
150     if (n->rhs_->typeof_ != ExprNode::INTEGER)
151       return mkstatus_(n, "Right-hand side of assignment must be a numeric type");
152   }
153   n->typeof_ = ExprNode::VOID;
154   return StatusTuple(0);
155 }
156 
visit_packet_expr_node(PacketExprNode * n)157 StatusTuple TypeCheck::visit_packet_expr_node(PacketExprNode *n) {
158   StructDeclStmtNode *struct_type = proto_scopes_->top_struct()->lookup(n->id_->name_, true);
159   if (!struct_type)
160     return mkstatus_(n, "Undefined packet header %s", n->id_->c_str());
161   if (n->id_->sub_name_.empty()) {
162     n->typeof_ = ExprNode::STRUCT;
163     n->struct_type_ = struct_type;
164   } else {
165     VariableDeclStmtNode *sub_decl = struct_type->field(n->id_->sub_name_);
166     if (!sub_decl)
167       return mkstatus_(n, "Access to invalid subfield %s.%s", n->id_->c_str(), n->id_->sub_name_.c_str());
168     n->typeof_ = ExprNode::INTEGER;
169     if (n->is_ref())
170       n->bit_width_ = 64;
171     else
172       n->bit_width_ = sub_decl->bit_width_;
173   }
174   n->flags_[ExprNode::WRITE] = true;
175   return StatusTuple(0);
176 }
177 
visit_integer_expr_node(IntegerExprNode * n)178 StatusTuple TypeCheck::visit_integer_expr_node(IntegerExprNode *n) {
179   n->typeof_ = ExprNode::INTEGER;
180   n->bit_width_ = n->bits_;
181   return StatusTuple(0);
182 }
183 
visit_string_expr_node(StringExprNode * n)184 StatusTuple TypeCheck::visit_string_expr_node(StringExprNode *n) {
185   n->typeof_ = ExprNode::STRING;
186   n->flags_[ExprNode::IS_REF] = true;
187   n->bit_width_ = n->val_.size() << 3;
188   return StatusTuple(0);
189 }
190 
visit_binop_expr_node(BinopExprNode * n)191 StatusTuple TypeCheck::visit_binop_expr_node(BinopExprNode *n) {
192   TRY2(n->lhs_->accept(this));
193   if (n->lhs_->typeof_ != ExprNode::INTEGER)
194     return mkstatus_(n, "Left-hand side of binary expression must be a numeric type");
195   TRY2(n->rhs_->accept(this));
196   if (n->rhs_->typeof_ != ExprNode::INTEGER)
197     return mkstatus_(n, "Right-hand side of binary expression must be a numeric type");
198   n->typeof_ = ExprNode::INTEGER;
199   switch(n->op_) {
200     case Tok::TCEQ:
201     case Tok::TCNE:
202     case Tok::TCLT:
203     case Tok::TCLE:
204     case Tok::TCGT:
205     case Tok::TCGE:
206       n->bit_width_ = 1;
207       break;
208     default:
209       n->bit_width_ = std::max(n->lhs_->bit_width_, n->rhs_->bit_width_);
210   }
211   return StatusTuple(0);
212 }
213 
visit_unop_expr_node(UnopExprNode * n)214 StatusTuple TypeCheck::visit_unop_expr_node(UnopExprNode *n) {
215   TRY2(n->expr_->accept(this));
216   if (n->expr_->typeof_ != ExprNode::INTEGER)
217     return mkstatus_(n, "Unary operand must be a numeric type");
218   n->copy_type(*n->expr_);
219   return StatusTuple(0);
220 }
221 
visit_bitop_expr_node(BitopExprNode * n)222 StatusTuple TypeCheck::visit_bitop_expr_node(BitopExprNode *n) {
223   if (n->expr_->typeof_ != ExprNode::INTEGER)
224     return mkstatus_(n, "Bitop [] can only operate on numeric types");
225   n->typeof_ = ExprNode::INTEGER;
226   return StatusTuple(0);
227 }
228 
visit_goto_expr_node(GotoExprNode * n)229 StatusTuple TypeCheck::visit_goto_expr_node(GotoExprNode *n) {
230   //n->id_->accept(this);
231   n->typeof_ = ExprNode::VOID;
232   return StatusTuple(0);
233 }
234 
visit_return_expr_node(ReturnExprNode * n)235 StatusTuple TypeCheck::visit_return_expr_node(ReturnExprNode *n) {
236   TRY2(n->expr_->accept(this));
237   n->typeof_ = ExprNode::VOID;
238   return StatusTuple(0);
239 }
240 
expect_method_arg(MethodCallExprNode * n,size_t num,size_t num_def_args=0)241 StatusTuple TypeCheck::expect_method_arg(MethodCallExprNode *n, size_t num, size_t num_def_args = 0) {
242   if (num_def_args == 0) {
243     if (n->args_.size() != num)
244       return mkstatus_(n, "%s expected %d argument%s, %zu given", n->id_->sub_name_.c_str(),
245                       num, num == 1 ? "" : "s", n->args_.size());
246   } else {
247     if (n->args_.size() < num - num_def_args || n->args_.size() > num)
248       return mkstatus_(n, "%s expected %d argument%s (%d default), %zu given", n->id_->sub_name_.c_str(),
249                       num, num == 1 ? "" : "s", num_def_args, n->args_.size());
250   }
251   return StatusTuple(0);
252 }
253 
check_lookup_method(MethodCallExprNode * n)254 StatusTuple TypeCheck::check_lookup_method(MethodCallExprNode *n) {
255   auto table = scopes_->top_table()->lookup(n->id_->name_);
256   if (!table)
257     return mkstatus_(n, "Unknown table name %s", n->id_->c_str());
258   TRY2(expect_method_arg(n, 2, 1));
259   if (table->type_id()->name_ == "LPM")
260     return mkstatus_(n, "LPM unsupported");
261   if (n->block_->scope_) {
262     auto result = make_unique<StructVariableDeclStmtNode>(table->leaf_id()->copy(), make_unique<IdentExprNode>("_result"),
263                                                           VariableDeclStmtNode::STRUCT_REFERENCE);
264     n->block_->scope_->add("_result", result.get());
265     n->block_->stmts_.insert(n->block_->stmts_.begin(), move(result));
266   }
267   return StatusTuple(0);
268 }
269 
check_update_method(MethodCallExprNode * n)270 StatusTuple TypeCheck::check_update_method(MethodCallExprNode *n) {
271   auto table = scopes_->top_table()->lookup(n->id_->name_);
272   if (!table)
273     return mkstatus_(n, "Unknown table name %s", n->id_->c_str());
274   if (table->type_id()->name_ == "FIXED_MATCH" || table->type_id()->name_ == "INDEXED")
275     TRY2(expect_method_arg(n, 2));
276   else if (table->type_id()->name_ == "LPM")
277     TRY2(expect_method_arg(n, 3));
278   return StatusTuple(0);
279 }
280 
check_delete_method(MethodCallExprNode * n)281 StatusTuple TypeCheck::check_delete_method(MethodCallExprNode *n) {
282   auto table = scopes_->top_table()->lookup(n->id_->name_);
283   if (!table)
284     return mkstatus_(n, "Unknown table name %s", n->id_->c_str());
285   if (table->type_id()->name_ == "FIXED_MATCH" || table->type_id()->name_ == "INDEXED")
286     TRY2(expect_method_arg(n, 1));
287   else if (table->type_id()->name_ == "LPM")
288     {}
289   return StatusTuple(0);
290 }
291 
visit_method_call_expr_node(MethodCallExprNode * n)292 StatusTuple TypeCheck::visit_method_call_expr_node(MethodCallExprNode *n) {
293   // be sure to visit those child nodes ASAP, so their properties can
294   // be propagated up to this node and be ready to be used
295   for (auto it = n->args_.begin(); it != n->args_.end(); ++it) {
296     TRY2((*it)->accept(this));
297   }
298 
299   n->typeof_ = ExprNode::VOID;
300   if (n->id_->sub_name_.size()) {
301     if (n->id_->sub_name_ == "lookup") {
302       TRY2(check_lookup_method(n));
303     } else if (n->id_->sub_name_ == "update") {
304       TRY2(check_update_method(n));
305     } else if (n->id_->sub_name_ == "delete") {
306       TRY2(check_delete_method(n));
307     } else if (n->id_->sub_name_ == "rewrite_field" && n->id_->name_ == "pkt") {
308       TRY2(expect_method_arg(n, 2));
309       n->args_[0]->flags_[ExprNode::IS_LHS] = true;
310     }
311   } else if (n->id_->name_ == "log") {
312     if (n->args_.size() < 1)
313       return mkstatus_(n, "%s expected at least 1 argument", n->id_->c_str());
314     if (n->args_[0]->typeof_ != ExprNode::STRING)
315       return mkstatus_(n, "%s expected a string for argument 1", n->id_->c_str());
316     n->typeof_ = ExprNode::INTEGER;
317     n->bit_width_ = 32;
318   } else if (n->id_->name_ == "atomic_add") {
319     TRY2(expect_method_arg(n, 2));
320     n->typeof_ = ExprNode::INTEGER;
321     n->bit_width_ = n->args_[0]->bit_width_;
322     n->args_[0]->flags_[ExprNode::IS_LHS] = true;
323   } else if (n->id_->name_ == "incr_cksum") {
324     TRY2(expect_method_arg(n, 4, 1));
325     n->typeof_ = ExprNode::INTEGER;
326     n->bit_width_ = 16;
327   } else if (n->id_->name_ == "sizeof") {
328     TRY2(expect_method_arg(n, 1));
329     n->typeof_ = ExprNode::INTEGER;
330     n->bit_width_ = 32;
331   } else if (n->id_->name_ == "get_usec_time") {
332      TRY2(expect_method_arg(n, 0));
333      n->typeof_ = ExprNode::INTEGER;
334      n->bit_width_ = 64;
335   }
336 
337   if (!n->block_->stmts_.empty()) {
338     if (n->id_->sub_name_ != "update" && n->id_->sub_name_ != "lookup")
339       return mkstatus_(n, "%s does not allow trailing block statements", n->id_->full_name().c_str());
340     TRY2(n->block_->accept(this));
341   }
342   return StatusTuple(0);
343 }
344 
visit_table_index_expr_node(TableIndexExprNode * n)345 StatusTuple TypeCheck::visit_table_index_expr_node(TableIndexExprNode *n) {
346   n->table_ = scopes_->top_table()->lookup(n->id_->name_);
347   if (!n->table_) return mkstatus_(n, "Unknown table name %s", n->id_->c_str());
348   TRY2(n->index_->accept(this));
349   if (n->index_->struct_type_ != n->table_->key_type_)
350     return mkstatus_(n, "Key to table %s lookup must be of type %s", n->id_->c_str(), n->table_->key_id()->c_str());
351 
352   if (n->sub_) {
353     n->sub_decl_ = n->table_->leaf_type_->field(n->sub_->name_);
354     if (!n->sub_decl_)
355       return mkstatus_(n, "Field %s is not a member of %s", n->sub_->c_str(), n->table_->leaf_id()->c_str());
356     n->typeof_ = ExprNode::INTEGER;
357   } else {
358     n->typeof_ = ExprNode::STRUCT;
359     n->flags_[ExprNode::IS_REF] = true;
360     n->struct_type_ = n->table_->leaf_type_;
361   }
362   return StatusTuple(0);
363 }
364 
visit_expr_stmt_node(ExprStmtNode * n)365 StatusTuple TypeCheck::visit_expr_stmt_node(ExprStmtNode *n) {
366   TRY2(n->expr_->accept(this));
367   return StatusTuple(0);
368 }
369 
visit_struct_variable_decl_stmt_node(StructVariableDeclStmtNode * n)370 StatusTuple TypeCheck::visit_struct_variable_decl_stmt_node(StructVariableDeclStmtNode *n) {
371   //TRY2(n->struct_id_->accept(this));
372   //TRY2(n->id_->accept(this));
373   if (!n->init_.empty()) {
374     StructDeclStmtNode *type;
375     if (n->struct_id_->scope_name_ == "proto")
376       type = proto_scopes_->top_struct()->lookup(n->struct_id_->name_, true);
377     else
378       type = scopes_->top_struct()->lookup(n->struct_id_->name_, true);
379 
380     if (!type)
381       return mkstatus_(n, "type %s does not exist", n->struct_id_->full_name().c_str());
382 
383     // init remaining fields to 0
384     set<string> used;
385     for (auto i = n->init_.begin(); i != n->init_.end(); ++i) {
386       auto asn = static_cast<AssignExprNode*>(i->get());
387       auto id = static_cast<IdentExprNode *>(asn->lhs_.get());
388       used.insert(id->sub_name_);
389     }
390     for (auto f = type->stmts_.begin(); f != type->stmts_.end(); ++f) {
391       if (used.find((*f)->id_->name_) == used.end()) {
392         auto id = make_unique<IdentExprNode>(n->id_->name_);
393         id->append_dot((*f)->id_->name_);
394         n->init_.push_back(make_unique<AssignExprNode>(move(id), make_unique<IntegerExprNode>("0")));
395       }
396     }
397 
398     for (auto it = n->init_.begin(); it != n->init_.end(); ++it) {
399       TRY2((*it)->accept(this));
400     }
401   }
402   return StatusTuple(0);
403 }
404 
visit_integer_variable_decl_stmt_node(IntegerVariableDeclStmtNode * n)405 StatusTuple TypeCheck::visit_integer_variable_decl_stmt_node(IntegerVariableDeclStmtNode *n) {
406   //TRY2(n->id_->accept(this));
407   if (!n->init_.empty()) {
408     TRY2(n->init_[0]->accept(this));
409   }
410   return StatusTuple(0);
411 }
412 
visit_struct_decl_stmt_node(StructDeclStmtNode * n)413 StatusTuple TypeCheck::visit_struct_decl_stmt_node(StructDeclStmtNode *n) {
414   //TRY2(n->id_->accept(this));
415   for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it) {
416     TRY2((*it)->accept(this));
417   }
418   return StatusTuple(0);
419 }
420 
visit_parser_state_stmt_node(ParserStateStmtNode * n)421 StatusTuple TypeCheck::visit_parser_state_stmt_node(ParserStateStmtNode *n) {
422   return StatusTuple(0);
423 }
424 
visit_state_decl_stmt_node(StateDeclStmtNode * n)425 StatusTuple TypeCheck::visit_state_decl_stmt_node(StateDeclStmtNode *n) {
426   if (!n->id_) {
427     return StatusTuple(0);
428   }
429   auto s1 = proto_scopes_->top_state()->lookup(n->id_->name_, true);
430   if (s1) {
431     const string &name = n->id_->name_;
432     auto offset_var = make_unique<IntegerVariableDeclStmtNode>(make_unique<IdentExprNode>("$" + name), "64");
433     offset_var->init_.push_back(make_unique<AssignExprNode>(offset_var->id_->copy(), make_unique<IntegerExprNode>("0")));
434     scopes_->current_var()->add("$" + name, offset_var.get());
435     s1->subs_[0].block_->scope_->add("$" + name, offset_var.get());
436     n->init_.push_back(move(offset_var));
437 
438     n->parser_ = ParserStateStmtNode::make(n->id_);
439     n->parser_->next_state_ = s1->subs_[0].block_.get();
440     n->parser_->scope_id_ = n->scope_id_;
441 
442     auto p = proto_scopes_->top_struct()->lookup(n->id_->name_, true);
443     if (!p) return mkstatus_(n, "unable to find struct decl for parser state %s", n->id_->full_name().c_str());
444 
445     // $proto = parsed_bytes; parsed_bytes += sizeof($proto);
446     auto asn1 = make_unique<AssignExprNode>(make_unique<IdentExprNode>("$" + n->id_->name_),
447                                             make_unique<IdentExprNode>("parsed_bytes"));
448     n->init_.push_back(make_unique<ExprStmtNode>(move(asn1)));
449     auto add_expr = make_unique<BinopExprNode>(make_unique<IdentExprNode>("parsed_bytes"), Tok::TPLUS,
450                                                make_unique<IntegerExprNode>(std::to_string(p->bit_width_ >> 3), 64));
451     auto asn2 = make_unique<AssignExprNode>(make_unique<IdentExprNode>("parsed_bytes"), move(add_expr));
452     n->init_.push_back(make_unique<ExprStmtNode>(move(asn2)));
453   }
454 
455   for (auto it = n->init_.begin(); it != n->init_.end(); ++it) {
456     TRY2((*it)->accept(this));
457   }
458 
459   for (auto it = n->subs_.begin(); it != n->subs_.end(); ++it) {
460     scopes_->push_state(it->scope_);
461 
462     TRY2(it->block_->accept(this));
463 
464     if (s1) {
465       if (it->id_->name_ == "") {
466         it->parser_ = ParserStateStmtNode::make(it->id_);
467         it->parser_->next_state_ = s1->subs_[0].block_.get();
468         it->parser_->scope_id_ = n->scope_id_ + n->id_->name_ + "_";
469       } else if (auto s2 = proto_scopes_->top_state()->lookup(it->id_->name_, true)) {
470         it->parser_ = ParserStateStmtNode::make(it->id_);
471         it->parser_->next_state_ = s2->subs_[0].block_.get();
472         it->parser_->scope_id_ = n->scope_id_ + n->id_->name_ + "_";
473       }
474 
475       if (it->parser_) {
476         TRY2(it->parser_->accept(this));
477       }
478     }
479 
480     scopes_->pop_state();
481   }
482   return StatusTuple(0);
483 }
484 
visit_match_decl_stmt_node(MatchDeclStmtNode * n)485 StatusTuple TypeCheck::visit_match_decl_stmt_node(MatchDeclStmtNode *n) {
486   //TRY2(n->id_->accept(this));
487   for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) {
488     TRY2((*it)->accept(this));
489   }
490   TRY2(n->block_->accept(this));
491   return StatusTuple(0);
492 }
493 
visit_miss_decl_stmt_node(MissDeclStmtNode * n)494 StatusTuple TypeCheck::visit_miss_decl_stmt_node(MissDeclStmtNode *n) {
495   //TRY2(n->id_->accept(this));
496   for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) {
497     TRY2((*it)->accept(this));
498   }
499   TRY2(n->block_->accept(this));
500   return StatusTuple(0);
501 }
502 
visit_failure_decl_stmt_node(FailureDeclStmtNode * n)503 StatusTuple TypeCheck::visit_failure_decl_stmt_node(FailureDeclStmtNode *n) {
504   //TRY2(n->id_->accept(this));
505   for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) {
506     TRY2((*it)->accept(this));
507   }
508   TRY2(n->block_->accept(this));
509   return StatusTuple(0);
510 }
511 
visit_table_decl_stmt_node(TableDeclStmtNode * n)512 StatusTuple TypeCheck::visit_table_decl_stmt_node(TableDeclStmtNode *n) {
513   n->key_type_ = scopes_->top_struct()->lookup(n->key_id()->name_, true);
514   if (!n->key_type_)
515     return mkstatus_(n, "Table key type %s undefined", n->key_id()->c_str());
516   n->key_id()->bit_width_ = n->key_type_->bit_width_;
517   n->leaf_type_ = scopes_->top_struct()->lookup(n->leaf_id()->name_, true);
518   if (!n->leaf_type_)
519     return mkstatus_(n, "Table leaf type %s undefined", n->leaf_id()->c_str());
520   n->leaf_id()->bit_width_ = n->leaf_type_->bit_width_;
521   if (n->type_id()->name_ == "INDEXED" && n->policy_id()->name_ != "AUTO") {
522     fprintf(stderr, "Table %s is INDEXED, policy should be AUTO\n", n->id_->c_str());
523     n->policy_id()->name_ = "AUTO";
524   }
525   if (n->policy_id()->name_ != "AUTO" && n->policy_id()->name_ != "NONE")
526     return mkstatus_(n, "Unsupported policy type %s", n->policy_id()->c_str());
527   return StatusTuple(0);
528 }
529 
visit_func_decl_stmt_node(FuncDeclStmtNode * n)530 StatusTuple TypeCheck::visit_func_decl_stmt_node(FuncDeclStmtNode *n) {
531   for (auto it = n->formals_.begin(); it != n->formals_.end(); ++it) {
532     VariableDeclStmtNode *var = it->get();
533     TRY2(var->accept(this));
534     if (var->is_struct()) {
535       if (!var->is_pointer())
536         return mkstatus_(n, "Only struct references allowed in function definitions");
537     }
538   }
539   scopes_->push_state(n->scope_);
540   TRY2(n->block_->accept(this));
541   scopes_->pop_state();
542   return StatusTuple(0);
543 }
544 
visit(Node * root)545 StatusTuple TypeCheck::visit(Node *root) {
546   BlockStmtNode *b = static_cast<BlockStmtNode*>(root);
547 
548   scopes_->set_current(scopes_->top_state());
549   scopes_->set_current(scopes_->top_var());
550 
551   // // packet data in bpf socket
552   // if (scopes_->top_struct()->lookup("_skbuff", true)) {
553   //   return StatusTuple(-1, "_skbuff already defined");
554   // }
555   // auto skb_type = make_unique<StructDeclStmtNode>(make_unique<IdentExprNode>("_skbuff"));
556   // scopes_->top_struct()->add("_skbuff", skb_type.get());
557   // b->stmts_.push_back(move(skb_type));
558 
559   // if (scopes_->current_var()->lookup("skb", true)) {
560   //   return StatusTuple(-1, "skb already defined");
561   // }
562   // auto skb = make_unique<StructVariableDeclStmtNode>(make_unique<IdentExprNode>("_skbuff"),
563   //                                                    make_unique<IdentExprNode>("skb"));
564   // skb->storage_type_ = VariableDeclStmtNode::STRUCT_REFERENCE;
565   // scopes_->current_var()->add("skb", skb.get());
566   // b->stmts_.push_back(move(skb));
567 
568   // offset counter
569   auto parsed_bytes = make_unique<IntegerVariableDeclStmtNode>(
570                         make_unique<IdentExprNode>("parsed_bytes"), "64");
571   parsed_bytes->init_.push_back(make_unique<AssignExprNode>(parsed_bytes->id_->copy(), make_unique<IntegerExprNode>("0")));
572   scopes_->current_var()->add("parsed_bytes", parsed_bytes.get());
573   b->stmts_.push_back(move(parsed_bytes));
574 
575   TRY2(b->accept(this));
576 
577   if (!errors_.empty()) {
578     for (auto it = errors_.begin(); it != errors_.end(); ++it) {
579       fprintf(stderr, "%s\n", it->c_str());
580     }
581     return StatusTuple(-1, errors_.begin()->c_str());
582   }
583   return StatusTuple(0);
584 }
585 
586 }  // namespace cc
587 }  // namespace ebpf
588