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