From ea3291cbe5192fa20f1a5d4dc45d776e48c21b7d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 21 Feb 2016 21:19:31 +1100 Subject: Fixing parser deficiencies --- src/ast/ast.cpp | 3 +- src/ast/ast.hpp | 52 ++++++-- src/ast/pattern.cpp | 15 ++- src/ast/pattern.hpp | 21 ++-- src/convert/ast_iterate.cpp | 3 + src/dump_as_rust.cpp | 8 +- src/parse/common.hpp | 5 + src/parse/expr.cpp | 60 +++++++-- src/parse/lex.cpp | 205 +++++++++++++++++++++---------- src/parse/lex.hpp | 10 ++ src/parse/parseerror.cpp | 9 +- src/parse/paths.cpp | 2 + src/parse/pattern.cpp | 7 ++ src/parse/root.cpp | 291 ++++++++++++++++++++++++++++++-------------- src/parse/types.cpp | 82 +++++++++---- src/types.hpp | 5 +- 16 files changed, 564 insertions(+), 214 deletions(-) (limited to 'src') diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index 7d6185e3..c8ad705f 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -500,7 +500,8 @@ SERIALISE_TYPE(ExternCrate::, "AST_ExternCrate", { },{ }) -SERIALISE_TYPE_A(MacroItem::, "AST_MacroItem", { +SERIALISE_TYPE_A(MacroInvocation::, "AST_MacroInvocation", { + s.item(m_attrs); s.item(m_macro_name); s.item(m_ident); s.item(m_input); diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 9c644bf6..a703da89 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -398,6 +398,7 @@ class Trait: ::std::vector m_supertraits; ItemList m_types; ItemList m_functions; + ItemList m_statics; public: Trait() {} Trait(MetaItems attrs, GenericParams params, ::std::vector supertraits): @@ -412,6 +413,7 @@ public: const ::std::vector& supertraits() const { return m_supertraits; } const ItemList& functions() const { return m_functions; } const ItemList& types() const { return m_types; } + const ItemList& statics() const { return m_statics; } GenericParams& params() { return m_params; } ::std::vector& supertraits() { return m_supertraits; } @@ -424,6 +426,9 @@ public: void add_function(::std::string name, Function fcn) { m_functions.push_back( Item(::std::move(name), ::std::move(fcn), true) ); } + void add_static(::std::string name, Static v) { + m_statics.push_back( Item(mv$(name), mv$(v), true) ); + } bool has_named_item(const ::std::string& name, bool& out_is_fcn) const { for( const auto& f : m_functions ) @@ -450,25 +455,31 @@ struct EnumVariant: MetaItems m_attrs; ::std::string m_name; ::std::vector m_sub_types; - int64_t m_value; + ::std::vector m_fields; + AST::Expr m_value; - EnumVariant(): - m_value(0) + EnumVariant() { } - EnumVariant(MetaItems attrs, ::std::string name, int64_t value): + EnumVariant(MetaItems attrs, ::std::string name, Expr&& value): + m_attrs( mv$(attrs) ), + m_name( mv$(name) ), + m_value( mv$(value) ) + { + } + + EnumVariant(MetaItems attrs, ::std::string name, ::std::vector sub_types): m_attrs( move(attrs) ), m_name( ::std::move(name) ), - m_value( value ) + m_sub_types( ::std::move(sub_types) ) { } - EnumVariant(MetaItems attrs, ::std::string name, ::std::vector sub_types): + EnumVariant(MetaItems attrs, ::std::string name, ::std::vector fields): m_attrs( move(attrs) ), m_name( ::std::move(name) ), - m_sub_types( ::std::move(sub_types) ), - m_value(0) + m_fields( ::std::move(fields) ) { } @@ -571,6 +582,7 @@ class Impl: ItemList m_types; ItemList m_functions; + ItemList m_statics; ::std::vector< ::std::pair< ::std::vector, Impl > > m_concrete_impls; public: @@ -586,6 +598,9 @@ public: void add_type(bool is_public, ::std::string name, TypeRef type) { m_types.push_back( Item( ::std::move(name), ::std::move(type), is_public ) ); } + void add_static(bool is_public, ::std::string name, Static v) { + m_statics.push_back( Item( mv$(name), mv$(v), is_public ) ); + } const ImplDef& def() const { return m_def; } const ItemList& functions() const { return m_functions; } @@ -615,7 +630,7 @@ class Module; typedef void fcn_visitor_t(const AST::Crate& crate, const AST::Module& mod, Function& fcn); -class MacroItem: +class MacroInvocation: public Serialisable { MetaItems m_attrs; @@ -623,11 +638,11 @@ class MacroItem: ::std::string m_ident; TokenTree m_input; public: - MacroItem() + MacroInvocation() { } - MacroItem(MetaItems attrs, ::std::string macro, ::std::string ident, TokenTree input): + MacroInvocation(MetaItems attrs, ::std::string macro, ::std::string ident, TokenTree input): m_attrs( mv$(attrs) ), m_macro_name( mv$(macro) ), m_ident( mv$(ident) ), @@ -635,7 +650,18 @@ public: { } + static ::std::unique_ptr from_deserialiser(Deserialiser& s) { + auto i = new MacroInvocation; + s.item( *i ); + return ::std::unique_ptr(i); + } + SERIALISABLE_PROTOTYPES(); + + friend ::std::ostream& operator<<(::std::ostream& os, const MacroInvocation& x) { + os << x.m_attrs << x.m_macro_name << "! " << x.m_ident << x.m_input; + return os; + } }; /// Representation of a parsed (and being converted) function @@ -664,7 +690,7 @@ class Module: itemlist_macros_t m_macros; macro_imports_t m_macro_imports; // module => macro ::std::vector< ItemNS > m_macro_import_res; // Vec of imported macros (not serialised) - ::std::vector m_macro_invocations; + ::std::vector m_macro_invocations; @@ -728,7 +754,7 @@ public: m_macros.push_back( Item( move(name), move(macro), is_exported ) ); } void add_macro_import(const Crate& crate, ::std::string mod, ::std::string name); - void add_macro_invocation(MacroItem item) { + void add_macro_invocation(MacroInvocation item) { m_macro_invocations.push_back( mv$(item) ); } diff --git a/src/ast/pattern.cpp b/src/ast/pattern.cpp index f2279a55..7ebdb35d 100644 --- a/src/ast/pattern.cpp +++ b/src/ast/pattern.cpp @@ -15,12 +15,15 @@ namespace AST { { os << "Pattern(" << pat.m_binding << " @ "; TU_MATCH(Pattern::Data, (pat.m_data), (ent), - (Any, - os << "_"; - ), (MaybeBind, os << "?"; ), + (Macro, + os << *ent.inv; + ), + (Any, + os << "_"; + ), (Box, os << "box " << *ent.sub; ), @@ -62,6 +65,9 @@ SERIALISE_TYPE(Pattern::, "Pattern", { ), (MaybeBind, ), + (Macro, + s.item( e.inv ); + ), (Box, s << e.sub; ), @@ -94,6 +100,9 @@ SERIALISE_TYPE(Pattern::, "Pattern", { _D(Any, ) _D(MaybeBind, ) + _D(Macro, + s.item( ent.inv ); + ) _D(Box, s.item( ent.sub ); ) diff --git a/src/ast/pattern.hpp b/src/ast/pattern.hpp index f28fe8e3..6cd78e91 100644 --- a/src/ast/pattern.hpp +++ b/src/ast/pattern.hpp @@ -11,6 +11,7 @@ namespace AST { using ::std::unique_ptr; using ::std::move; +class MacroInvocation; class ExprNode; @@ -19,8 +20,9 @@ class Pattern: { public: TAGGED_UNION(Data, Any, - (Any, () ), (MaybeBind, () ), + (Macro, (unique_ptr<::AST::MacroInvocation> inv;) ), + (Any, () ), (Box, (unique_ptr sub;) ), (Ref, (bool mut; unique_ptr sub;) ), (Value, (unique_ptr start; unique_ptr end;) ), @@ -36,6 +38,17 @@ public: Pattern() {} + struct TagMaybeBind {}; + Pattern(TagMaybeBind, ::std::string name): + m_binding(name), + m_data( Data::make_MaybeBind({}) ) + {} + + struct TagMacro {}; + Pattern(TagMacro, unique_ptr<::AST::MacroInvocation> inv): + m_data( Data::make_Macro({mv$(inv)}) ) + {} + // Wildcard = '..', distinct from '_' // TODO: Store wildcard as a different pattern type struct TagWildcard {}; @@ -47,12 +60,6 @@ public: m_binding(name) {} - struct TagMaybeBind {}; - Pattern(TagMaybeBind, ::std::string name): - m_binding(name), - m_data( Data::make_MaybeBind({}) ) - {} - struct TagBox {}; Pattern(TagBox, Pattern sub): m_data( Data::make_Box({ unique_ptr(new Pattern(mv$(sub))) }) ) diff --git a/src/convert/ast_iterate.cpp b/src/convert/ast_iterate.cpp index 3674d947..f5bc805e 100644 --- a/src/convert/ast_iterate.cpp +++ b/src/convert/ast_iterate.cpp @@ -123,6 +123,9 @@ void CASTIterator::handle_pattern(AST::Pattern& pat, const TypeRef& type_hint) (Any, // Wildcard, nothing to do ), + (Macro, + // Macro, nothing really (should be impossible?) + ), (Box, { auto& v = pat.data().as_Box(); if( type_hint.is_wildcard() ) diff --git a/src/dump_as_rust.cpp b/src/dump_as_rust.cpp index a498e626..f7f1d30b 100644 --- a/src/dump_as_rust.cpp +++ b/src/dump_as_rust.cpp @@ -746,6 +746,9 @@ void RustPrinter::print_pattern(const AST::Pattern& p, bool is_refutable) (MaybeBind, m_os << "_ /*?*/"; ), + (Macro, + m_os << *v.inv; + ), (Box, { const auto& v = p.data().as_Box(); m_os << "& "; @@ -854,10 +857,13 @@ void RustPrinter::handle_enum(const AST::Enum& s) for( const auto& t : i.m_sub_types ) m_os << t.print_pretty() << ", "; } - else if(i.m_value > 0) + else if(i.m_value.is_valid()) { m_os << " = " << i.m_value; } + else + { + } m_os << ",\n"; idx ++; } diff --git a/src/parse/common.hpp b/src/parse/common.hpp index e24ef82b..def771e2 100644 --- a/src/parse/common.hpp +++ b/src/parse/common.hpp @@ -39,13 +39,18 @@ extern ::std::vector Parse_Path_GenericList(TokenStream& lex); extern AST::MetaItem Parse_MetaItem(TokenStream& lex); +extern ::AST::MacroInvocation Parse_MacroInvocation(::AST::MetaItems meta_items, ::std::string name, TokenStream& lex); extern TypeRef Parse_Type(TokenStream& lex); extern AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable); extern void Parse_Use(TokenStream& lex, ::std::function fcn); extern AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems meta_items); +extern AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems meta_items); +extern AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items); extern void Parse_Impl(TokenStream& lex, AST::Module& mod, bool is_unsafe=false); extern void Parse_MacroRules(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items); +extern void Parse_ExternCrate(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items); + extern AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, AST::MetaItems attrs, bool allow_self, bool can_be_prototype); extern AST::Function Parse_FunctionDefWithCode(TokenStream& lex, ::std::string abi, AST::MetaItems attrs, bool allow_self); diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 47fe444a..723352d3 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -93,7 +93,13 @@ ExprNodeP Parse_ExprBlockNode(TokenStream& lex) // 'extern' blocks case TOK_RWORD_EXTERN: keep_mod = true; - Parse_ExternBlock(lex, ::std::move(item_attrs), local_mod->functions()); + if( GET_TOK(tok, lex) == TOK_RWORD_CRATE ) { + Parse_ExternCrate(lex, *local_mod, mv$(item_attrs)); + } + else { + lex.putback(tok); + Parse_ExternBlock(lex, ::std::move(item_attrs), local_mod->functions()); + } break; // - 'const' case TOK_RWORD_CONST: @@ -142,6 +148,20 @@ ExprNodeP Parse_ExprBlockNode(TokenStream& lex) ::std::string name = tok.str(); local_mod->add_struct(false, mv$(name), Parse_Struct(lex, item_attrs)); break; } + // - 'enum' + case TOK_RWORD_ENUM: { + keep_mod = true; + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + local_mod->add_enum(false, mv$(name), Parse_EnumDef(lex, item_attrs)); + break; } + // - 'trait' + case TOK_RWORD_TRAIT: { + keep_mod = true; + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = tok.str(); + local_mod->add_trait(false, mv$(name), Parse_TraitDef(lex, mv$(item_attrs))); + break; } // - 'impl' case TOK_RWORD_IMPL: keep_mod = true; @@ -306,8 +326,9 @@ void Parse_ExternBlock(TokenStream& lex, AST::MetaItems attrs, ::std::vector< AS if( GET_TOK(tok, lex) == TOK_STRING ) { abi = tok.str(); } - else + else { lex.putback(tok); + } bool is_block = false; if( GET_TOK(tok, lex) == TOK_BRACE_OPEN ) { @@ -507,8 +528,17 @@ ExprNodeP Parse_Stmt(TokenStream& lex) { case TOK_RWORD_RETURN: { ExprNodeP val; - if( LOOK_AHEAD(lex) != TOK_SEMICOLON && LOOK_AHEAD(lex) != TOK_COMMA && LOOK_AHEAD(lex) != TOK_BRACE_CLOSE ) { + switch(LOOK_AHEAD(lex)) + { + case TOK_SEMICOLON: + case TOK_COMMA: + case TOK_BRACE_CLOSE: + case TOK_PAREN_CLOSE: + case TOK_SQUARE_CLOSE: + break; + default: val = Parse_Expr1(lex); + break; } return NEWNODE( AST::ExprNode_Flow, AST::ExprNode_Flow::RETURN, "", ::std::move(val) ); } @@ -529,14 +559,22 @@ ExprNodeP Parse_Stmt(TokenStream& lex) GET_TOK(tok, lex); } ExprNodeP val; - if( tok.type() != TOK_SEMICOLON && tok.type() != TOK_COMMA && tok.type() != TOK_BRACE_CLOSE ) { + switch(tok.type()) + { + case TOK_SEMICOLON: + case TOK_COMMA: + case TOK_BRACE_CLOSE: + case TOK_PAREN_CLOSE: + case TOK_SQUARE_CLOSE: + lex.putback(tok); + break; + default: lex.putback(tok); val = Parse_Expr1(lex); + break; } - else - lex.putback(tok); return NEWNODE( AST::ExprNode_Flow, type, lifetime, ::std::move(val) ); - } + } default: lex.putback(tok); return Parse_Expr0(lex); @@ -556,7 +594,7 @@ ExprNodeP Parse_Stmt(TokenStream& lex) { lex.putback(tok); do { - rv.push_back( Parse_Expr0(lex) ); + rv.push_back( Parse_Stmt(lex) ); } while( GET_TOK(tok, lex) == TOK_COMMA ); CHECK_TOK(tok, TOK_PAREN_CLOSE); } @@ -598,7 +636,7 @@ ExprNodeP Parse_Expr0(TokenStream& lex) case TOK_EQUAL: op = AST::ExprNode_Assign::NONE; - return NEWNODE( AST::ExprNode_Assign, op, ::std::move(rv), Parse_Expr1(lex) ); + return NEWNODE( AST::ExprNode_Assign, op, ::std::move(rv), Parse_Expr0(lex) ); default: lex.putback(tok); @@ -1091,7 +1129,7 @@ ExprNodeP Parse_ExprVal(TokenStream& lex) CLEAR_PARSE_FLAG(lex, disallow_struct_literal); lex.putback(tok); - ExprNodeP rv = Parse_Expr0(lex); + ExprNodeP rv = Parse_Stmt(lex); if( GET_TOK(tok, lex) == TOK_COMMA ) { ::std::vector ents; ents.push_back( ::std::move(rv) ); @@ -1099,7 +1137,7 @@ ExprNodeP Parse_ExprVal(TokenStream& lex) if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE ) break; lex.putback(tok); - ents.push_back( Parse_Expr0(lex) ); + ents.push_back( Parse_Stmt(lex) ); } while( GET_TOK(tok, lex) == TOK_COMMA ); rv = NEWNODE( AST::ExprNode_Tuple, ::std::move(ents) ); } diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp index 2338adcd..dc206ad8 100644 --- a/src/parse/lex.cpp +++ b/src/parse/lex.cpp @@ -200,12 +200,14 @@ signed int Lexer::getSymbol() return best; } -bool issym(char ch) +bool issym(int ch) { if( ::std::isalnum(ch) ) return true; if( ch == '_' ) return true; + if( ch >= 128 || ch < 0 ) + return true; return false; } @@ -279,7 +281,7 @@ Token Lexer::getTokenInt() uint64_t val = 0; if( ch == '0' ) { // Octal/hex handling - ch = this->getc(); + ch = this->getc_num(); if( ch == 'x' ) { num_mode = HEX; while( isxdigit(ch = this->getc_num()) ) @@ -323,7 +325,7 @@ Token Lexer::getTokenInt() } } - if(ch == 'u' || ch == 'i') { + if(issym(ch)) { // Unsigned ::std::string suffix; while( issym(ch) ) @@ -344,6 +346,8 @@ Token Lexer::getTokenInt() else if(suffix == "u32") num_type = CORETYPE_U32; else if(suffix == "u64") num_type = CORETYPE_U64; else if(suffix == "usize") num_type = CORETYPE_UINT; + else if(suffix == "f32") num_type = CORETYPE_F32; + else if(suffix == "f64") num_type = CORETYPE_F64; else throw ParseError::Generic(*this, FMT("Unknown integer suffix '" << suffix << "'")); return Token(val, num_type); @@ -375,7 +379,7 @@ Token Lexer::getTokenInt() this->ungetc(); double fval = this->parseFloat(val); - if( (ch = this->getc()) == 'f' ) + if( issym(ch = this->getc()) ) { ::std::string suffix; while( issym(ch) ) @@ -403,62 +407,60 @@ Token Lexer::getTokenInt() return Token(val, num_type); } } - // Symbols - else if( issym(ch) ) + // Byte/Raw strings + else if( ch == 'b' || ch == 'r' ) { - ::std::string str; - while( issym(ch) ) - { - str.push_back(ch); + bool is_byte = false; + if(ch == 'b') { + is_byte = true; ch = this->getc(); } - - if( ch == '!' ) - { - return Token(TOK_MACRO, str); + + if(ch == 'r') { + return this->getTokenInt_RawString(is_byte); } - else - { - if( str == "b" ) - { - if( ch == '\'' ) { - // Byte constant - ch = this->getc(); - if( ch == '\\' ) { - uint32_t val = this->parseEscape('\''); - if( this->getc() != '\'' ) - throw ParseError::Generic(*this, "Multi-byte character literal"); - return Token((uint64_t)val, CORETYPE_U8); - } - else { - if( this->getc() != '\'' ) - throw ParseError::Generic(*this, "Multi-byte character literal"); - return Token((uint64_t)ch, CORETYPE_U8); - } + else { + assert(is_byte); + + // Byte string + if( ch == '"' ) { + ::std::string str; + while( (ch = this->getc()) != '"' ) + { + if( ch == '\\' ) + ch = this->parseEscape('"'); + str.push_back(ch); } - else if( ch == '"') { - ::std::string str; - while( (ch = this->getc()) != '"' ) - { - if( ch == '\\' ) - ch = this->parseEscape('"'); - str.push_back(ch); - } - return Token(TOK_BYTESTRING, str); + return Token(TOK_BYTESTRING, str); + } + // Byte constant + else if( ch == '\'' ) { + // Byte constant + ch = this->getc(); + if( ch == '\\' ) { + uint32_t val = this->parseEscape('\''); + if( this->getc() != '\'' ) + throw ParseError::Generic(*this, "Multi-byte character literal"); + return Token((uint64_t)val, CORETYPE_U8); } else { + if( this->getc() != '\'' ) + throw ParseError::Generic(*this, "Multi-byte character literal"); + return Token((uint64_t)ch, CORETYPE_U8); } } - - this->ungetc(); - for( unsigned int i = 0; i < LEN(RWORDS); i ++ ) - { - if( str < RWORDS[i].chars ) break; - if( str == RWORDS[i].chars ) return Token((enum eTokenType)RWORDS[i].type); + else { + assert(is_byte); + this->ungetc(); + return this->getTokenInt_Identifier('b'); } - return Token(TOK_IDENT, str); } } + // Symbols + else if( issym(ch) ) + { + return this->getTokenInt_Identifier(ch); + } else { throw ParseError::BadChar(ch); @@ -497,17 +499,25 @@ Token Lexer::getTokenInt() } return Token(TOK_COMMENT, str); } case SINGLEQUOTE: { - char firstchar = this->getc(); - if( firstchar != '\\' ) { + auto firstchar = this->getc_codepoint(); + if( firstchar.v == '\\' ) { + // Character constant with an escape code + uint32_t val = this->parseEscape('\''); + if(this->getc() != '\'') { + throw ParseError::Todo("Proper error for lex failures"); + } + return Token((uint64_t)val, CORETYPE_CHAR); + } + else { ch = this->getc(); if( ch == '\'' ) { // Character constant - return Token((uint64_t)firstchar, CORETYPE_CHAR); + return Token((uint64_t)firstchar.v, CORETYPE_CHAR); } - else { + else if( issym(firstchar.v) ) { // Lifetime name ::std::string str; - str.push_back(firstchar); + str += firstchar; while( issym(ch) ) { str.push_back(ch); @@ -516,14 +526,9 @@ Token Lexer::getTokenInt() this->ungetc(); return Token(TOK_LIFETIME, str); } - } - else { - // Character constant with an escape code - uint32_t val = this->parseEscape('\''); - if(this->getc() != '\'') { - throw ParseError::Todo("Proper error for lex failures"); + else { + throw ParseError::Todo("Lex Fail - Expected ' after character constant"); } - return Token((uint64_t)val, CORETYPE_CHAR); } break; } case DOUBLEQUOTE: { @@ -548,6 +553,72 @@ Token Lexer::getTokenInt() //assert(!"bugcheck"); } +Token Lexer::getTokenInt_RawString(bool is_byte) +{ + // Raw string (possibly byte) + char ch = this->getc(); + unsigned int hashes = 0; + while(ch == '#') + { + hashes ++; + ch = this->getc(); + } + if( hashes == 0 && ch != '"' ) { + this->ungetc(); + return this->getTokenInt_Identifier('r'); + } + char terminator = ch; + ::std::string val; + + for(;;) + { + ch = this->getc(); + if( ch == terminator ) { + for(unsigned i = 0; i < hashes; i ++) + { + ch = this->getc(); + if( ch != '#' ) { + val += terminator; + while( i -- ) + val += '#'; + break ; + } + } + if( hashes == 0 || ch == '#' ) { + return Token(is_byte ? TOK_BYTESTRING : TOK_STRING, val); + } + } + else { + val += ch; + } + } +} +Token Lexer::getTokenInt_Identifier(char leader) +{ + char ch = leader; + ::std::string str; + while( issym(ch) ) + { + str.push_back(ch); + ch = this->getc(); + } + + if( ch == '!' ) + { + return Token(TOK_MACRO, str); + } + else + { + this->ungetc(); + for( unsigned int i = 0; i < LEN(RWORDS); i ++ ) + { + if( str < RWORDS[i].chars ) break; + if( str == RWORDS[i].chars ) return Token((enum eTokenType)RWORDS[i].type); + } + return Token(TOK_IDENT, str); + } +} + // Takes the VERY lazy way of reading the float into a string then passing to strtod double Lexer::parseFloat(uint64_t whole) { @@ -615,6 +686,8 @@ uint32_t Lexer::parseEscape(char enclosing) else ; return val; } + case '0': + return '\0'; case '\\': return '\\'; case '\'': @@ -628,7 +701,7 @@ uint32_t Lexer::parseEscape(char enclosing) case 't': return '\t'; case '\n': - m_line ++; + m_line ++; while( isspace(ch) ) ch = this->getc(); return ch; @@ -662,6 +735,16 @@ char Lexer::getc_num() } while( ch == '_' ); return ch; } +Codepoint Lexer::getc_codepoint() +{ + uint8_t v1 = this->getc(); + if( v1 < 128 ) { + return {v1}; + } + else { + throw ParseError::Todo("getc_codepoint"); + } +} void Lexer::ungetc() { diff --git a/src/parse/lex.hpp b/src/parse/lex.hpp index 30500ba2..1b37127e 100644 --- a/src/parse/lex.hpp +++ b/src/parse/lex.hpp @@ -172,6 +172,13 @@ public: #define CLEAR_PARSE_FLAG(lex, flag) SavedParseState _sps(lex, lex.parse_state()); lex.parse_state().flag = false #define CHECK_PARSE_FLAG(lex, flag) (lex.parse_state().flag == true) +struct Codepoint { + uint32_t v; + friend ::std::string& operator+=(::std::string& s, const Codepoint& cp) { + return s; + } +}; + class Lexer: public TokenStream { @@ -193,11 +200,14 @@ private: Token getTokenInt(); signed int getSymbol(); + Token getTokenInt_RawString(bool is_byte); + Token getTokenInt_Identifier(char ch); double parseFloat(uint64_t whole); uint32_t parseEscape(char enclosing); char getc(); char getc_num(); + Codepoint getc_codepoint(); void ungetc(); class EndOfFile {}; diff --git a/src/parse/parseerror.cpp b/src/parse/parseerror.cpp index 0d58bd52..bd9d5a7c 100644 --- a/src/parse/parseerror.cpp +++ b/src/parse/parseerror.cpp @@ -78,7 +78,14 @@ ParseError::Unexpected::Unexpected(const TokenStream& lex, Token tok, ::std::vec if(pos.filename == "") pos = lex.getPosition(); ::std::cout << pos << ": Unexpected " << tok << ", expected "; - ::std::cout << exp << ")" << ::std::endl; + bool f = true; + for(auto v: exp) { + if(!f) + ::std::cout << " or "; + f = false; + ::std::cout << Token::typestr(v); + } + ::std::cout << ::std::endl; } ParseError::Unexpected::~Unexpected() throw() { diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp index f867e244..1b48dbb3 100644 --- a/src/parse/paths.cpp +++ b/src/parse/paths.cpp @@ -21,6 +21,8 @@ AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode) { case TOK_DOUBLE_COLON: return Parse_Path(lex, true, generic_mode); + case TOK_DOUBLE_LT: + lex.putback( Token(TOK_LT) ); case TOK_LT: { TypeRef ty = Parse_Type(lex); TypeRef trait; diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp index 32d1b017..4e4fa862 100644 --- a/src/parse/pattern.cpp +++ b/src/parse/pattern.cpp @@ -37,6 +37,11 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable) Token tok; tok = lex.getToken(); + if( tok.type() == TOK_MACRO ) + { + return AST::Pattern( AST::Pattern::TagMacro(), box$(Parse_MacroInvocation(AST::MetaItems(), tok.str(), lex))); + } + bool expect_bind = false; bool is_mut = false; bool is_ref = false; @@ -190,6 +195,8 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable) return AST::Pattern( AST::Pattern::TagValue(), NEWNODE( AST::ExprNode_Bool, false ) ); case TOK_STRING: return AST::Pattern( AST::Pattern::TagValue(), NEWNODE(AST::ExprNode_String, tok.str()) ); + case TOK_BYTESTRING: + return AST::Pattern( AST::Pattern::TagValue(), NEWNODE(AST::ExprNode_String, tok.str()) ); case TOK_PAREN_OPEN: return AST::Pattern(AST::Pattern::TagTuple(), Parse_PatternList(lex, is_refutable)); case TOK_SQUARE_OPEN: diff --git a/src/parse/root.cpp b/src/parse/root.cpp index fb7249e4..d9e47626 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -52,27 +52,26 @@ void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_ else if( tok.type() == TOK_QMARK ) { ret.add_bound(AST::GenericBound::make_MaybeTrait( {type: checked_type, trait: Parse_Path(lex, PATH_GENERIC_TYPE)} )); } - //else if( tok.type() == TOK_RWORD_FOR ) - //{ - // ::std::vector< ::std::string> lifetimes; - // GET_CHECK_TOK(tok, lex, TOK_LT); - // do { - // switch(GET_TOK(tok, lex)) - // { - // case TOK_LIFETIME: - // lifetimes.push_back(tok.str()); - // break; - // default: - // throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME)); - // } - // } while( GET_TOK(tok, lex) == TOK_COMMA ); - // CHECK_TOK(tok, TOK_GT); - // - // ret.add_bound( AST::GenericBound::make_IsTrait( {type: checked_type, hrls: lifetimes, trait: Parse_Path(lex, PATH_GENERIC_TYPE) }) ); - //} - else - { - lex.putback(tok); + else { + if( tok.type() == TOK_RWORD_FOR ) + { + GET_CHECK_TOK(tok, lex, TOK_LT); + do { + switch(GET_TOK(tok, lex)) + { + case TOK_LIFETIME: + lifetimes.push_back(tok.str()); + break; + default: + throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME)); + } + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_GT); + } + else { + lex.putback(tok); + } + ret.add_bound( AST::GenericBound::make_IsTrait( {type: checked_type, hrls: lifetimes, trait: Parse_Path(lex, PATH_GENERIC_TYPE) }) ); } } while( GET_TOK(tok, lex) == TOK_PLUS ); @@ -274,7 +273,16 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, AST::MetaIt GET_TOK(tok, lex); if( allow_self == false ) throw ParseError::Generic(lex, "Self binding not expected"); - args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef("Self")) ); + TypeRef ty; + if( GET_TOK(tok, lex) == TOK_COLON ) { + // Typed mut self + ty = Parse_Type(lex); + } + else { + lex.putback(tok); + ty = TypeRef("Self"); + } + args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), ty) ); GET_TOK(tok, lex); } } @@ -283,7 +291,16 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, AST::MetaIt // By-value method if( allow_self == false ) throw ParseError::Generic(lex, "Self binding not expected"); - args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef("Self")) ); + TypeRef ty; + if( GET_TOK(tok, lex) == TOK_COLON ) { + // Typed mut self + ty = Parse_Type(lex); + } + else { + lex.putback(tok); + ty = TypeRef("Self"); + } + args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), ty) ); GET_TOK(tok, lex); } else @@ -534,7 +551,35 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items) switch(tok.type()) { case TOK_RWORD_STATIC: { - throw ParseError::Todo("Associated static"); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + auto ty = Parse_Type(lex); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + + ::AST::Expr val; + if(GET_TOK(tok, lex) == TOK_EQUAL) { + val = Parse_Expr(lex, true); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_SEMICOLON); + + trait.add_static( mv$(name), ::AST::Static(mv$(item_attrs), AST::Static::STATIC, mv$(ty), val) ); + break; } + case TOK_RWORD_CONST: { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + auto ty = Parse_Type(lex); + + ::AST::Expr val; + if(GET_TOK(tok, lex) == TOK_EQUAL) { + val = Parse_Expr(lex, true); + GET_TOK(tok, lex); + } + CHECK_TOK(tok, TOK_SEMICOLON); + + trait.add_static( mv$(name), ::AST::Static(mv$(item_attrs), AST::Static::CONST, mv$(ty), val) ); break; } // Associated type case TOK_RWORD_TYPE: { @@ -631,6 +676,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems meta_items) ::std::vector variants; while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE ) { + auto sp = lex.start_span(); AST::MetaItems item_attrs; while( tok.type() == TOK_ATTR_OPEN ) { @@ -653,16 +699,26 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems meta_items) GET_TOK(tok, lex); variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(types)) ); } + else if( tok.type() == TOK_BRACE_OPEN ) + { + ::std::vector<::AST::StructItem> fields; + do + { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + auto name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + auto ty = Parse_Type(lex); + fields.push_back( ::AST::Item(mv$(name), mv$(ty), true) ); + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_BRACE_CLOSE); + GET_TOK(tok, lex); + + variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(fields)) ); + } else if( tok.type() == TOK_EQUAL ) { - bool is_neg = false; - if( GET_TOK(tok, lex) == TOK_DASH ) - is_neg = true; - else - lex.putback(tok); - GET_CHECK_TOK(tok, lex, TOK_INTEGER); - int64_t val = (is_neg ? -tok.intval() : tok.intval()); - variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), val) ); + auto node = Parse_Expr(lex, true); + variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(node)) ); GET_TOK(tok, lex); } else @@ -857,7 +913,16 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl) case TOK_RWORD_CONST: if( GET_TOK(tok, lex) != TOK_RWORD_FN && tok.type() != TOK_RWORD_UNSAFE ) { - BUG(lex.end_span(lex.start_span()), "TODO: Associated const"); + CHECK_TOK(tok, TOK_IDENT); + auto name = mv$(tok.str()); + GET_CHECK_TOK(tok, lex, TOK_COLON); + auto ty = Parse_Type(lex); + GET_CHECK_TOK(tok, lex, TOK_EQUAL); + auto val = Parse_Expr(lex, true); + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + + impl.add_static( is_public, mv$(name), ::AST::Static(mv$(item_attrs), AST::Static::CONST, mv$(ty), mv$(val)) ); + break ; } else if( tok.type() == TOK_RWORD_UNSAFE ) { @@ -934,9 +999,13 @@ void Parse_Use_Set(TokenStream& lex, const AST::Path& base_path, ::std::function Token tok; do { + if( GET_TOK(tok, lex) == TOK_RWORD_SELF ) { fcn(base_path, base_path[base_path.size()-1].name()); } + else if( tok.type() == TOK_BRACE_CLOSE ) { + break ; + } else { CHECK_TOK(tok, TOK_IDENT); fcn(base_path + AST::PathNode(tok.str(), {}), tok.str()); @@ -1024,6 +1093,7 @@ void Parse_Use(TokenStream& lex, ::std::function else { lex.putback(tok); + assert(path.nodes().size() > 0); name = path.nodes().back().name(); } @@ -1255,10 +1325,20 @@ void Parse_MacroRules(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_it GET_CHECK_TOK(tok, lex, TOK_IDENT); ::std::string name = tok.str(); - GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN); + eTokenType close; + switch(GET_TOK(tok,lex)) + { + case TOK_BRACE_OPEN: close = TOK_BRACE_CLOSE; break; + case TOK_PAREN_OPEN: close = TOK_PAREN_CLOSE; break; + case TOK_SQUARE_OPEN: close = TOK_SQUARE_CLOSE; break; + default: + // TODO: Synerror + throw ParseError::Unexpected(lex, tok, {TOK_BRACE_OPEN, TOK_PAREN_OPEN, TOK_SQUARE_OPEN}); + break; + } ::std::vector rules; - while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE ) + while( GET_TOK(tok, lex) != close ) { lex.putback(tok); @@ -1274,6 +1354,68 @@ void Parse_MacroRules(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_it mod.add_macro( is_pub, name, MacroRules(move(rules)) ); } +::AST::MacroInvocation Parse_MacroInvocation(::AST::MetaItems meta_items, ::std::string name, TokenStream& lex) +{ + Token tok; + ::std::string ident; + if( GET_TOK(tok, lex) == TOK_IDENT ) { + ident = mv$(tok.str()); + } + else { + lex.putback(tok); + } + TokenTree tt = Parse_TT(lex, true); + return ::AST::MacroInvocation( mv$(meta_items), mv$(name), mv$(ident), mv$(tt)); +} + +void Parse_ExternCrate(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items) +{ + Token tok; + ::std::string path, name; + switch( GET_TOK(tok, lex) ) + { + // `extern crate "crate-name" as crate_name;` + // TODO: rustc no longer supports this feature + case TOK_STRING: + path = tok.str(); + GET_CHECK_TOK(tok, lex, TOK_RWORD_AS); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = tok.str(); + break; + // `extern crate crate_name;` + case TOK_IDENT: + name = tok.str(); + if(GET_TOK(tok, lex) == TOK_RWORD_AS) { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = mv$(tok.str()); + } + else { + lex.putback(tok); + name = path; + } + break; + default: + throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_IDENT}); + } + GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); + + mod.add_ext_crate(path, name); + + // Handle #[macro_use]/#[macro_use(...)] + //auto at = meta_items.get("macro_use"); + //if( at ) + //{ + // if( at->has_sub_items() ) + // { + // throw ParseError::Todo("selective macro_use"); + // } + // else + // { + // mod.add_macro_import(crate, name, ""); + // } + //} +} + void Parse_ModRoot_Items(TokenStream& lex, AST::Crate& crate, AST::Module& mod, LList& modstack, const ::std::string& path) { //TRACE_FUNCTION; @@ -1309,22 +1451,14 @@ void Parse_ModRoot_Items(TokenStream& lex, AST::Crate& crate, AST::Module& mod, { ::std::string name = mv$(tok.str()); // `macro_rules! ...` - if( name == "macro_rules" ) - { - Parse_MacroRules(lex, mod, mv$(meta_items)); - } - else - { - ::std::string ident; - if( GET_TOK(tok, lex) == TOK_IDENT ) { - ident = mv$(tok.str()); - } - else { - lex.putback(tok); - } - TokenTree tt = Parse_TT(lex, true); - mod.add_macro_invocation( ::AST::MacroItem( mv$(meta_items), mv$(name), mv$(ident), mv$(tt)) ); - } + //if( name == "macro_rules" ) + //{ + // Parse_MacroRules(lex, mod, mv$(meta_items)); + //} + //else + //{ + mod.add_macro_invocation( Parse_MacroInvocation( mv$(meta_items), mv$(name), lex ) ); + //} // - Silently consume ';' after the macro if( GET_TOK(tok, lex) != TOK_SEMICOLON ) lex.putback(tok); @@ -1387,44 +1521,9 @@ void Parse_ModRoot_Items(TokenStream& lex, AST::Crate& crate, AST::Module& mod, break; // `extern crate "crate-name" as crate_name;` // `extern crate crate_name;` - case TOK_RWORD_CRATE: { - ::std::string path, name; - switch( GET_TOK(tok, lex) ) - { - // `extern crate "crate-name" as crate_name;` - // TODO: rustc no longer supports this feature - case TOK_STRING: - path = tok.str(); - GET_CHECK_TOK(tok, lex, TOK_RWORD_AS); - GET_CHECK_TOK(tok, lex, TOK_IDENT); - name = tok.str(); - break; - // `extern crate crate_name;` - case TOK_IDENT: - path = name = tok.str(); - break; - default: - throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_IDENT}); - } - crate.load_extern_crate(path); - mod.add_ext_crate(path, name); - - // Handle #[macro_use]/#[macro_use(...)] - auto at = meta_items.get("macro_use"); - if( at ) - { - if( at->has_sub_items() ) - { - throw ParseError::Todo("selective macro_use"); - } - else - { - mod.add_macro_import(crate, name, ""); - } - } - - GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); - break; } + case TOK_RWORD_CRATE: + Parse_ExternCrate(lex, mod, mv$(meta_items)); + break; default: throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_RWORD_FN, TOK_BRACE_OPEN, TOK_RWORD_CRATE}); } @@ -1487,6 +1586,19 @@ void Parse_ModRoot_Items(TokenStream& lex, AST::Crate& crate, AST::Module& mod, meta_items.push_back( AST::MetaItem("#UNSAFE") ); switch(GET_TOK(tok, lex)) { + // `unsafe extern fn` + case TOK_RWORD_EXTERN: { + ::std::string abi = "C"; + if(GET_TOK(tok, lex) == TOK_STRING) { + abi = mv$(tok.str()); + } + else { + lex.putback(tok); + } + GET_CHECK_TOK(tok, lex, TOK_RWORD_FN); + GET_CHECK_TOK(tok, lex, TOK_IDENT); + mod.add_function(is_public, tok.str(), Parse_FunctionDefWithCode(lex, abi, ::std::move(meta_items), false)); + break; } // `unsafe fn` case TOK_RWORD_FN: GET_CHECK_TOK(tok, lex, TOK_IDENT); @@ -1498,6 +1610,7 @@ void Parse_ModRoot_Items(TokenStream& lex, AST::Crate& crate, AST::Module& mod, case TOK_RWORD_TRAIT: { GET_CHECK_TOK(tok, lex, TOK_IDENT); ::std::string name = tok.str(); + // TODO: Mark as unsafe mod.add_trait(is_public, name, Parse_TraitDef(lex, meta_items)); break; } // `unsafe impl` diff --git a/src/parse/types.cpp b/src/parse/types.cpp index 532cccae..425a7f36 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -14,6 +14,7 @@ TypeRef Parse_Type(TokenStream& lex); TypeRef Parse_Type_Int(TokenStream& lex); TypeRef Parse_Type_Fn(TokenStream& lex); +TypeRef Parse_Type_Path(TokenStream& lex, ::std::vector<::std::string> hrls); // === CODE === TypeRef Parse_Type(TokenStream& lex) @@ -52,8 +53,26 @@ TypeRef Parse_Type_Int(TokenStream& lex) return Parse_Type_Fn(lex); // '<' - An associated type cast case TOK_LT: + case TOK_DOUBLE_LT: lex.putback(tok); return TypeRef(TypeRef::TagPath(), Parse_Path(lex, PATH_GENERIC_TYPE)); + // + case TOK_RWORD_FOR: { + GET_CHECK_TOK(tok, lex, TOK_LT); + ::std::vector<::std::string> hrls; + do { + GET_CHECK_TOK(tok, lex, TOK_LIFETIME); + hrls.push_back( mv$(tok.str()) ); + } while( GET_TOK(tok, lex) == TOK_COMMA ); + CHECK_TOK(tok, TOK_GT); + if( LOOK_AHEAD(lex) == TOK_RWORD_FN || LOOK_AHEAD(lex) == TOK_RWORD_EXTERN ) { + // TODO: Handle HRLS in fn types + return Parse_Type_Fn(lex); + } + else { + return Parse_Type_Path(lex, hrls); + } + } // - Either a primitive, or a path case TOK_IDENT: // or a primitive @@ -65,33 +84,17 @@ TypeRef Parse_Type_Int(TokenStream& lex) { return TypeRef(TypeRef::TagPath(), AST::Path("", { AST::PathNode("#",{}), AST::PathNode("str",{}) })); } + lex.putback(tok); + return Parse_Type_Path(lex, {}); // - Fall through to path handling // '::' - Absolute path - case TOK_DOUBLE_COLON: { + case TOK_DOUBLE_COLON: lex.putback(tok); - ::std::vector traits; - ::std::vector< ::std::string> lifetimes; - do { - if( LOOK_AHEAD(lex) == TOK_LIFETIME ) { - GET_TOK(tok, lex); - lifetimes.push_back( tok.str() ); - } - else - traits.push_back( Parse_Path(lex, PATH_GENERIC_TYPE) ); - } while( GET_TOK(tok, lex) == TOK_PLUS ); - lex.putback(tok); - if( traits.size() > 1 || lifetimes.size() > 0 ) { - if( lifetimes.size() ) - DEBUG("TODO: Lifetime bounds on trait objects"); - return TypeRef(::std::move(traits)); - } - else - return TypeRef(TypeRef::TagPath(), traits.at(0)); - } + return Parse_Type_Path(lex, {}); // 'super' - Parent relative path case TOK_RWORD_SUPER: - GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON); - return TypeRef(TypeRef::TagPath(), AST::Path(AST::Path::TagSuper(), Parse_PathNodes(lex, PATH_GENERIC_TYPE))); + lex.putback(tok); + return Parse_Type_Path(lex, {}); // HACK! Convert && into & & case TOK_DOUBLE_AMP: @@ -206,9 +209,13 @@ TypeRef Parse_Type_Fn(TokenStream& lex) } if( tok.type() == TOK_RWORD_EXTERN ) { - GET_CHECK_TOK(tok, lex, TOK_STRING); - abi = tok.str(); - GET_TOK(tok, lex); + if( GET_TOK(tok, lex) == TOK_STRING ) { + abi = tok.str(); + GET_TOK(tok, lex); + } + else { + abi = "C"; + } } CHECK_TOK(tok, TOK_RWORD_FN); @@ -236,3 +243,28 @@ TypeRef Parse_Type_Fn(TokenStream& lex) return TypeRef(TypeRef::TagFunction(), ::std::move(abi), ::std::move(args), ::std::move(ret_type)); } +TypeRef Parse_Type_Path(TokenStream& lex, ::std::vector<::std::string> hrls) +{ + Token tok; + + ::std::vector traits; + ::std::vector< ::std::string> lifetimes; + do { + if( LOOK_AHEAD(lex) == TOK_LIFETIME ) { + GET_TOK(tok, lex); + lifetimes.push_back( tok.str() ); + } + else + traits.push_back( Parse_Path(lex, PATH_GENERIC_TYPE) ); + } while( GET_TOK(tok, lex) == TOK_PLUS ); + lex.putback(tok); + if( hrls.size() > 0 || traits.size() > 1 || lifetimes.size() > 0 ) { + if( lifetimes.size() ) + DEBUG("TODO: Lifetime bounds on trait objects"); + return TypeRef(mv$(hrls), ::std::move(traits)); + } + else { + return TypeRef(TypeRef::TagPath(), traits.at(0)); + } +} + diff --git a/src/types.hpp b/src/types.hpp index 7484d522..0cb8ba9a 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -90,6 +90,7 @@ TAGGED_UNION(TypeData, None, AST::Path path; )), (TraitObject, ( + ::std::vector<::std::string> hrls; ::std::vector traits; )) ); @@ -200,8 +201,8 @@ public: TypeRef(TagPath(), ::std::move(path)) {} - TypeRef( ::std::vector traits ): - m_data(TypeData::make_TraitObject({ ::std::move(traits) })) + TypeRef( ::std::vector<::std::string> hrls, ::std::vector traits ): + m_data(TypeData::make_TraitObject({ mv$(hrls), ::std::move(traits) })) {} -- cgit v1.2.3