// Parse a function declaration. // // function-decl -> 'def' identifier parameter-clause return-type ';' // | 'def' identifier parameter-clause return-type function-definition // parameter-clause -> '(' [parameter-list] ')' // // parameter-list -> parameter-decl | parameter-decl ',' parameter-list // // return-type -> '->' type // // function-definition -> block-stmt // // A function declaration may not have a definition. Decl* Parser::function_decl(Specifier spec) { require(def_kw); Token n = match(identifier_tok); // parameter-clause Decl_seq parms; match(lparen_tok); while (lookahead() != rparen_tok) { Decl* p = parameter_decl(); parms.push_back(p); if (match_if(comma_tok)) continue; else break; } match(rparen_tok); // return-type match(arrow_tok); Type const* t = type(); // function declaration if (match_if(semicolon_tok)) return on_function(spec, n, parms, t); // function-definition. Stmt* s = block_stmt(); return on_function(spec, n, parms, t, s); }
// Parse a method declaration. // // // method-decl -> 'def' identifier parameter-clause return-type function-definition // // Note that methods must be declared inside // the class. // // TODO: Support out-of-class definitions? // // TODO: Support specifiers to modify the "this" // parameter. Maybe before the return type? Maybe // as part of the specifiers? // // TODO: // // struct R { // const def f() -> void { } // Why not... Decl* Parser::method_decl(Specifier spec) { require(def_kw); Token n = match(identifier_tok); //check for a this_kw //do stuff //return on_ctor <- reference on_method // parameter-clause Decl_seq parms; match(lparen_tok); while (lookahead() != rparen_tok) { Decl* p = parameter_decl(); parms.push_back(p); if (match_if(comma_tok)) continue; else break; } match(rparen_tok); // return-type match(arrow_tok); Type const* t = type(); // function-definition. Stmt* s = block_stmt(); return on_method(spec, n, parms, t, s); }
// NOTE ADD LAMDBA PARSER HERE Expr* Parser::lambda_expr() { require(bslash_tok); //Match the identifier inserted earlier Token n = match(identifier_tok); // parameter-clause Decl_seq parms; match(lparen_tok); while (lookahead() != rparen_tok) { Decl* p = parameter_decl(); parms.push_back(p); if (match_if(comma_tok)) { continue; } else break; } match(rparen_tok); // return-type match(arrow_tok); Type const* t = type(); // must be function-definition Stmt* s = block_stmt(); //return a lambda expression return on_lambda(n, parms, t, s); }
// Parse a module. // // module -> decl-seq | <empty> // // decl-seq -> decl | decl-seq // // TODO: Return an empty module. Decl* Parser::module() { Decl_seq decls; while (!ts_.eof()) { try { Decl* d = decl(); decls.push_back(d); } catch (Translation_error& err) { diagnose(err); consume_thru(term_); } } return on_module(decls); }
// Parse a record declaration. // // record-decl -> 'struct' identifier record-body // // record-body -> '{' field-seq '}' // // field-seq -> field-seq | field-seq field-seq Decl* Parser::record_decl(Specifier spec) { require(struct_kw); Token n = match(identifier_tok); // record-body and field-seq require(lbrace_tok); Decl_seq fs; while (lookahead() != rbrace_tok) { Decl* f = field_decl(); fs.push_back(f); } match(rbrace_tok); return on_record(spec, n, fs); }
// Returns an expression which computes the byte offsetof a // member within a record. // 'e' is an offsetof expression. // // The byte offset of a member within a record type // is the sum of the length of all fields preceding // it within the record. Expr* get_offset(Decl const* layout, Decl const* mem) { assert(is<Layout_decl>(layout)); // keep track of all member declarations coming before mem Decl_seq pred; Expr* offsetof = zero(); for (auto decl : as<Layout_decl>(layout)->fields()) { if (decl == mem) { break; } pred.push_back(decl); } for (auto decl : pred) { offsetof = add(offsetof, get_length(decl->type())); } return offsetof; }