// Parse a variable declaration. // // variable-decl -> 'var' identifier object-type initializer-clause // // initializer-clause -> ';' | '=' 'trivial' ';' | '=' expr ';' Decl* Parser::variable_decl(Specifier spec) { require(var_kw); Token n = match(identifier_tok); // object-type match(colon_tok); Type const* t = type(); // default initialization (var x : T;) if (match_if(semicolon_tok)) return on_variable(spec, n, t); // value initialization (var x : T = e;) match(equal_tok); if (match_if(trivial_kw)) { match(semicolon_tok); return on_variable(spec, n, t, trivial_kw); } Expr* e = expr(); match(semicolon_tok); return on_variable(spec, n, t, e); }
// Parse a relational expression. // // relational-expression: // shift-expression: // relational-expression '<' shift-expression // relational-expression '>' shift-expression // relational-expression '<=' shift-expression // relational-expression '>=' shift-expression // relational-expression '<=>' shift-expression Expr& Parser::relational_expression() { Expr* e1 = &shift_expression(); while (true) { if (Token tok = match_if(tk::lt_tok)) { Expr& e2 = shift_expression(); e1 = &on_lt_expression(tok, *e1, e2); } else if (Token tok = match_if(tk::gt_tok)) { Expr& e2 = shift_expression(); e1 = &on_gt_expression(tok, *e1, e2); } else if (Token tok = match_if(tk::lt_eq_tok)) { Expr& e2 = shift_expression(); e1 = &on_le_expression(tok, *e1, e2); } else if (Token tok = match_if(tk::gt_eq_tok)) { Expr& e2 = shift_expression(); e1 = &on_ge_expression(tok, *e1, e2); } else if (Token tok = match_if(tk::lt_eq_gt_tok)) { Expr& e2 = shift_expression(); e1 = &on_cmp_expression(tok, *e1, e2); } else { break; } } return *e1; }
// 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 class definition. // // class-declaration: // 'class' identifier [':'] class-body // 'class' identifier [':' type] class-body // 'class' identifier [':' extension] class-body // // NOTE: The parser currently allows the omission of the ':' because it // looks weird when the kind is not given explicitly omitted. // // TODO: We could use '=' notation in bodies to create new derived types. Decl& Parser::class_declaration() { Match_token_pred end_kind(*this, lbrace_tok); require(class_tok); Name& name = identifier(); // Match the metatype. Type* kind; if (match_if(colon_tok)) { if (match_if(extension_tok)) return extension_declaration(name, &cxt.get_type_type()); if (next_token_is(lbrace_tok)) kind = &cxt.get_type_type(); else kind = &unparsed_type(end_kind); } else { kind = &cxt.get_type_type(); } // Point of declaration. Decl& decl = start_class_declaration(name, *kind); Enter_scope scope(cxt, cxt.saved_scope(decl)); // Match the class body. Def& def = class_body(); return finish_class_definition(decl, def); };
// Parse a unary epxression. A unary expressions is one // that begins with an operator and is followed by a // unary expression. // // unary-expression ::= // primary-expression // | unary-operator unary-expression. Expr const* Parser::unary() { if (Token tok = match_if(plus_tok)) return on_unary(tok, unary()); if (Token tok = match_if(minus_tok)) return on_unary(tok, unary()); return primary(); }
// Parse a template argument. // // template-argument: // type // expression // template-name // // FIXME: The expression must be a constant expression. // // FIXME: In the last instance, the template name can be qualified. Term& Parser::template_argument() { if (Type* t = match_if(&Parser::type)) return *t; if (Expr* e = match_if(&Parser::expression)) return *e; if (Decl* d = match_if(&Parser::template_name)) return *d; throw Syntax_error("expected template-argument"); }
// Parse a nested-name specifier. // // nested-name-specifier: // leading-name-specifier // nested-name-specifier identifier '::' // nested-name-specifier simple-template-id '::' // // Here, the identifier and simple-template-id must be either // namespaces or types. In dependent contexts, those could also // be members of an unknown specialization. Decl& Parser::nested_name_specifier() { Decl* scope = &leading_name_specifier(); while (true) { if (Token id = match_if(identifier_tok)) scope = &on_nested_name_specifier(*scope, id); else if (Name* id = match_if(&Parser::simple_template_id)) scope = &on_nested_name_specifier(*scope, *id); else break; } return *scope; }
// Parse an additive expression. // // additive-expression ::= // multiplicative-expression // | additive-expression additive-operator multiplicative-expression Expr const* Parser::additive() { Expr const* e = multiplicative(); while (true) { if (Token tok = match_if(plus_tok)) e = on_binary(tok, e, multiplicative()); else if (Token tok = match_if(minus_tok)) e = on_binary(tok, e, multiplicative()); else break; } return e; }
// Parse a multiplicative expression. // // multiplicative-expression ::= // unary-expression // | multiplicative-expression multiplicative-operator unary-expression Expr const* Parser::multiplicative() { Expr const* e = unary(); while (true) { if (Token tok = match_if(star_tok)) e = on_binary(tok, e, unary()); else if (Token tok = match_if(slash_tok)) e = on_binary(tok, e, unary()); else if (Token tok = match_if(percent_tok)) e = on_binary(tok, e, unary()); else break; } return e; }
// 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 type template parameter. // // type-template-parameter: // typename [identifier] ['='' type] // // Note that the point of declaration for a template parameter is // past the full definition (after the default argument, if present). Decl& Parser::type_template_parameter() { match(tk::typename_tok); // Get the optional identifier. Create a placeholder // if no name is given. Name* n; if (Token id = match_if(tk::identifier_tok)) n = &on_simple_id(id); else n = &build.get_id(); // Parse the default argument. Type* t = nullptr; if (lookahead() == tk::eq_tok) t = &type(); // Point of declaration. Decl* d; if (t) d = &on_type_template_parameter(*n, *t); else d = &on_type_template_parameter(*n); return *d; }
// 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); }
// Parse a unary expression. // // unary-expr -> '+' unary-expr // | '-' unary-expr // | '!' unary-expr // | postfix-expr Expr* Parser::unary_expr() { if (match_if(plus_tok)) { Expr* e = unary_expr(); return on_pos(e); } else if (match_if(minus_tok)) { Expr* e = unary_expr(); return on_neg(e); } else if (match_if(not_tok)) { Expr* e = unary_expr(); return on_not(e); } else { return postfix_expr(); } }
// 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); const Type* t = nullptr; // Determine if it is inheriting from a base class if(match_if(colon_tok)){ // We have a base class t = type(); } // record-body and field-seq require(lbrace_tok); Decl_seq fs, ms; while (lookahead() != rbrace_tok) { Specifier spec = specifier_seq(); if (lookahead() == def_kw) { Decl* m = method_decl(spec); ms.push_back(m); } else if(lookahead() == identifier_tok) { Decl* f = field_decl(spec); fs.push_back(f); } else { throw Syntax_error(ts_.location(), "invalid member declaration"); } } match(rbrace_tok); // Need to replace nullptr with base record return on_record(spec, n, fs, ms, t); }
// Parse a sequence of declaration specifiers. // // specifier-seq -> specifier | specifier-seq specifier Specifier Parser::specifier_seq() { Specifier spec = no_spec; while (true) { if (match_if(foreign_kw)) spec |= foreign_spec; else if (match_if(abstract_kw)) spec |= abstract_spec; else if (match_if(virtual_kw)) spec |= virtual_spec; else break; } return spec; }
// Parse a variable declaration. // // variable-declaration: // 'var' identifier ':' [template-header] type ';' // 'var' identifier ':' [template-header] type '=' initializer ';' // 'var' identifier ':' '=' initializer ';' // // TODO: Are there other forms of variable declaration? Decl& Parser::variable_declaration() { // Helper functions. Match_any_token_pred end_type(*this, tk::eq_tok, tk::semicolon_tok); Match_token_pred end_init(*this, tk::semicolon_tok); require(tk::var_tok); Name& name = identifier(); match(tk::colon_tok); // Match the ":=" form. // if (match_if(tk::eq_tok)) { // Type& type = cxt.get_auto_type(object_type); // Expr& init = unparsed_expression(end_init); // match(tk::semicolon_tok); // return on_variable_declaration(name, type, init); // } // Match the type. Type& type = unparsed_type(end_type); // Match the "name : type =" form. if (match_if(tk::eq_tok)) { Expr& init = unparsed_expression(end_init); match(tk::semicolon_tok); return on_variable_declaration(name, type, init); } // Otherwise, match the "name : type ;" form. match(tk::semicolon_tok); return on_variable_declaration(name, type); }
// Parse a leading-name-specifier. This defines the set of // terms that can be nested within a nested-name-specifier. // // nested-name-specifier: // '::' // namespace-name '::' // type-name '::' // decltype-type '::' Decl& Parser::leading_name_specifier() { Decl* scope; if (lookahead() == colon_colon_tok) scope = &on_nested_name_specifier(); else if (lookahead() == decltype_tok) scope = &on_nested_name_specifier(decltype_type()); else if (Decl* n = match_if(&Parser::namespace_name)) scope = &on_nested_name_specifier(*n); else if (Type* t = match_if(&Parser::type_name)) scope = &on_nested_name_specifier(*t); else throw Syntax_error("expected leading-name-specifier"); match(colon_colon_tok); return *scope; }
// Parse an equality expression. // // equality-expr -> equality-expr '<' ordering-expr // | equality-expr '>' ordering-expr // | equality-expr '<=' ordering-expr // | equality-expr '>=' ordering-expr // | ordering-expr Expr* Parser::equality_expr() { Expr* e1 = ordering_expr(); while (true) { if (match_if(eq_tok)) { Expr* e2 = ordering_expr(); e1 = on_eq(e1, e2); } else if (match_if(ne_tok)) { Expr* e2 = ordering_expr(); e1 = on_ne(e1, e2); } else { break; } } return e1; }
// Parse an additive expression. // // additive-expr -> additive-expr '*' multiplicative-expr // | additive-expr '/' multiplicative-expr // | multiplicative-expr Expr* Parser::additive_expr() { Expr* e1 = multiplicative_expr(); while (true) { if (match_if(plus_tok)) { Expr* e2 = multiplicative_expr(); e1 = on_add(e1, e2); } else if (match_if(minus_tok)) { Expr* e2 = multiplicative_expr(); e1 = on_sub(e1, e2); } else { break; } } return e1; }
// Parse an additive expression. // // additive-expression: // multiplicative-expression: // additive-expression '+' multiplicative-expression // additive-expression '-' multiplicative-expression Expr& Parser::additive_expression() { Expr* e1 = &multiplicative_expression(); while (true) { if (Token tok = match_if(tk::plus_tok)) { Expr& e2 = multiplicative_expression(); e1 = &on_add_expression(tok, *e1, e2); } else if (Token tok = match_if(tk::minus_tok)) { Expr& e2 = unary_expression(); e1 = &on_sub_expression(tok, *e1, e2); } else { break; } } return *e1; }
// Parse a shift expression. // // shift-expression: // additive_expression: // shift-expression '<<' additive_expression // shift-expression '>>' additive_expression // Expr& Parser::shift_expression() { Expr* e1 = &additive_expression(); while (true) { if (Token tok = match_if(tk::lt_lt_tok)) { Expr& e2 = additive_expression(); e1 = &on_lsh_expression(tok, *e1, e2); } else if (Token tok = match_if(tk::gt_gt_tok)) { Expr& e2 = additive_expression(); e1 = &on_rsh_expression(tok, *e1, e2); } else { break; } } return *e1; }
// Parse an equality expression. // // equality-expression: // relational-expression: // equality-expression '==' relational-expression // equality-expression '!=' relational-expression Expr& Parser::equality_expression() { Expr* e1 = &relational_expression(); while (true) { if (Token tok = match_if(tk::eq_eq_tok)) { Expr& e2 = relational_expression(); e1 = &on_eq_expression(tok, *e1, e2); } else if (Token tok = match_if(tk::bang_eq_tok)) { Expr& e2 = relational_expression(); e1 = &on_ne_expression(tok, *e1, e2); } else { break; } } return *e1; }
// Parse a qualified type. // // unary-type: // postfix-type // '*' unary-type // 'const' unary-type // 'volatile' unary-type Type& Parser::unary_type() { if (match_if(const_tok)) { Type& t = unary_type(); return on_const_type(t); } if (match_if(volatile_tok)) { Type& t = unary_type(); return on_volatile_type(t); } if (match_if(star_tok)) { Type& t = unary_type(); return on_pointer_type(t); } return postfix_type(); }
// Parse a suffix type specifier. // // suffix-type: // prefix-type ['...'] Type& Parser::suffix_type() { Type& t = prefix_type(); if (match_if(ellipsis_tok)) return on_pack_type(t); return t; }
// Parse a type name. // // type-name: // class-name // union-name // enum-name // type-alias // // Note that all of these names are either identifiers or // simple-template-ids. Match syntactically and differentiate // semantically. Type& Parser::type_name() { if (Name* n = match_if(&Parser::simple_template_id)) return on_type_name(*n); Token id = match(identifier_tok); return on_type_name(id); }
// arrow-type: base-type '->' arrow_type // type Type const* Parser::arrow_type() { Type const* t = primary_type(); if (match_if(arrow_tok)) t = on_arrow_type(t, arrow_type()); return t; }
// Parse a type-alias. // // type-alias: // identifier // template-id Type& Parser::type_alias() { if (Name* n = match_if(&Parser::template_id)) return on_type_alias(*n); Token id = match(identifier_tok); return on_type_alias(id); }
// Parse a namespace-alias. // // namespace-alias: // identifier // template-id Decl& Parser::namespace_alias() { if (Name* n = match_if(&Parser::template_id)) return on_namespace_alias(*n); Token id = match(identifier_tok); return on_namespace_alias(id); }
// Parse a type list. // // type-list: // type // type-list ',' type Type_list Parser::type_list() { Type_list types; types.push_back(type()); while (match_if(comma_tok)) types.push_back(type()); return types; }
// Parse a template parameter list. // // template-parameter-list: // template-parameter // template-parameter-list ',' template-parameter Decl_list Parser::template_parameter_list() { Decl_list ds; do { Decl& d = template_parameter(); ds.push_back(d); } while (match_if(tk::comma_tok)); return ds; }