summaryrefslogtreecommitdiff
path: root/src/parse
diff options
context:
space:
mode:
Diffstat (limited to 'src/parse')
-rw-r--r--src/parse/common.hpp140
-rw-r--r--src/parse/expr.cpp2602
-rw-r--r--src/parse/interpolated_fragment.hpp12
-rw-r--r--src/parse/lex.cpp40
-rw-r--r--src/parse/lex.hpp4
-rw-r--r--src/parse/parseerror.cpp182
-rw-r--r--src/parse/parseerror.hpp80
-rw-r--r--src/parse/paths.cpp28
-rw-r--r--src/parse/pattern.cpp68
-rw-r--r--src/parse/root.cpp3758
-rw-r--r--src/parse/token.cpp12
-rw-r--r--src/parse/token.hpp18
-rw-r--r--src/parse/tokenstream.cpp8
-rw-r--r--src/parse/tokenstream.hpp18
-rw-r--r--src/parse/tokentree.hpp122
-rw-r--r--src/parse/ttstream.hpp4
-rw-r--r--src/parse/types.cpp30
17 files changed, 3563 insertions, 3563 deletions
diff --git a/src/parse/common.hpp b/src/parse/common.hpp
index 57d6f24d..613290f2 100644
--- a/src/parse/common.hpp
+++ b/src/parse/common.hpp
@@ -1,70 +1,70 @@
-/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * parse/common.hpp
- * - Common definitions used by the parser
- */
-#ifndef PARSE_COMMON_HPP_INCLUDED
-#define PARSE_COMMON_HPP_INCLUDED
-#include <iostream>
-#include "tokenstream.hpp"
-#include "../ast/ast.hpp"
-
-#define GET_TOK(tok, lex) ((tok = lex.getToken()).type())
-#define PUTBACK(tok, lex) lex.putback( ::std::move(tok) )
-#define LOOK_AHEAD(lex) (lex.lookahead(0))
-#define GET_CHECK_TOK(tok, lex, exp) do {\
- if((tok = lex.getToken()).type() != exp) { \
- DEBUG("GET_CHECK_TOK " << __FILE__ << ":" << __LINE__); \
- throw ParseError::Unexpected(lex, tok, Token(exp));\
- }\
-} while(0)
-#define CHECK_TOK(tok, exp) do {\
- if(tok.type() != exp) { \
- DEBUG("CHECK_TOK " << __FILE__ << ":" << __LINE__); \
- throw ParseError::Unexpected(lex, tok, Token(exp));\
- } \
-} while(0)
-
-// --- path.cpp
-enum eParsePathGenericMode
-{
- PATH_GENERIC_NONE,
- PATH_GENERIC_EXPR,
- PATH_GENERIC_TYPE
-};
-extern AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode); // Auto-determines
-extern AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generic_mode);
-extern ::std::vector<AST::PathNode> Parse_PathNodes(TokenStream& lex, eParsePathGenericMode generic_mode);
-extern AST::PathParams Parse_Path_GenericList(TokenStream& lex);
-
-
-extern ::std::vector< ::std::string> Parse_HRB(TokenStream& lex);
-extern AST::MetaItem Parse_MetaItem(TokenStream& lex);
-extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, ::std::string name, TokenStream& lex);
-extern TypeRef Parse_Type(TokenStream& lex, bool allow_trait_list = true);
-extern AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable);
-
-extern void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl);
-extern void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items);
-extern ::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::MetaItems meta_items);
-extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod);
-
-
-extern AST::Expr Parse_Expr(TokenStream& lex);
-extern AST::Expr Parse_ExprBlock(TokenStream& lex);
-extern AST::ExprNodeP Parse_Expr0(TokenStream& lex);
-extern AST::ExprNodeP Parse_ExprVal(TokenStream& lex);
-extern AST::ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false);
-extern AST::ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence);
-extern AST::ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end);
-extern AST::ExprNodeP Parse_Stmt(TokenStream& lex);
-
-// unwrapped = Exclude the enclosing brackets (used by macro parse code)
-extern TokenTree Parse_TT(TokenStream& lex, bool unwrapped);
-
-
-extern bool Parse_IsTokValue(eTokenType tok_type);
-
-#endif // PARSE_COMMON_HPP_INCLUDED
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * parse/common.hpp
+ * - Common definitions used by the parser
+ */
+#ifndef PARSE_COMMON_HPP_INCLUDED
+#define PARSE_COMMON_HPP_INCLUDED
+#include <iostream>
+#include "tokenstream.hpp"
+#include "../ast/ast.hpp"
+
+#define GET_TOK(tok, lex) ((tok = lex.getToken()).type())
+#define PUTBACK(tok, lex) lex.putback( ::std::move(tok) )
+#define LOOK_AHEAD(lex) (lex.lookahead(0))
+#define GET_CHECK_TOK(tok, lex, exp) do {\
+ if((tok = lex.getToken()).type() != exp) { \
+ DEBUG("GET_CHECK_TOK " << __FILE__ << ":" << __LINE__); \
+ throw ParseError::Unexpected(lex, tok, Token(exp));\
+ }\
+} while(0)
+#define CHECK_TOK(tok, exp) do {\
+ if(tok.type() != exp) { \
+ DEBUG("CHECK_TOK " << __FILE__ << ":" << __LINE__); \
+ throw ParseError::Unexpected(lex, tok, Token(exp));\
+ } \
+} while(0)
+
+// --- path.cpp
+enum eParsePathGenericMode
+{
+ PATH_GENERIC_NONE,
+ PATH_GENERIC_EXPR,
+ PATH_GENERIC_TYPE
+};
+extern AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode); // Auto-determines
+extern AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generic_mode);
+extern ::std::vector<AST::PathNode> Parse_PathNodes(TokenStream& lex, eParsePathGenericMode generic_mode);
+extern AST::PathParams Parse_Path_GenericList(TokenStream& lex);
+
+
+extern ::std::vector< ::std::string> Parse_HRB(TokenStream& lex);
+extern AST::MetaItem Parse_MetaItem(TokenStream& lex);
+extern ::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan ps, ::std::string name, TokenStream& lex);
+extern TypeRef Parse_Type(TokenStream& lex, bool allow_trait_list = true);
+extern AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable);
+
+extern void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl);
+extern void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items);
+extern ::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::MetaItems meta_items);
+extern void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod);
+
+
+extern AST::Expr Parse_Expr(TokenStream& lex);
+extern AST::Expr Parse_ExprBlock(TokenStream& lex);
+extern AST::ExprNodeP Parse_Expr0(TokenStream& lex);
+extern AST::ExprNodeP Parse_ExprVal(TokenStream& lex);
+extern AST::ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false);
+extern AST::ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence);
+extern AST::ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end);
+extern AST::ExprNodeP Parse_Stmt(TokenStream& lex);
+
+// unwrapped = Exclude the enclosing brackets (used by macro parse code)
+extern TokenTree Parse_TT(TokenStream& lex, bool unwrapped);
+
+
+extern bool Parse_IsTokValue(eTokenType tok_type);
+
+#endif // PARSE_COMMON_HPP_INCLUDED
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index c71d2b4a..eb82bae7 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -1,1301 +1,1301 @@
-/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * parse/expr.cpp
- * - Expression (i.e. code) parsing
- *
- * Start points:
- * - Parse_ExprBlockNode : Parses a block
- * - Parse_Stmt : Parse a single statement
- * - Parse_Expr0 : Parse a single expression
- */
-#include "parseerror.hpp"
-#include <ast/ast.hpp>
-#include <ast/expr.hpp>
-#include "common.hpp"
-#include <iostream>
-#include "tokentree.hpp"
-#include "interpolated_fragment.hpp"
-
-using AST::ExprNode;
-using AST::ExprNodeP;
-static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){en->set_pos(lex.getPosition()); return ExprNodeP(en); }
-#define NEWNODE(type, ...) mk_exprnodep(lex, new type(__VA_ARGS__))
-
-//ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false); // common.hpp
-//ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end);
-//ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence);
-ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon);
-//ExprNodeP Parse_Stmt(TokenStream& lex); // common.hpp
-ExprNodeP Parse_Stmt_Let(TokenStream& lex);
-ExprNodeP Parse_Expr0(TokenStream& lex);
-ExprNodeP Parse_IfStmt(TokenStream& lex);
-ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime);
-ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime);
-ExprNodeP Parse_Expr_Match(TokenStream& lex);
-ExprNodeP Parse_Expr1(TokenStream& lex);
-ExprNodeP Parse_ExprMacro(TokenStream& lex, Token tok);
-
-AST::Expr Parse_Expr(TokenStream& lex)
-{
- return ::AST::Expr( Parse_Expr0(lex) );
-}
-
-AST::Expr Parse_ExprBlock(TokenStream& lex)
-{
- return ::AST::Expr( Parse_ExprBlockNode(lex) );
-}
-
-ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe/*=false*/)
-{
- TRACE_FUNCTION;
- Token tok;
-
- bool yields_final_value = true;
- ::std::vector<ExprNodeP> nodes;
-
- ::std::shared_ptr<AST::Module> local_mod;
-
- GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
-
- while( LOOK_AHEAD(lex) != TOK_BRACE_CLOSE )
- {
- DEBUG("tok = " << tok);
-
- // NOTE: Doc comments can appear within a function and apply to the function
- // TODO: Use these attributes
- while( GET_TOK(tok, lex) == TOK_CATTR_OPEN )
- {
- /*node_attrs.push_back(*/ Parse_MetaItem(lex) /*)*/;
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
- PUTBACK(tok, lex);
- if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE )
- break;
-
- bool add_silence_if_end = false;
- auto rv = Parse_ExprBlockLine_WithItems(lex, local_mod, add_silence_if_end);
- if( rv )
- {
- // Set to TRUE if there was no semicolon after a statement
- if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE && add_silence_if_end )
- {
- DEBUG("End of block, and add_silence_if_end == true - doesn't yeild");
- yields_final_value = false;
- // Since the next token is TOK_BRACE_CLOSE, the loop will terminate
- }
- nodes.push_back( mv$(rv) );
- }
- else {
- assert( !add_silence_if_end );
- }
- }
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
-
- return NEWNODE( AST::ExprNode_Block, is_unsafe, yields_final_value, mv$(nodes), mv$(local_mod) );
-}
-
-/// Parse a single line in a block, handling items added to the local module
-///
-/// - If an item was parsed, this returns an empty ExprNodeP
-ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end)
-{
- Token tok;
-
- AST::MetaItems item_attrs;
- while( GET_TOK(tok, lex) == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- switch(tok.type())
- {
- // Items:
- case TOK_RWORD_PUB:
- // NOTE: Allowed, but doesn't do much
- case TOK_RWORD_TYPE:
- case TOK_RWORD_USE:
- case TOK_RWORD_EXTERN:
- case TOK_RWORD_CONST:
- case TOK_RWORD_STATIC:
- case TOK_RWORD_STRUCT:
- case TOK_RWORD_ENUM:
- case TOK_RWORD_TRAIT:
- case TOK_RWORD_IMPL:
- case TOK_RWORD_FN:
- case TOK_RWORD_MOD:
- PUTBACK(tok, lex);
- if( !local_mod ) {
- local_mod = lex.parse_state().get_current_mod().add_anon();
- }
- Parse_Mod_Item(lex, *local_mod, mv$(item_attrs));
- return ExprNodeP();
- // 'unsafe' - Check if the next token isn't a `{`, if so it's an item. Otherwise, fall through
- case TOK_RWORD_UNSAFE:
- if( LOOK_AHEAD(lex) != TOK_BRACE_OPEN )
- {
- PUTBACK(tok, lex);
- if( !local_mod ) {
- local_mod = lex.parse_state().get_current_mod().add_anon();
- }
- Parse_Mod_Item(lex, *local_mod, mv$(item_attrs));
- return ExprNodeP();
- }
- // fall
- default: {
- PUTBACK(tok, lex);
- auto rv = Parse_ExprBlockLine(lex, &add_silence_if_end);
- if( rv ) {
- rv->set_attrs( mv$(item_attrs) );
- }
- else if( item_attrs.m_items.size() > 0 ) {
- // TODO: Is this an error? - Attributes on a expression that didn't yeild a node.
- }
- else {
- }
- return rv;
- } break;
- }
-}
-
-/// Parse a single line from a block
-///
-/// Handles:
-/// - Block-level constructs (with lifetime annotations)
-/// - use/extern/const/let
-ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence)
-{
- Token tok;
- ExprNodeP ret;
-
- if( GET_TOK(tok, lex) == TOK_LIFETIME )
- {
- // Lifetimes can only precede loops... and blocks?
- ::std::string lifetime = tok.str();
- GET_CHECK_TOK(tok, lex, TOK_COLON);
-
- switch( GET_TOK(tok, lex) )
- {
- case TOK_RWORD_LOOP:
- return NEWNODE( AST::ExprNode_Loop, lifetime, Parse_ExprBlockNode(lex) );
- case TOK_RWORD_WHILE:
- return Parse_WhileStmt(lex, lifetime);
- case TOK_RWORD_FOR:
- return Parse_ForStmt(lex, lifetime);
- //case TOK_RWORD_IF:
- // return Parse_IfStmt(lex);
- //case TOK_RWORD_MATCH:
- // return Parse_Expr_Match(lex);
- //case TOK_BRACE_OPEN:
- // PUTBACK(tok, lex);
- // return Parse_ExprBlockNode(lex);
-
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- }
- else
- {
- switch( tok.type() )
- {
- case TOK_INTERPOLATED_BLOCK:
- return tok.take_frag_node();
- case TOK_SEMICOLON:
- // Return a NULL expression, nothing here.
- return nullptr;
-
- // let binding
- case TOK_RWORD_LET:
- ret = Parse_Stmt_Let(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- return ret;
-
- // Blocks that don't need semicolons
- // NOTE: If these are followed by a small set of tokens (`.` and `?`) then they are actually the start of an expression
- // HACK: Parse here, but if the next token is one of the set store in a TOK_INTERPOLATED_EXPR and invoke the statement parser
- case TOK_RWORD_LOOP:
- ret = NEWNODE( AST::ExprNode_Loop, "", Parse_ExprBlockNode(lex) );
- if(0)
- case TOK_RWORD_WHILE:
- ret = Parse_WhileStmt(lex, "");
- if(0)
- case TOK_RWORD_FOR:
- ret = Parse_ForStmt(lex, "");
- if(0)
- case TOK_RWORD_IF:
- ret = Parse_IfStmt(lex);
- if(0)
- case TOK_RWORD_MATCH:
- ret = Parse_Expr_Match(lex);
- if(0)
- case TOK_RWORD_UNSAFE:
- ret = Parse_ExprBlockNode(lex, true);
- if(0)
- case TOK_BRACE_OPEN:
- { PUTBACK(tok, lex); ret = Parse_ExprBlockNode(lex); }
-
- if( lex.lookahead(0) == TOK_DOT || lex.lookahead(0) == TOK_QMARK ) {
- lex.putback( Token(Token::TagTakeIP(), InterpolatedFragment(InterpolatedFragment::EXPR, ret.release())) );
- return Parse_ExprBlockLine_Stmt(lex, *add_silence);
- }
-
- if( LOOK_AHEAD(lex) == TOK_SEMICOLON ) {
- GET_TOK(tok, lex);
- *add_silence = true;
- }
-
- return ret;
-
- // Flow control
- case TOK_RWORD_RETURN:
- case TOK_RWORD_CONTINUE:
- case TOK_RWORD_BREAK: {
- PUTBACK(tok, lex);
- auto ret = Parse_Stmt(lex);
- if( LOOK_AHEAD(lex) == TOK_EOF ) {
- }
- else if( GET_TOK(tok, lex) != TOK_SEMICOLON ) {
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
- PUTBACK(tok, lex);
- }
- else {
- // return/continue/break don't need silencing
- }
- return ret;
- }
-
- case TOK_MACRO:
- // If a braced macro invocation is the first part of a statement, don't expect a semicolon
- if( LOOK_AHEAD(lex) == TOK_BRACE_OPEN || (lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_BRACE_OPEN) ) {
- return Parse_ExprMacro(lex, tok);
- }
- // Fall through to the statement code
- default:
- PUTBACK(tok, lex);
- return Parse_ExprBlockLine_Stmt(lex, *add_silence);
- }
- }
-}
-
-ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon)
-{
- Token tok;
- auto ret = Parse_Stmt(lex);
- // If this expression statement wasn't followed by a semicolon, then it's yielding its value out of the block.
- // - I.e. The block should be ending
- if( GET_TOK(tok, lex) != TOK_SEMICOLON ) {
- // - Allow TOK_EOF for macro expansion.
- if( tok.type() == TOK_EOF )
- ;
- else
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
- PUTBACK(tok, lex);
- }
- else {
- has_semicolon = true;
- }
- return ret;
-}
-
-/// While loop (either as a statement, or as part of an expression)
-ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime)
-{
- Token tok;
-
- if( GET_TOK(tok, lex) == TOK_RWORD_LET ) {
- auto pat = Parse_Pattern(lex, true); // Refutable pattern
- GET_CHECK_TOK(tok, lex, TOK_EQUAL);
- ExprNodeP val;
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- val = Parse_Expr0(lex);
- }
- return NEWNODE( AST::ExprNode_Loop, lifetime, AST::ExprNode_Loop::WHILELET,
- ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) );
- }
- else {
- PUTBACK(tok, lex);
- ExprNodeP cnd;
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- cnd = Parse_Expr1(lex);
- }
- return NEWNODE( AST::ExprNode_Loop, lifetime, ::std::move(cnd), Parse_ExprBlockNode(lex) );
- }
-}
-/// For loop (either as a statement, or as part of an expression)
-ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime)
-{
- Token tok;
-
- // Irrefutable pattern
- AST::Pattern pat = Parse_Pattern(lex, false);
- GET_CHECK_TOK(tok, lex, TOK_RWORD_IN);
- ExprNodeP val;
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- val = Parse_Expr0(lex);
- }
- return NEWNODE( AST::ExprNode_Loop, lifetime, AST::ExprNode_Loop::FOR,
- ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) );
-}
-/// Parse an 'if' statement
-// Note: TOK_RWORD_IF has already been eaten
-ExprNodeP Parse_IfStmt(TokenStream& lex)
-{
- TRACE_FUNCTION;
-
- Token tok;
- ExprNodeP cond;
- AST::Pattern pat;
- bool if_let = false;
-
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- if( GET_TOK(tok, lex) == TOK_RWORD_LET ) {
- if_let = true;
- // Refutable pattern
- pat = Parse_Pattern(lex, true);
- GET_CHECK_TOK(tok, lex, TOK_EQUAL);
- cond = Parse_Expr0(lex);
- }
- else {
- PUTBACK(tok, lex);
- cond = Parse_Expr0(lex);
- }
- }
-
- // Contents
- ExprNodeP code = Parse_ExprBlockNode(lex);
-
- // Handle else:
- ExprNodeP altcode;
- if( GET_TOK(tok, lex) == TOK_RWORD_ELSE )
- {
- // Recurse for 'else if'
- if( GET_TOK(tok, lex) == TOK_RWORD_IF ) {
- altcode = Parse_IfStmt(lex);
- }
- // - or get block
- else {
- PUTBACK(tok, lex);
- altcode = Parse_ExprBlockNode(lex);
- }
- }
- // - or nothing
- else {
- PUTBACK(tok, lex);
- }
-
- if( if_let )
- return NEWNODE( AST::ExprNode_IfLet, ::std::move(pat), ::std::move(cond), ::std::move(code), ::std::move(altcode) );
- else
- return NEWNODE( AST::ExprNode_If, ::std::move(cond), ::std::move(code), ::std::move(altcode) );
-}
-/// "match" block
-ExprNodeP Parse_Expr_Match(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
-
- CLEAR_PARSE_FLAG(lex, disallow_struct_literal);
- // 1. Get expression
- ExprNodeP switch_val;
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- switch_val = Parse_Expr1(lex);
- }
- //ASSERT(lex, !CHECK_PARSE_FLAG(lex, disallow_struct_literal) );
- GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
-
- ::std::vector< AST::ExprNode_Match_Arm > arms;
- do {
- if( GET_TOK(tok, lex) == TOK_BRACE_CLOSE )
- break;
- PUTBACK(tok, lex);
- AST::ExprNode_Match_Arm arm;
-
- ::AST::MetaItems arm_attrs;
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN ) {
- GET_TOK(tok, lex);
- arm_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
- arm.m_attrs = mv$(arm_attrs);
-
- do {
- // Refutable pattern
- arm.m_patterns.push_back( Parse_Pattern(lex, true) );
- } while( GET_TOK(tok, lex) == TOK_PIPE );
-
- if( tok.type() == TOK_RWORD_IF )
- {
- arm.m_cond = Parse_Expr1(lex);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_FATARROW);
-
- arm.m_code = Parse_Stmt(lex);
-
- arms.push_back( ::std::move(arm) );
-
- if( GET_TOK(tok, lex) == TOK_COMMA )
- continue;
- PUTBACK(tok, lex);
-
- } while( 1 );
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
- return NEWNODE( AST::ExprNode_Match, ::std::move(switch_val), ::std::move(arms) );
-}
-
-/// Parses the 'stmt' fragment specifier
-/// - Flow control
-/// - Expressions
-ExprNodeP Parse_Stmt(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
-
- switch(GET_TOK(tok, lex))
- {
- case TOK_INTERPOLATED_STMT:
- return tok.take_frag_node();
- // Duplicated here for the :stmt pattern fragment.
- case TOK_RWORD_LET:
- return Parse_Stmt_Let(lex);
- case TOK_RWORD_RETURN: {
- ExprNodeP val;
- 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_Expr0(lex);
- break;
- }
- return NEWNODE( AST::ExprNode_Flow, AST::ExprNode_Flow::RETURN, "", ::std::move(val) );
- }
- case TOK_RWORD_CONTINUE:
- case TOK_RWORD_BREAK:
- {
- AST::ExprNode_Flow::Type type;
- switch(tok.type())
- {
- case TOK_RWORD_CONTINUE: type = AST::ExprNode_Flow::CONTINUE; break;
- case TOK_RWORD_BREAK: type = AST::ExprNode_Flow::BREAK; break;
- default: throw ParseError::BugCheck(/*lex,*/ "continue/break");
- }
- ::std::string lifetime;
- if( GET_TOK(tok, lex) == TOK_LIFETIME )
- {
- lifetime = tok.str();
- GET_TOK(tok, lex);
- }
- ExprNodeP val;
- switch(tok.type())
- {
- case TOK_SEMICOLON:
- case TOK_COMMA:
- case TOK_BRACE_OPEN:
- case TOK_BRACE_CLOSE:
- case TOK_PAREN_CLOSE:
- case TOK_SQUARE_CLOSE:
- PUTBACK(tok, lex);
- break;
- default:
- PUTBACK(tok, lex);
- val = Parse_Expr1(lex);
- break;
- }
- return NEWNODE( AST::ExprNode_Flow, type, lifetime, ::std::move(val) );
- }
- case TOK_BRACE_OPEN:
- PUTBACK(tok, lex);
- return Parse_ExprBlockNode(lex);
- default:
- PUTBACK(tok, lex);
- return Parse_Expr0(lex);
- }
-}
-
-ExprNodeP Parse_Stmt_Let(TokenStream& lex)
-{
- Token tok;
- AST::Pattern pat = Parse_Pattern(lex, false); // irrefutable
- TypeRef type { lex.getPosition() };
- if( GET_TOK(tok, lex) == TOK_COLON ) {
- type = Parse_Type(lex);
- GET_TOK(tok, lex);
- }
- ExprNodeP val;
- if( tok.type() == TOK_EQUAL ) {
- val = Parse_Expr0(lex);
- }
- else {
- PUTBACK(tok, lex);
- }
- return NEWNODE( AST::ExprNode_LetBinding, ::std::move(pat), mv$(type), ::std::move(val) );
-}
-
-::std::vector<ExprNodeP> Parse_ParenList(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
-
- CLEAR_PARSE_FLAG(lex, disallow_struct_literal);
-
- ::std::vector<ExprNodeP> rv;
- GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
- if( GET_TOK(tok, lex) != TOK_PAREN_CLOSE )
- {
- PUTBACK(tok, lex);
- do {
- if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) {
- GET_TOK(tok, lex);
- break;
- }
- rv.push_back( Parse_Expr0(lex) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
- }
- return rv;
-}
-
-// 0: Assign
-ExprNodeP Parse_Expr0(TokenStream& lex)
-{
- //TRACE_FUNCTION;
- Token tok;
-
- ::AST::MetaItems expr_attrs;
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
- {
- GET_TOK(tok, lex);
- expr_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- ExprNodeP rv = Parse_Expr1(lex);
- auto op = AST::ExprNode_Assign::NONE;
- switch( GET_TOK(tok, lex) )
- {
- case TOK_PLUS_EQUAL:
- op = AST::ExprNode_Assign::ADD; if(0)
- case TOK_DASH_EQUAL:
- op = AST::ExprNode_Assign::SUB; if(0)
- case TOK_STAR_EQUAL:
- op = AST::ExprNode_Assign::MUL; if(0)
- case TOK_SLASH_EQUAL:
- op = AST::ExprNode_Assign::DIV; if(0)
- case TOK_PERCENT_EQUAL:
- op = AST::ExprNode_Assign::MOD; if(0)
-
- case TOK_AMP_EQUAL:
- op = AST::ExprNode_Assign::AND; if(0)
- case TOK_PIPE_EQUAL:
- op = AST::ExprNode_Assign::OR ; if(0)
- case TOK_CARET_EQUAL:
- op = AST::ExprNode_Assign::XOR; if(0)
-
- case TOK_DOUBLE_GT_EQUAL:
- op = AST::ExprNode_Assign::SHR; if(0)
- case TOK_DOUBLE_LT_EQUAL:
- op = AST::ExprNode_Assign::SHL; if(0)
-
- case TOK_EQUAL:
- op = AST::ExprNode_Assign::NONE;
- rv = NEWNODE( AST::ExprNode_Assign, op, ::std::move(rv), Parse_Expr0(lex) );
- rv->set_attrs(mv$(expr_attrs));
- return rv;
-
- default:
- PUTBACK(tok, lex);
- rv->set_attrs(mv$(expr_attrs));
- return rv;
- }
-}
-
-
-#define LEFTASSOC(cur, _next, cases) \
-ExprNodeP _next(TokenStream& lex); \
-ExprNodeP cur(TokenStream& lex) \
-{ \
- ExprNodeP (*next)(TokenStream&) = _next;\
- ExprNodeP rv = next(lex); \
- while(true) \
- { \
- Token tok; \
- switch((tok = lex.getToken()).type()) \
- { \
- cases \
- default: \
- /*::std::cout << "<<" << #cur << ::std::endl; */\
- PUTBACK(tok, lex); \
- return rv; \
- } \
- } \
-}
-bool Parse_IsTokValue(eTokenType tok_type)
-{
- switch( tok_type )
- {
- case TOK_DOUBLE_COLON:
- case TOK_IDENT:
- case TOK_INTEGER:
- case TOK_FLOAT:
- case TOK_STRING:
- case TOK_RWORD_TRUE:
- case TOK_RWORD_FALSE:
- case TOK_RWORD_SELF:
- case TOK_RWORD_SUPER:
- case TOK_RWORD_BOX:
- case TOK_RWORD_IN:
- case TOK_PAREN_OPEN:
- case TOK_SQUARE_OPEN:
-
- case TOK_MACRO:
-
- case TOK_PIPE:
- case TOK_EXCLAM:
- case TOK_DASH:
- case TOK_STAR:
- case TOK_AMP:
- return true;
- default:
- return false;
- }
-
-}
-ExprNodeP Parse_Expr1_1(TokenStream& lex);
-// Very evil handling for '..'
-ExprNodeP Parse_Expr1(TokenStream& lex)
-{
- Token tok;
- ExprNodeP (*next)(TokenStream&) = Parse_Expr1_1;
- ExprNodeP left, right;
-
- // Inclusive range to a value
- if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT ) {
- right = next(lex);
- return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, nullptr, mv$(right) );
- }
- else {
- PUTBACK(tok, lex);
- }
-
- // Exclusive ranges
- // - If NOT `.. <VAL>`, parse a leading value
- if( GET_TOK(tok, lex) != TOK_DOUBLE_DOT )
- {
- PUTBACK(tok, lex);
-
- left = next(lex);
-
- // - If NOT `<VAL> ..`, return the value
- if( GET_TOK(tok, lex) != TOK_DOUBLE_DOT )
- {
- PUTBACK(tok, lex);
- return ::std::move(left);
- }
- }
- assert( tok.type() == TOK_DOUBLE_DOT );
- // If the next token is part of a value, parse that value
- if( Parse_IsTokValue( LOOK_AHEAD(lex) ) )
- {
- right = next(lex);
- }
- else
- {
- // Otherwise, leave `right` as nullptr
- }
-
- return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE, ::std::move(left), ::std::move(right) );
-}
-// TODO: Is this left associative?
-LEFTASSOC(Parse_Expr1_1, Parse_Expr1_5,
- case TOK_TRIPLE_DOT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) );
- break;
-)
-// 1: Bool OR
-LEFTASSOC(Parse_Expr1_5, Parse_Expr2,
- case TOK_DOUBLE_PIPE:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BOOLOR, ::std::move(rv), next(lex));
- break;
-)
-// 2: Bool AND
-LEFTASSOC(Parse_Expr2, Parse_Expr3,
- case TOK_DOUBLE_AMP:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BOOLAND, ::std::move(rv), next(lex));
- break;
-)
-// 3: (In)Equality
-LEFTASSOC(Parse_Expr3, Parse_Expr4,
- case TOK_DOUBLE_EQUAL:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPEQU, ::std::move(rv), next(lex));
- break;
- case TOK_EXCLAM_EQUAL:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPNEQU, ::std::move(rv), next(lex));
- break;
-)
-// 4: Comparisons
-LEFTASSOC(Parse_Expr4, Parse_Expr5,
- case TOK_LT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPLT, ::std::move(rv), next(lex));
- break;
- case TOK_GT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPGT, ::std::move(rv), next(lex));
- break;
- case TOK_LTE:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPLTE, ::std::move(rv), next(lex));
- break;
- case TOK_GTE:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPGTE, ::std::move(rv), next(lex));
- break;
-)
-// 5: Bit OR
-LEFTASSOC(Parse_Expr5, Parse_Expr6,
- case TOK_PIPE:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITOR, ::std::move(rv), next(lex));
- break;
-)
-// 6: Bit XOR
-LEFTASSOC(Parse_Expr6, Parse_Expr7,
- case TOK_CARET:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITXOR, ::std::move(rv), next(lex));
- break;
-)
-// 7: Bit AND
-LEFTASSOC(Parse_Expr7, Parse_Expr8,
- case TOK_AMP:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITAND, ::std::move(rv), next(lex));
- break;
-)
-// 8: Bit Shifts
-LEFTASSOC(Parse_Expr8, Parse_Expr9,
- case TOK_DOUBLE_LT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SHL, ::std::move(rv), next(lex));
- break;
- case TOK_DOUBLE_GT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SHR, ::std::move(rv), next(lex));
- break;
-)
-// 9: Add / Subtract
-LEFTASSOC(Parse_Expr9, Parse_Expr10,
- case TOK_PLUS:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::ADD, ::std::move(rv), next(lex));
- break;
- case TOK_DASH:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SUB, ::std::move(rv), next(lex));
- break;
-)
-// 10: Times / Divide / Modulo
-LEFTASSOC(Parse_Expr10, Parse_Expr11,
- case TOK_STAR:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::MULTIPLY, ::std::move(rv), next(lex));
- break;
- case TOK_SLASH:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::DIVIDE, ::std::move(rv), next(lex));
- break;
- case TOK_PERCENT:
- rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::MODULO, ::std::move(rv), next(lex));
- break;
-)
-// 11: Cast
-LEFTASSOC(Parse_Expr11, Parse_Expr12,
- case TOK_RWORD_AS:
- rv = NEWNODE( AST::ExprNode_Cast, ::std::move(rv), Parse_Type(lex, false) );
- break;
-)
-// 12: Type Ascription
-ExprNodeP Parse_Expr13(TokenStream& lex);
-ExprNodeP Parse_Expr12(TokenStream& lex)
-{
- Token tok;
- auto rv = Parse_Expr13(lex);
- if(GET_TOK(tok, lex) == TOK_COLON)
- {
- rv = NEWNODE( AST::ExprNode_TypeAnnotation, mv$(rv), Parse_Type(lex) );
- }
- else
- {
- PUTBACK(tok, lex);
- }
- return rv;
-}
-// 13: Unaries
-ExprNodeP Parse_ExprFC(TokenStream& lex);
-ExprNodeP Parse_Expr13(TokenStream& lex)
-{
- Token tok;
- switch(GET_TOK(tok, lex))
- {
- case TOK_DASH:
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::NEGATE, Parse_Expr12(lex) );
- case TOK_EXCLAM:
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::INVERT, Parse_Expr12(lex) );
- case TOK_STAR:
- return NEWNODE( AST::ExprNode_Deref, Parse_Expr12(lex) );
- case TOK_RWORD_BOX:
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::BOX, Parse_Expr12(lex) );
- case TOK_RWORD_IN: {
- ExprNodeP dest;
- {
- SET_PARSE_FLAG(lex, disallow_struct_literal);
- dest = Parse_Expr1(lex);
- }
- auto val = Parse_ExprBlockNode(lex);
- return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::PLACE_IN, mv$(dest), mv$(val));
- }
- case TOK_DOUBLE_AMP:
- // HACK: Split && into & &
- lex.putback( Token(TOK_AMP) );
- case TOK_AMP:
- if( GET_TOK(tok, lex) == TOK_RWORD_MUT )
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REFMUT, Parse_Expr12(lex) );
- else {
- PUTBACK(tok, lex);
- return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REF, Parse_Expr12(lex) );
- }
- default:
- PUTBACK(tok, lex);
- return Parse_ExprFC(lex);
- }
-}
-
-ExprNodeP Parse_ExprVal(TokenStream& lex);
-ExprNodeP Parse_ExprFC(TokenStream& lex)
-{
- ExprNodeP val = Parse_ExprVal(lex);
- while(true)
- {
- Token tok;
- switch(GET_TOK(tok, lex))
- {
- case TOK_QMARK:
- val = NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::QMARK, mv$(val) );
- break;
-
- case TOK_PAREN_OPEN:
- // Expression method call
- PUTBACK(tok, lex);
- val = NEWNODE( AST::ExprNode_CallObject, ::std::move(val), Parse_ParenList(lex) );
- break;
- case TOK_SQUARE_OPEN:
- val = NEWNODE( AST::ExprNode_Index, ::std::move(val), Parse_Expr0(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- break;
- case TOK_DOT:
- // Field access / method call
- // TODO: What about tuple indexing?
- switch(GET_TOK(tok, lex))
- {
- case TOK_IDENT: {
- AST::PathNode path( mv$(tok.str()) , {});
- switch( GET_TOK(tok, lex) )
- {
- case TOK_PAREN_OPEN:
- PUTBACK(tok, lex);
- val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) );
- break;
- case TOK_DOUBLE_COLON:
- GET_CHECK_TOK(tok, lex, TOK_LT);
- path.args() = Parse_Path_GenericList(lex);
- val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) );
- break;
- default:
- val = NEWNODE( AST::ExprNode_Field, ::std::move(val), ::std::string(path.name()) );
- PUTBACK(tok, lex);
- break;
- }
- break; }
- case TOK_INTEGER:
- val = NEWNODE( AST::ExprNode_Field, ::std::move(val), FMT(tok.intval()) );
- break;
- default:
- throw ParseError::Unexpected(lex, mv$(tok));
- }
- break;
- default:
- PUTBACK(tok, lex);
- return val;
- }
- }
-}
-
-ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path)
-{
- TRACE_FUNCTION;
- Token tok;
-
- // #![feature(relaxed_adts)]
- if( LOOK_AHEAD(lex) == TOK_INTEGER )
- {
- ::std::map<unsigned int, ExprNodeP> nodes;
- while( GET_TOK(tok, lex) == TOK_INTEGER )
- {
- unsigned int ofs = tok.intval();
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- ExprNodeP val = Parse_Stmt(lex);
- if( ! nodes.insert( ::std::make_pair(ofs, mv$(val)) ).second ) {
- ERROR(lex.getPosition(), E0000, "Duplicate index");
- }
-
- if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE )
- break;
- CHECK_TOK(tok, TOK_COMMA);
- }
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
- ::std::vector<ExprNodeP> items;
- unsigned int i = 0;
- for(auto& p : nodes)
- {
- if( p.first != i ) {
- ERROR(lex.getPosition(), E0000, "Missing index " << i);
- }
- items.push_back( mv$(p.second) );
- i ++;
- }
-
- return NEWNODE( AST::ExprNode_CallPath, mv$(path), mv$(items) );
- }
-
- // Braced structure literal
- // - A series of 0 or more pairs of <ident>: <expr>,
- // - '..' <expr>
- ::std::vector< ::std::pair< ::std::string, ::std::unique_ptr<AST::ExprNode>> > items;
- while( GET_TOK(tok, lex) == TOK_IDENT )
- {
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- ExprNodeP val = Parse_Stmt(lex);
- items.push_back( ::std::make_pair(::std::move(name), ::std::move(val)) );
-
- if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE )
- break;
- CHECK_TOK(tok, TOK_COMMA);
- }
- ExprNodeP base_val;
- if( tok.type() == TOK_DOUBLE_DOT )
- {
- // default
- base_val = Parse_Expr0(lex);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
- return NEWNODE( AST::ExprNode_StructLiteral, path, ::std::move(base_val), ::std::move(items) );
-}
-
-ExprNodeP Parse_ExprVal_Closure(TokenStream& lex, bool is_move)
-{
- TRACE_FUNCTION;
- Token tok;
-
- ::std::vector< ::std::pair<AST::Pattern, TypeRef> > args;
-
- while( GET_TOK(tok, lex) != TOK_PIPE )
- {
- PUTBACK(tok, lex);
- // Irrefutable pattern
- AST::Pattern pat = Parse_Pattern(lex, false);
-
- TypeRef type { lex.getPosition() };
- if( GET_TOK(tok, lex) == TOK_COLON )
- type = Parse_Type(lex);
- else
- PUTBACK(tok, lex);
-
- args.push_back( ::std::make_pair( ::std::move(pat), ::std::move(type) ) );
-
- if( GET_TOK(tok, lex) != TOK_COMMA )
- break;
- }
- CHECK_TOK(tok, TOK_PIPE);
-
- auto rt = TypeRef(lex.getPosition());
- if( GET_TOK(tok, lex) == TOK_THINARROW ) {
-
- if( GET_TOK(tok, lex) == TOK_EXCLAM ) {
- rt = TypeRef(TypeRef::TagInvalid(), Span(tok.get_pos()));
- }
- else {
- PUTBACK(tok, lex);
- rt = Parse_Type(lex);
- }
- }
- else
- PUTBACK(tok, lex);
-
- auto code = Parse_Expr0(lex);
-
- return NEWNODE( AST::ExprNode_Closure, ::std::move(args), ::std::move(rt), ::std::move(code), is_move );
-}
-
-ExprNodeP Parse_ExprVal(TokenStream& lex)
-{
- TRACE_FUNCTION;
-
- Token tok;
- AST::Path path;
- switch( GET_TOK(tok, lex) )
- {
- case TOK_BRACE_OPEN:
- PUTBACK(tok, lex);
- return Parse_ExprBlockNode(lex);
-
- case TOK_INTERPOLATED_EXPR:
- case TOK_INTERPOLATED_BLOCK:
- return tok.take_frag_node();
-
-
- // TODO: Return/break/continue/... here?
- case TOK_RWORD_RETURN:
- case TOK_RWORD_CONTINUE:
- case TOK_RWORD_BREAK:
- PUTBACK(tok, lex);
- return Parse_Stmt(lex);
-
- case TOK_RWORD_LOOP:
- return NEWNODE( AST::ExprNode_Loop, "", Parse_ExprBlockNode(lex) );
- case TOK_RWORD_WHILE:
- return Parse_WhileStmt(lex, "");
- case TOK_RWORD_FOR:
- return Parse_ForStmt(lex, "");
- case TOK_RWORD_MATCH:
- return Parse_Expr_Match(lex);
- case TOK_RWORD_IF:
- return Parse_IfStmt(lex);
- case TOK_RWORD_UNSAFE:
- return Parse_ExprBlockNode(lex, true);
-
- // UFCS
- case TOK_DOUBLE_LT:
- case TOK_LT:
- PUTBACK(tok, lex);
- path = Parse_Path(lex, PATH_GENERIC_EXPR);
- // Skip down to method
- if(0)
- case TOK_RWORD_SELF:
- {
- if( LOOK_AHEAD(lex) != TOK_DOUBLE_COLON ) {
- return NEWNODE( AST::ExprNode_NamedValue, AST::Path(AST::Path::TagLocal(), "self") );
- }
- else
- {
- PUTBACK(tok, lex);
- path = Parse_Path(lex, PATH_GENERIC_EXPR);
- }
- }
- if(0)
- case TOK_RWORD_SUPER:
- {
- PUTBACK(tok, lex);
- path = Parse_Path(lex, PATH_GENERIC_EXPR);
- }
- if(0)
- case TOK_IDENT:
- // Get path
- {
- PUTBACK(tok, lex);
- path = Parse_Path(lex, false, PATH_GENERIC_EXPR);
- }
- if(0)
- case TOK_INTERPOLATED_PATH:
- {
- path = mv$(tok.frag_path());
- }
- if(0)
- case TOK_DOUBLE_COLON:
- path = Parse_Path(lex, true, PATH_GENERIC_EXPR);
- // SKIP TARGET
- switch( GET_TOK(tok, lex) )
- {
- case TOK_PAREN_OPEN:
- // Function call
- PUTBACK(tok, lex);
- return NEWNODE( AST::ExprNode_CallPath, ::std::move(path), Parse_ParenList(lex) );
- case TOK_BRACE_OPEN:
- if( !CHECK_PARSE_FLAG(lex, disallow_struct_literal) )
- return Parse_ExprVal_StructLiteral(lex, ::std::move(path));
- else
- DEBUG("Not parsing struct literal");
- default:
- // Value
- PUTBACK(tok, lex);
- return NEWNODE( AST::ExprNode_NamedValue, ::std::move(path) );
- }
- case TOK_RWORD_MOVE:
- // TODO: Annotate closure as move
- GET_TOK(tok, lex);
- if(tok.type() == TOK_PIPE)
- return Parse_ExprVal_Closure(lex, true);
- else if(tok.type() == TOK_DOUBLE_PIPE) {
- lex.putback(Token(TOK_PIPE));
- return Parse_ExprVal_Closure(lex, true);
- }
- else {
- CHECK_TOK(tok, TOK_PIPE);
- }
- case TOK_DOUBLE_PIPE:
- lex.putback(Token(TOK_PIPE));
- case TOK_PIPE:
- return Parse_ExprVal_Closure(lex, false);
- case TOK_INTEGER:
- return NEWNODE( AST::ExprNode_Integer, tok.intval(), tok.datatype() );
- case TOK_FLOAT:
- return NEWNODE( AST::ExprNode_Float, tok.floatval(), tok.datatype() );
- case TOK_STRING:
- return NEWNODE( AST::ExprNode_String, tok.str() );
- case TOK_BYTESTRING:
- return NEWNODE( AST::ExprNode_ByteString, tok.str() );
- case TOK_RWORD_TRUE:
- return NEWNODE( AST::ExprNode_Bool, true );
- case TOK_RWORD_FALSE:
- return NEWNODE( AST::ExprNode_Bool, false );
- case TOK_PAREN_OPEN:
- if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
- {
- DEBUG("Unit");
- return NEWNODE( AST::ExprNode_Tuple, ::std::vector<ExprNodeP>() );
- }
- else
- {
- CLEAR_PARSE_FLAG(lex, disallow_struct_literal);
- PUTBACK(tok, lex);
-
- ExprNodeP rv = Parse_Expr0(lex);
- if( GET_TOK(tok, lex) == TOK_COMMA ) {
- ::std::vector<ExprNodeP> ents;
- ents.push_back( ::std::move(rv) );
- do {
- if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
- break;
- PUTBACK(tok, lex);
- ents.push_back( Parse_Expr0(lex) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- rv = NEWNODE( AST::ExprNode_Tuple, ::std::move(ents) );
- }
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
- return rv;
- }
- case TOK_SQUARE_OPEN:
- if( GET_TOK(tok, lex) == TOK_SQUARE_CLOSE )
- {
- // Empty literal
- return NEWNODE( AST::ExprNode_Array, ::std::vector<ExprNodeP>() );
- }
- else
- {
- PUTBACK(tok, lex);
- auto first = Parse_Expr0(lex);
- if( GET_TOK(tok, lex) == TOK_SEMICOLON )
- {
- // Repetiion
- auto count = Parse_Expr0(lex);
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- return NEWNODE( AST::ExprNode_Array, ::std::move(first), ::std::move(count) );
- }
- else
- {
- ::std::vector<ExprNodeP> items;
- items.push_back( ::std::move(first) );
- while( tok.type() == TOK_COMMA )
- {
- if( GET_TOK(tok, lex) == TOK_SQUARE_CLOSE )
- break;
- else
- PUTBACK(tok, lex);
- items.push_back( Parse_Expr0(lex) );
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_SQUARE_CLOSE);
- return NEWNODE( AST::ExprNode_Array, ::std::move(items) );
- }
- }
- throw ParseError::BugCheck(lex, "Array literal fell");
- case TOK_MACRO:
- return Parse_ExprMacro(lex, mv$(tok));
- default:
- throw ParseError::Unexpected(lex, tok);
- }
-}
-ExprNodeP Parse_ExprMacro(TokenStream& lex, Token tok)
-{
- ::std::string name = tok.str();
- ::std::string ident;
- if( GET_TOK(tok, lex) == TOK_IDENT ) {
- ident = mv$(tok.str());
- }
- else {
- PUTBACK(tok, lex);
- }
- TokenTree tt = Parse_TT(lex, true);
- if( tt.is_token() ) {
- throw ParseError::Unexpected(lex, tt.tok());
- }
- return NEWNODE(AST::ExprNode_Macro, mv$(name), mv$(ident), mv$(tt));
-}
-
-// Token Tree Parsing
-TokenTree Parse_TT(TokenStream& lex, bool unwrapped)
-{
- TokenTree rv;
- TRACE_FUNCTION_FR("", rv);
-
- Token tok = lex.getToken();
- eTokenType closer = TOK_PAREN_CLOSE;
- switch(tok.type())
- {
- case TOK_PAREN_OPEN:
- closer = TOK_PAREN_CLOSE;
- break;
- case TOK_SQUARE_OPEN:
- closer = TOK_SQUARE_CLOSE;
- break;
- case TOK_BRACE_OPEN:
- closer = TOK_BRACE_CLOSE;
- break;
- // HACK! mrustc parses #[ and #![ as composite tokens
- // TODO: Split these into their component tokens.
- case TOK_ATTR_OPEN:
- case TOK_CATTR_OPEN:
- if( unwrapped )
- throw ParseError::Unexpected(lex, tok);
- closer = TOK_SQUARE_CLOSE;
- break;
-
- case TOK_EOF:
- case TOK_NULL:
- case TOK_PAREN_CLOSE:
- case TOK_SQUARE_CLOSE:
- case TOK_BRACE_CLOSE:
- throw ParseError::Unexpected(lex, tok);
- default:
- rv = TokenTree(lex.getHygiene(), mv$(tok) );
- return rv;
- }
-
- ::std::vector<TokenTree> items;
- if( !unwrapped )
- items.push_back( TokenTree(lex.getHygiene(), mv$(tok)) );
- while(GET_TOK(tok, lex) != closer && tok.type() != TOK_EOF)
- {
- if( tok.type() == TOK_NULL )
- throw ParseError::Unexpected(lex, tok);
- PUTBACK(tok, lex);
- items.push_back(Parse_TT(lex, false));
- }
- if( !unwrapped )
- items.push_back( TokenTree(lex.getHygiene(), mv$(tok)) );
- rv = TokenTree(lex.getHygiene(), mv$(items));
- return rv;
-}
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * parse/expr.cpp
+ * - Expression (i.e. code) parsing
+ *
+ * Start points:
+ * - Parse_ExprBlockNode : Parses a block
+ * - Parse_Stmt : Parse a single statement
+ * - Parse_Expr0 : Parse a single expression
+ */
+#include "parseerror.hpp"
+#include <ast/ast.hpp>
+#include <ast/expr.hpp>
+#include "common.hpp"
+#include <iostream>
+#include "tokentree.hpp"
+#include "interpolated_fragment.hpp"
+
+using AST::ExprNode;
+using AST::ExprNodeP;
+static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){en->set_pos(lex.getPosition()); return ExprNodeP(en); }
+#define NEWNODE(type, ...) mk_exprnodep(lex, new type(__VA_ARGS__))
+
+//ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false); // common.hpp
+//ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end);
+//ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence);
+ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon);
+//ExprNodeP Parse_Stmt(TokenStream& lex); // common.hpp
+ExprNodeP Parse_Stmt_Let(TokenStream& lex);
+ExprNodeP Parse_Expr0(TokenStream& lex);
+ExprNodeP Parse_IfStmt(TokenStream& lex);
+ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime);
+ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime);
+ExprNodeP Parse_Expr_Match(TokenStream& lex);
+ExprNodeP Parse_Expr1(TokenStream& lex);
+ExprNodeP Parse_ExprMacro(TokenStream& lex, Token tok);
+
+AST::Expr Parse_Expr(TokenStream& lex)
+{
+ return ::AST::Expr( Parse_Expr0(lex) );
+}
+
+AST::Expr Parse_ExprBlock(TokenStream& lex)
+{
+ return ::AST::Expr( Parse_ExprBlockNode(lex) );
+}
+
+ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe/*=false*/)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ bool yields_final_value = true;
+ ::std::vector<ExprNodeP> nodes;
+
+ ::std::shared_ptr<AST::Module> local_mod;
+
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
+
+ while( LOOK_AHEAD(lex) != TOK_BRACE_CLOSE )
+ {
+ DEBUG("tok = " << tok);
+
+ // NOTE: Doc comments can appear within a function and apply to the function
+ // TODO: Use these attributes
+ while( GET_TOK(tok, lex) == TOK_CATTR_OPEN )
+ {
+ /*node_attrs.push_back(*/ Parse_MetaItem(lex) /*)*/;
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+ PUTBACK(tok, lex);
+ if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE )
+ break;
+
+ bool add_silence_if_end = false;
+ auto rv = Parse_ExprBlockLine_WithItems(lex, local_mod, add_silence_if_end);
+ if( rv )
+ {
+ // Set to TRUE if there was no semicolon after a statement
+ if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE && add_silence_if_end )
+ {
+ DEBUG("End of block, and add_silence_if_end == true - doesn't yeild");
+ yields_final_value = false;
+ // Since the next token is TOK_BRACE_CLOSE, the loop will terminate
+ }
+ nodes.push_back( mv$(rv) );
+ }
+ else {
+ assert( !add_silence_if_end );
+ }
+ }
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
+
+ return NEWNODE( AST::ExprNode_Block, is_unsafe, yields_final_value, mv$(nodes), mv$(local_mod) );
+}
+
+/// Parse a single line in a block, handling items added to the local module
+///
+/// - If an item was parsed, this returns an empty ExprNodeP
+ExprNodeP Parse_ExprBlockLine_WithItems(TokenStream& lex, ::std::shared_ptr<AST::Module>& local_mod, bool& add_silence_if_end)
+{
+ Token tok;
+
+ AST::MetaItems item_attrs;
+ while( GET_TOK(tok, lex) == TOK_ATTR_OPEN )
+ {
+ item_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+
+ switch(tok.type())
+ {
+ // Items:
+ case TOK_RWORD_PUB:
+ // NOTE: Allowed, but doesn't do much
+ case TOK_RWORD_TYPE:
+ case TOK_RWORD_USE:
+ case TOK_RWORD_EXTERN:
+ case TOK_RWORD_CONST:
+ case TOK_RWORD_STATIC:
+ case TOK_RWORD_STRUCT:
+ case TOK_RWORD_ENUM:
+ case TOK_RWORD_TRAIT:
+ case TOK_RWORD_IMPL:
+ case TOK_RWORD_FN:
+ case TOK_RWORD_MOD:
+ PUTBACK(tok, lex);
+ if( !local_mod ) {
+ local_mod = lex.parse_state().get_current_mod().add_anon();
+ }
+ Parse_Mod_Item(lex, *local_mod, mv$(item_attrs));
+ return ExprNodeP();
+ // 'unsafe' - Check if the next token isn't a `{`, if so it's an item. Otherwise, fall through
+ case TOK_RWORD_UNSAFE:
+ if( LOOK_AHEAD(lex) != TOK_BRACE_OPEN )
+ {
+ PUTBACK(tok, lex);
+ if( !local_mod ) {
+ local_mod = lex.parse_state().get_current_mod().add_anon();
+ }
+ Parse_Mod_Item(lex, *local_mod, mv$(item_attrs));
+ return ExprNodeP();
+ }
+ // fall
+ default: {
+ PUTBACK(tok, lex);
+ auto rv = Parse_ExprBlockLine(lex, &add_silence_if_end);
+ if( rv ) {
+ rv->set_attrs( mv$(item_attrs) );
+ }
+ else if( item_attrs.m_items.size() > 0 ) {
+ // TODO: Is this an error? - Attributes on a expression that didn't yeild a node.
+ }
+ else {
+ }
+ return rv;
+ } break;
+ }
+}
+
+/// Parse a single line from a block
+///
+/// Handles:
+/// - Block-level constructs (with lifetime annotations)
+/// - use/extern/const/let
+ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *add_silence)
+{
+ Token tok;
+ ExprNodeP ret;
+
+ if( GET_TOK(tok, lex) == TOK_LIFETIME )
+ {
+ // Lifetimes can only precede loops... and blocks?
+ ::std::string lifetime = tok.str();
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_RWORD_LOOP:
+ return NEWNODE( AST::ExprNode_Loop, lifetime, Parse_ExprBlockNode(lex) );
+ case TOK_RWORD_WHILE:
+ return Parse_WhileStmt(lex, lifetime);
+ case TOK_RWORD_FOR:
+ return Parse_ForStmt(lex, lifetime);
+ //case TOK_RWORD_IF:
+ // return Parse_IfStmt(lex);
+ //case TOK_RWORD_MATCH:
+ // return Parse_Expr_Match(lex);
+ //case TOK_BRACE_OPEN:
+ // PUTBACK(tok, lex);
+ // return Parse_ExprBlockNode(lex);
+
+ default:
+ throw ParseError::Unexpected(lex, tok);
+ }
+ }
+ else
+ {
+ switch( tok.type() )
+ {
+ case TOK_INTERPOLATED_BLOCK:
+ return tok.take_frag_node();
+ case TOK_SEMICOLON:
+ // Return a NULL expression, nothing here.
+ return nullptr;
+
+ // let binding
+ case TOK_RWORD_LET:
+ ret = Parse_Stmt_Let(lex);
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ return ret;
+
+ // Blocks that don't need semicolons
+ // NOTE: If these are followed by a small set of tokens (`.` and `?`) then they are actually the start of an expression
+ // HACK: Parse here, but if the next token is one of the set store in a TOK_INTERPOLATED_EXPR and invoke the statement parser
+ case TOK_RWORD_LOOP:
+ ret = NEWNODE( AST::ExprNode_Loop, "", Parse_ExprBlockNode(lex) );
+ if(0)
+ case TOK_RWORD_WHILE:
+ ret = Parse_WhileStmt(lex, "");
+ if(0)
+ case TOK_RWORD_FOR:
+ ret = Parse_ForStmt(lex, "");
+ if(0)
+ case TOK_RWORD_IF:
+ ret = Parse_IfStmt(lex);
+ if(0)
+ case TOK_RWORD_MATCH:
+ ret = Parse_Expr_Match(lex);
+ if(0)
+ case TOK_RWORD_UNSAFE:
+ ret = Parse_ExprBlockNode(lex, true);
+ if(0)
+ case TOK_BRACE_OPEN:
+ { PUTBACK(tok, lex); ret = Parse_ExprBlockNode(lex); }
+
+ if( lex.lookahead(0) == TOK_DOT || lex.lookahead(0) == TOK_QMARK ) {
+ lex.putback( Token(Token::TagTakeIP(), InterpolatedFragment(InterpolatedFragment::EXPR, ret.release())) );
+ return Parse_ExprBlockLine_Stmt(lex, *add_silence);
+ }
+
+ if( LOOK_AHEAD(lex) == TOK_SEMICOLON ) {
+ GET_TOK(tok, lex);
+ *add_silence = true;
+ }
+
+ return ret;
+
+ // Flow control
+ case TOK_RWORD_RETURN:
+ case TOK_RWORD_CONTINUE:
+ case TOK_RWORD_BREAK: {
+ PUTBACK(tok, lex);
+ auto ret = Parse_Stmt(lex);
+ if( LOOK_AHEAD(lex) == TOK_EOF ) {
+ }
+ else if( GET_TOK(tok, lex) != TOK_SEMICOLON ) {
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+ PUTBACK(tok, lex);
+ }
+ else {
+ // return/continue/break don't need silencing
+ }
+ return ret;
+ }
+
+ case TOK_MACRO:
+ // If a braced macro invocation is the first part of a statement, don't expect a semicolon
+ if( LOOK_AHEAD(lex) == TOK_BRACE_OPEN || (lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_BRACE_OPEN) ) {
+ return Parse_ExprMacro(lex, tok);
+ }
+ // Fall through to the statement code
+ default:
+ PUTBACK(tok, lex);
+ return Parse_ExprBlockLine_Stmt(lex, *add_silence);
+ }
+ }
+}
+
+ExprNodeP Parse_ExprBlockLine_Stmt(TokenStream& lex, bool& has_semicolon)
+{
+ Token tok;
+ auto ret = Parse_Stmt(lex);
+ // If this expression statement wasn't followed by a semicolon, then it's yielding its value out of the block.
+ // - I.e. The block should be ending
+ if( GET_TOK(tok, lex) != TOK_SEMICOLON ) {
+ // - Allow TOK_EOF for macro expansion.
+ if( tok.type() == TOK_EOF )
+ ;
+ else
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+ PUTBACK(tok, lex);
+ }
+ else {
+ has_semicolon = true;
+ }
+ return ret;
+}
+
+/// While loop (either as a statement, or as part of an expression)
+ExprNodeP Parse_WhileStmt(TokenStream& lex, ::std::string lifetime)
+{
+ Token tok;
+
+ if( GET_TOK(tok, lex) == TOK_RWORD_LET ) {
+ auto pat = Parse_Pattern(lex, true); // Refutable pattern
+ GET_CHECK_TOK(tok, lex, TOK_EQUAL);
+ ExprNodeP val;
+ {
+ SET_PARSE_FLAG(lex, disallow_struct_literal);
+ val = Parse_Expr0(lex);
+ }
+ return NEWNODE( AST::ExprNode_Loop, lifetime, AST::ExprNode_Loop::WHILELET,
+ ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) );
+ }
+ else {
+ PUTBACK(tok, lex);
+ ExprNodeP cnd;
+ {
+ SET_PARSE_FLAG(lex, disallow_struct_literal);
+ cnd = Parse_Expr1(lex);
+ }
+ return NEWNODE( AST::ExprNode_Loop, lifetime, ::std::move(cnd), Parse_ExprBlockNode(lex) );
+ }
+}
+/// For loop (either as a statement, or as part of an expression)
+ExprNodeP Parse_ForStmt(TokenStream& lex, ::std::string lifetime)
+{
+ Token tok;
+
+ // Irrefutable pattern
+ AST::Pattern pat = Parse_Pattern(lex, false);
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_IN);
+ ExprNodeP val;
+ {
+ SET_PARSE_FLAG(lex, disallow_struct_literal);
+ val = Parse_Expr0(lex);
+ }
+ return NEWNODE( AST::ExprNode_Loop, lifetime, AST::ExprNode_Loop::FOR,
+ ::std::move(pat), ::std::move(val), Parse_ExprBlockNode(lex) );
+}
+/// Parse an 'if' statement
+// Note: TOK_RWORD_IF has already been eaten
+ExprNodeP Parse_IfStmt(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+ ExprNodeP cond;
+ AST::Pattern pat;
+ bool if_let = false;
+
+ {
+ SET_PARSE_FLAG(lex, disallow_struct_literal);
+ if( GET_TOK(tok, lex) == TOK_RWORD_LET ) {
+ if_let = true;
+ // Refutable pattern
+ pat = Parse_Pattern(lex, true);
+ GET_CHECK_TOK(tok, lex, TOK_EQUAL);
+ cond = Parse_Expr0(lex);
+ }
+ else {
+ PUTBACK(tok, lex);
+ cond = Parse_Expr0(lex);
+ }
+ }
+
+ // Contents
+ ExprNodeP code = Parse_ExprBlockNode(lex);
+
+ // Handle else:
+ ExprNodeP altcode;
+ if( GET_TOK(tok, lex) == TOK_RWORD_ELSE )
+ {
+ // Recurse for 'else if'
+ if( GET_TOK(tok, lex) == TOK_RWORD_IF ) {
+ altcode = Parse_IfStmt(lex);
+ }
+ // - or get block
+ else {
+ PUTBACK(tok, lex);
+ altcode = Parse_ExprBlockNode(lex);
+ }
+ }
+ // - or nothing
+ else {
+ PUTBACK(tok, lex);
+ }
+
+ if( if_let )
+ return NEWNODE( AST::ExprNode_IfLet, ::std::move(pat), ::std::move(cond), ::std::move(code), ::std::move(altcode) );
+ else
+ return NEWNODE( AST::ExprNode_If, ::std::move(cond), ::std::move(code), ::std::move(altcode) );
+}
+/// "match" block
+ExprNodeP Parse_Expr_Match(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ CLEAR_PARSE_FLAG(lex, disallow_struct_literal);
+ // 1. Get expression
+ ExprNodeP switch_val;
+ {
+ SET_PARSE_FLAG(lex, disallow_struct_literal);
+ switch_val = Parse_Expr1(lex);
+ }
+ //ASSERT(lex, !CHECK_PARSE_FLAG(lex, disallow_struct_literal) );
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
+
+ ::std::vector< AST::ExprNode_Match_Arm > arms;
+ do {
+ if( GET_TOK(tok, lex) == TOK_BRACE_CLOSE )
+ break;
+ PUTBACK(tok, lex);
+ AST::ExprNode_Match_Arm arm;
+
+ ::AST::MetaItems arm_attrs;
+ while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN ) {
+ GET_TOK(tok, lex);
+ arm_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+ arm.m_attrs = mv$(arm_attrs);
+
+ do {
+ // Refutable pattern
+ arm.m_patterns.push_back( Parse_Pattern(lex, true) );
+ } while( GET_TOK(tok, lex) == TOK_PIPE );
+
+ if( tok.type() == TOK_RWORD_IF )
+ {
+ arm.m_cond = Parse_Expr1(lex);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_FATARROW);
+
+ arm.m_code = Parse_Stmt(lex);
+
+ arms.push_back( ::std::move(arm) );
+
+ if( GET_TOK(tok, lex) == TOK_COMMA )
+ continue;
+ PUTBACK(tok, lex);
+
+ } while( 1 );
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+
+ return NEWNODE( AST::ExprNode_Match, ::std::move(switch_val), ::std::move(arms) );
+}
+
+/// Parses the 'stmt' fragment specifier
+/// - Flow control
+/// - Expressions
+ExprNodeP Parse_Stmt(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_INTERPOLATED_STMT:
+ return tok.take_frag_node();
+ // Duplicated here for the :stmt pattern fragment.
+ case TOK_RWORD_LET:
+ return Parse_Stmt_Let(lex);
+ case TOK_RWORD_RETURN: {
+ ExprNodeP val;
+ 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_Expr0(lex);
+ break;
+ }
+ return NEWNODE( AST::ExprNode_Flow, AST::ExprNode_Flow::RETURN, "", ::std::move(val) );
+ }
+ case TOK_RWORD_CONTINUE:
+ case TOK_RWORD_BREAK:
+ {
+ AST::ExprNode_Flow::Type type;
+ switch(tok.type())
+ {
+ case TOK_RWORD_CONTINUE: type = AST::ExprNode_Flow::CONTINUE; break;
+ case TOK_RWORD_BREAK: type = AST::ExprNode_Flow::BREAK; break;
+ default: throw ParseError::BugCheck(/*lex,*/ "continue/break");
+ }
+ ::std::string lifetime;
+ if( GET_TOK(tok, lex) == TOK_LIFETIME )
+ {
+ lifetime = tok.str();
+ GET_TOK(tok, lex);
+ }
+ ExprNodeP val;
+ switch(tok.type())
+ {
+ case TOK_SEMICOLON:
+ case TOK_COMMA:
+ case TOK_BRACE_OPEN:
+ case TOK_BRACE_CLOSE:
+ case TOK_PAREN_CLOSE:
+ case TOK_SQUARE_CLOSE:
+ PUTBACK(tok, lex);
+ break;
+ default:
+ PUTBACK(tok, lex);
+ val = Parse_Expr1(lex);
+ break;
+ }
+ return NEWNODE( AST::ExprNode_Flow, type, lifetime, ::std::move(val) );
+ }
+ case TOK_BRACE_OPEN:
+ PUTBACK(tok, lex);
+ return Parse_ExprBlockNode(lex);
+ default:
+ PUTBACK(tok, lex);
+ return Parse_Expr0(lex);
+ }
+}
+
+ExprNodeP Parse_Stmt_Let(TokenStream& lex)
+{
+ Token tok;
+ AST::Pattern pat = Parse_Pattern(lex, false); // irrefutable
+ TypeRef type { lex.getPosition() };
+ if( GET_TOK(tok, lex) == TOK_COLON ) {
+ type = Parse_Type(lex);
+ GET_TOK(tok, lex);
+ }
+ ExprNodeP val;
+ if( tok.type() == TOK_EQUAL ) {
+ val = Parse_Expr0(lex);
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+ return NEWNODE( AST::ExprNode_LetBinding, ::std::move(pat), mv$(type), ::std::move(val) );
+}
+
+::std::vector<ExprNodeP> Parse_ParenList(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ CLEAR_PARSE_FLAG(lex, disallow_struct_literal);
+
+ ::std::vector<ExprNodeP> rv;
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
+ if( GET_TOK(tok, lex) != TOK_PAREN_CLOSE )
+ {
+ PUTBACK(tok, lex);
+ do {
+ if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) {
+ GET_TOK(tok, lex);
+ break;
+ }
+ rv.push_back( Parse_Expr0(lex) );
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ CHECK_TOK(tok, TOK_PAREN_CLOSE);
+ }
+ return rv;
+}
+
+// 0: Assign
+ExprNodeP Parse_Expr0(TokenStream& lex)
+{
+ //TRACE_FUNCTION;
+ Token tok;
+
+ ::AST::MetaItems expr_attrs;
+ while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
+ {
+ GET_TOK(tok, lex);
+ expr_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+
+ ExprNodeP rv = Parse_Expr1(lex);
+ auto op = AST::ExprNode_Assign::NONE;
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_PLUS_EQUAL:
+ op = AST::ExprNode_Assign::ADD; if(0)
+ case TOK_DASH_EQUAL:
+ op = AST::ExprNode_Assign::SUB; if(0)
+ case TOK_STAR_EQUAL:
+ op = AST::ExprNode_Assign::MUL; if(0)
+ case TOK_SLASH_EQUAL:
+ op = AST::ExprNode_Assign::DIV; if(0)
+ case TOK_PERCENT_EQUAL:
+ op = AST::ExprNode_Assign::MOD; if(0)
+
+ case TOK_AMP_EQUAL:
+ op = AST::ExprNode_Assign::AND; if(0)
+ case TOK_PIPE_EQUAL:
+ op = AST::ExprNode_Assign::OR ; if(0)
+ case TOK_CARET_EQUAL:
+ op = AST::ExprNode_Assign::XOR; if(0)
+
+ case TOK_DOUBLE_GT_EQUAL:
+ op = AST::ExprNode_Assign::SHR; if(0)
+ case TOK_DOUBLE_LT_EQUAL:
+ op = AST::ExprNode_Assign::SHL; if(0)
+
+ case TOK_EQUAL:
+ op = AST::ExprNode_Assign::NONE;
+ rv = NEWNODE( AST::ExprNode_Assign, op, ::std::move(rv), Parse_Expr0(lex) );
+ rv->set_attrs(mv$(expr_attrs));
+ return rv;
+
+ default:
+ PUTBACK(tok, lex);
+ rv->set_attrs(mv$(expr_attrs));
+ return rv;
+ }
+}
+
+
+#define LEFTASSOC(cur, _next, cases) \
+ExprNodeP _next(TokenStream& lex); \
+ExprNodeP cur(TokenStream& lex) \
+{ \
+ ExprNodeP (*next)(TokenStream&) = _next;\
+ ExprNodeP rv = next(lex); \
+ while(true) \
+ { \
+ Token tok; \
+ switch((tok = lex.getToken()).type()) \
+ { \
+ cases \
+ default: \
+ /*::std::cout << "<<" << #cur << ::std::endl; */\
+ PUTBACK(tok, lex); \
+ return rv; \
+ } \
+ } \
+}
+bool Parse_IsTokValue(eTokenType tok_type)
+{
+ switch( tok_type )
+ {
+ case TOK_DOUBLE_COLON:
+ case TOK_IDENT:
+ case TOK_INTEGER:
+ case TOK_FLOAT:
+ case TOK_STRING:
+ case TOK_RWORD_TRUE:
+ case TOK_RWORD_FALSE:
+ case TOK_RWORD_SELF:
+ case TOK_RWORD_SUPER:
+ case TOK_RWORD_BOX:
+ case TOK_RWORD_IN:
+ case TOK_PAREN_OPEN:
+ case TOK_SQUARE_OPEN:
+
+ case TOK_MACRO:
+
+ case TOK_PIPE:
+ case TOK_EXCLAM:
+ case TOK_DASH:
+ case TOK_STAR:
+ case TOK_AMP:
+ return true;
+ default:
+ return false;
+ }
+
+}
+ExprNodeP Parse_Expr1_1(TokenStream& lex);
+// Very evil handling for '..'
+ExprNodeP Parse_Expr1(TokenStream& lex)
+{
+ Token tok;
+ ExprNodeP (*next)(TokenStream&) = Parse_Expr1_1;
+ ExprNodeP left, right;
+
+ // Inclusive range to a value
+ if( GET_TOK(tok, lex) == TOK_TRIPLE_DOT ) {
+ right = next(lex);
+ return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, nullptr, mv$(right) );
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+
+ // Exclusive ranges
+ // - If NOT `.. <VAL>`, parse a leading value
+ if( GET_TOK(tok, lex) != TOK_DOUBLE_DOT )
+ {
+ PUTBACK(tok, lex);
+
+ left = next(lex);
+
+ // - If NOT `<VAL> ..`, return the value
+ if( GET_TOK(tok, lex) != TOK_DOUBLE_DOT )
+ {
+ PUTBACK(tok, lex);
+ return ::std::move(left);
+ }
+ }
+ assert( tok.type() == TOK_DOUBLE_DOT );
+ // If the next token is part of a value, parse that value
+ if( Parse_IsTokValue( LOOK_AHEAD(lex) ) )
+ {
+ right = next(lex);
+ }
+ else
+ {
+ // Otherwise, leave `right` as nullptr
+ }
+
+ return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE, ::std::move(left), ::std::move(right) );
+}
+// TODO: Is this left associative?
+LEFTASSOC(Parse_Expr1_1, Parse_Expr1_5,
+ case TOK_TRIPLE_DOT:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::RANGE_INC, mv$(rv), next(lex) );
+ break;
+)
+// 1: Bool OR
+LEFTASSOC(Parse_Expr1_5, Parse_Expr2,
+ case TOK_DOUBLE_PIPE:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BOOLOR, ::std::move(rv), next(lex));
+ break;
+)
+// 2: Bool AND
+LEFTASSOC(Parse_Expr2, Parse_Expr3,
+ case TOK_DOUBLE_AMP:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BOOLAND, ::std::move(rv), next(lex));
+ break;
+)
+// 3: (In)Equality
+LEFTASSOC(Parse_Expr3, Parse_Expr4,
+ case TOK_DOUBLE_EQUAL:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPEQU, ::std::move(rv), next(lex));
+ break;
+ case TOK_EXCLAM_EQUAL:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPNEQU, ::std::move(rv), next(lex));
+ break;
+)
+// 4: Comparisons
+LEFTASSOC(Parse_Expr4, Parse_Expr5,
+ case TOK_LT:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPLT, ::std::move(rv), next(lex));
+ break;
+ case TOK_GT:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPGT, ::std::move(rv), next(lex));
+ break;
+ case TOK_LTE:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPLTE, ::std::move(rv), next(lex));
+ break;
+ case TOK_GTE:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::CMPGTE, ::std::move(rv), next(lex));
+ break;
+)
+// 5: Bit OR
+LEFTASSOC(Parse_Expr5, Parse_Expr6,
+ case TOK_PIPE:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITOR, ::std::move(rv), next(lex));
+ break;
+)
+// 6: Bit XOR
+LEFTASSOC(Parse_Expr6, Parse_Expr7,
+ case TOK_CARET:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITXOR, ::std::move(rv), next(lex));
+ break;
+)
+// 7: Bit AND
+LEFTASSOC(Parse_Expr7, Parse_Expr8,
+ case TOK_AMP:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::BITAND, ::std::move(rv), next(lex));
+ break;
+)
+// 8: Bit Shifts
+LEFTASSOC(Parse_Expr8, Parse_Expr9,
+ case TOK_DOUBLE_LT:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SHL, ::std::move(rv), next(lex));
+ break;
+ case TOK_DOUBLE_GT:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SHR, ::std::move(rv), next(lex));
+ break;
+)
+// 9: Add / Subtract
+LEFTASSOC(Parse_Expr9, Parse_Expr10,
+ case TOK_PLUS:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::ADD, ::std::move(rv), next(lex));
+ break;
+ case TOK_DASH:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::SUB, ::std::move(rv), next(lex));
+ break;
+)
+// 10: Times / Divide / Modulo
+LEFTASSOC(Parse_Expr10, Parse_Expr11,
+ case TOK_STAR:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::MULTIPLY, ::std::move(rv), next(lex));
+ break;
+ case TOK_SLASH:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::DIVIDE, ::std::move(rv), next(lex));
+ break;
+ case TOK_PERCENT:
+ rv = NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::MODULO, ::std::move(rv), next(lex));
+ break;
+)
+// 11: Cast
+LEFTASSOC(Parse_Expr11, Parse_Expr12,
+ case TOK_RWORD_AS:
+ rv = NEWNODE( AST::ExprNode_Cast, ::std::move(rv), Parse_Type(lex, false) );
+ break;
+)
+// 12: Type Ascription
+ExprNodeP Parse_Expr13(TokenStream& lex);
+ExprNodeP Parse_Expr12(TokenStream& lex)
+{
+ Token tok;
+ auto rv = Parse_Expr13(lex);
+ if(GET_TOK(tok, lex) == TOK_COLON)
+ {
+ rv = NEWNODE( AST::ExprNode_TypeAnnotation, mv$(rv), Parse_Type(lex) );
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ }
+ return rv;
+}
+// 13: Unaries
+ExprNodeP Parse_ExprFC(TokenStream& lex);
+ExprNodeP Parse_Expr13(TokenStream& lex)
+{
+ Token tok;
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_DASH:
+ return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::NEGATE, Parse_Expr12(lex) );
+ case TOK_EXCLAM:
+ return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::INVERT, Parse_Expr12(lex) );
+ case TOK_STAR:
+ return NEWNODE( AST::ExprNode_Deref, Parse_Expr12(lex) );
+ case TOK_RWORD_BOX:
+ return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::BOX, Parse_Expr12(lex) );
+ case TOK_RWORD_IN: {
+ ExprNodeP dest;
+ {
+ SET_PARSE_FLAG(lex, disallow_struct_literal);
+ dest = Parse_Expr1(lex);
+ }
+ auto val = Parse_ExprBlockNode(lex);
+ return NEWNODE( AST::ExprNode_BinOp, AST::ExprNode_BinOp::PLACE_IN, mv$(dest), mv$(val));
+ }
+ case TOK_DOUBLE_AMP:
+ // HACK: Split && into & &
+ lex.putback( Token(TOK_AMP) );
+ case TOK_AMP:
+ if( GET_TOK(tok, lex) == TOK_RWORD_MUT )
+ return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REFMUT, Parse_Expr12(lex) );
+ else {
+ PUTBACK(tok, lex);
+ return NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::REF, Parse_Expr12(lex) );
+ }
+ default:
+ PUTBACK(tok, lex);
+ return Parse_ExprFC(lex);
+ }
+}
+
+ExprNodeP Parse_ExprVal(TokenStream& lex);
+ExprNodeP Parse_ExprFC(TokenStream& lex)
+{
+ ExprNodeP val = Parse_ExprVal(lex);
+ while(true)
+ {
+ Token tok;
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_QMARK:
+ val = NEWNODE( AST::ExprNode_UniOp, AST::ExprNode_UniOp::QMARK, mv$(val) );
+ break;
+
+ case TOK_PAREN_OPEN:
+ // Expression method call
+ PUTBACK(tok, lex);
+ val = NEWNODE( AST::ExprNode_CallObject, ::std::move(val), Parse_ParenList(lex) );
+ break;
+ case TOK_SQUARE_OPEN:
+ val = NEWNODE( AST::ExprNode_Index, ::std::move(val), Parse_Expr0(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ break;
+ case TOK_DOT:
+ // Field access / method call
+ // TODO: What about tuple indexing?
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_IDENT: {
+ AST::PathNode path( mv$(tok.str()) , {});
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_PAREN_OPEN:
+ PUTBACK(tok, lex);
+ val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) );
+ break;
+ case TOK_DOUBLE_COLON:
+ GET_CHECK_TOK(tok, lex, TOK_LT);
+ path.args() = Parse_Path_GenericList(lex);
+ val = NEWNODE( AST::ExprNode_CallMethod, ::std::move(val), ::std::move(path), Parse_ParenList(lex) );
+ break;
+ default:
+ val = NEWNODE( AST::ExprNode_Field, ::std::move(val), ::std::string(path.name()) );
+ PUTBACK(tok, lex);
+ break;
+ }
+ break; }
+ case TOK_INTEGER:
+ val = NEWNODE( AST::ExprNode_Field, ::std::move(val), FMT(tok.intval()) );
+ break;
+ default:
+ throw ParseError::Unexpected(lex, mv$(tok));
+ }
+ break;
+ default:
+ PUTBACK(tok, lex);
+ return val;
+ }
+ }
+}
+
+ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ // #![feature(relaxed_adts)]
+ if( LOOK_AHEAD(lex) == TOK_INTEGER )
+ {
+ ::std::map<unsigned int, ExprNodeP> nodes;
+ while( GET_TOK(tok, lex) == TOK_INTEGER )
+ {
+ unsigned int ofs = tok.intval();
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ ExprNodeP val = Parse_Stmt(lex);
+ if( ! nodes.insert( ::std::make_pair(ofs, mv$(val)) ).second ) {
+ ERROR(lex.getPosition(), E0000, "Duplicate index");
+ }
+
+ if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE )
+ break;
+ CHECK_TOK(tok, TOK_COMMA);
+ }
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+
+ ::std::vector<ExprNodeP> items;
+ unsigned int i = 0;
+ for(auto& p : nodes)
+ {
+ if( p.first != i ) {
+ ERROR(lex.getPosition(), E0000, "Missing index " << i);
+ }
+ items.push_back( mv$(p.second) );
+ i ++;
+ }
+
+ return NEWNODE( AST::ExprNode_CallPath, mv$(path), mv$(items) );
+ }
+
+ // Braced structure literal
+ // - A series of 0 or more pairs of <ident>: <expr>,
+ // - '..' <expr>
+ ::std::vector< ::std::pair< ::std::string, ::std::unique_ptr<AST::ExprNode>> > items;
+ while( GET_TOK(tok, lex) == TOK_IDENT )
+ {
+ auto name = mv$(tok.str());
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ ExprNodeP val = Parse_Stmt(lex);
+ items.push_back( ::std::make_pair(::std::move(name), ::std::move(val)) );
+
+ if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE )
+ break;
+ CHECK_TOK(tok, TOK_COMMA);
+ }
+ ExprNodeP base_val;
+ if( tok.type() == TOK_DOUBLE_DOT )
+ {
+ // default
+ base_val = Parse_Expr0(lex);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+
+ return NEWNODE( AST::ExprNode_StructLiteral, path, ::std::move(base_val), ::std::move(items) );
+}
+
+ExprNodeP Parse_ExprVal_Closure(TokenStream& lex, bool is_move)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ ::std::vector< ::std::pair<AST::Pattern, TypeRef> > args;
+
+ while( GET_TOK(tok, lex) != TOK_PIPE )
+ {
+ PUTBACK(tok, lex);
+ // Irrefutable pattern
+ AST::Pattern pat = Parse_Pattern(lex, false);
+
+ TypeRef type { lex.getPosition() };
+ if( GET_TOK(tok, lex) == TOK_COLON )
+ type = Parse_Type(lex);
+ else
+ PUTBACK(tok, lex);
+
+ args.push_back( ::std::make_pair( ::std::move(pat), ::std::move(type) ) );
+
+ if( GET_TOK(tok, lex) != TOK_COMMA )
+ break;
+ }
+ CHECK_TOK(tok, TOK_PIPE);
+
+ auto rt = TypeRef(lex.getPosition());
+ if( GET_TOK(tok, lex) == TOK_THINARROW ) {
+
+ if( GET_TOK(tok, lex) == TOK_EXCLAM ) {
+ rt = TypeRef(TypeRef::TagInvalid(), Span(tok.get_pos()));
+ }
+ else {
+ PUTBACK(tok, lex);
+ rt = Parse_Type(lex);
+ }
+ }
+ else
+ PUTBACK(tok, lex);
+
+ auto code = Parse_Expr0(lex);
+
+ return NEWNODE( AST::ExprNode_Closure, ::std::move(args), ::std::move(rt), ::std::move(code), is_move );
+}
+
+ExprNodeP Parse_ExprVal(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+ AST::Path path;
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_BRACE_OPEN:
+ PUTBACK(tok, lex);
+ return Parse_ExprBlockNode(lex);
+
+ case TOK_INTERPOLATED_EXPR:
+ case TOK_INTERPOLATED_BLOCK:
+ return tok.take_frag_node();
+
+
+ // TODO: Return/break/continue/... here?
+ case TOK_RWORD_RETURN:
+ case TOK_RWORD_CONTINUE:
+ case TOK_RWORD_BREAK:
+ PUTBACK(tok, lex);
+ return Parse_Stmt(lex);
+
+ case TOK_RWORD_LOOP:
+ return NEWNODE( AST::ExprNode_Loop, "", Parse_ExprBlockNode(lex) );
+ case TOK_RWORD_WHILE:
+ return Parse_WhileStmt(lex, "");
+ case TOK_RWORD_FOR:
+ return Parse_ForStmt(lex, "");
+ case TOK_RWORD_MATCH:
+ return Parse_Expr_Match(lex);
+ case TOK_RWORD_IF:
+ return Parse_IfStmt(lex);
+ case TOK_RWORD_UNSAFE:
+ return Parse_ExprBlockNode(lex, true);
+
+ // UFCS
+ case TOK_DOUBLE_LT:
+ case TOK_LT:
+ PUTBACK(tok, lex);
+ path = Parse_Path(lex, PATH_GENERIC_EXPR);
+ // Skip down to method
+ if(0)
+ case TOK_RWORD_SELF:
+ {
+ if( LOOK_AHEAD(lex) != TOK_DOUBLE_COLON ) {
+ return NEWNODE( AST::ExprNode_NamedValue, AST::Path(AST::Path::TagLocal(), "self") );
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ path = Parse_Path(lex, PATH_GENERIC_EXPR);
+ }
+ }
+ if(0)
+ case TOK_RWORD_SUPER:
+ {
+ PUTBACK(tok, lex);
+ path = Parse_Path(lex, PATH_GENERIC_EXPR);
+ }
+ if(0)
+ case TOK_IDENT:
+ // Get path
+ {
+ PUTBACK(tok, lex);
+ path = Parse_Path(lex, false, PATH_GENERIC_EXPR);
+ }
+ if(0)
+ case TOK_INTERPOLATED_PATH:
+ {
+ path = mv$(tok.frag_path());
+ }
+ if(0)
+ case TOK_DOUBLE_COLON:
+ path = Parse_Path(lex, true, PATH_GENERIC_EXPR);
+ // SKIP TARGET
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_PAREN_OPEN:
+ // Function call
+ PUTBACK(tok, lex);
+ return NEWNODE( AST::ExprNode_CallPath, ::std::move(path), Parse_ParenList(lex) );
+ case TOK_BRACE_OPEN:
+ if( !CHECK_PARSE_FLAG(lex, disallow_struct_literal) )
+ return Parse_ExprVal_StructLiteral(lex, ::std::move(path));
+ else
+ DEBUG("Not parsing struct literal");
+ default:
+ // Value
+ PUTBACK(tok, lex);
+ return NEWNODE( AST::ExprNode_NamedValue, ::std::move(path) );
+ }
+ case TOK_RWORD_MOVE:
+ // TODO: Annotate closure as move
+ GET_TOK(tok, lex);
+ if(tok.type() == TOK_PIPE)
+ return Parse_ExprVal_Closure(lex, true);
+ else if(tok.type() == TOK_DOUBLE_PIPE) {
+ lex.putback(Token(TOK_PIPE));
+ return Parse_ExprVal_Closure(lex, true);
+ }
+ else {
+ CHECK_TOK(tok, TOK_PIPE);
+ }
+ case TOK_DOUBLE_PIPE:
+ lex.putback(Token(TOK_PIPE));
+ case TOK_PIPE:
+ return Parse_ExprVal_Closure(lex, false);
+ case TOK_INTEGER:
+ return NEWNODE( AST::ExprNode_Integer, tok.intval(), tok.datatype() );
+ case TOK_FLOAT:
+ return NEWNODE( AST::ExprNode_Float, tok.floatval(), tok.datatype() );
+ case TOK_STRING:
+ return NEWNODE( AST::ExprNode_String, tok.str() );
+ case TOK_BYTESTRING:
+ return NEWNODE( AST::ExprNode_ByteString, tok.str() );
+ case TOK_RWORD_TRUE:
+ return NEWNODE( AST::ExprNode_Bool, true );
+ case TOK_RWORD_FALSE:
+ return NEWNODE( AST::ExprNode_Bool, false );
+ case TOK_PAREN_OPEN:
+ if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
+ {
+ DEBUG("Unit");
+ return NEWNODE( AST::ExprNode_Tuple, ::std::vector<ExprNodeP>() );
+ }
+ else
+ {
+ CLEAR_PARSE_FLAG(lex, disallow_struct_literal);
+ PUTBACK(tok, lex);
+
+ ExprNodeP rv = Parse_Expr0(lex);
+ if( GET_TOK(tok, lex) == TOK_COMMA ) {
+ ::std::vector<ExprNodeP> ents;
+ ents.push_back( ::std::move(rv) );
+ do {
+ if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
+ break;
+ PUTBACK(tok, lex);
+ ents.push_back( Parse_Expr0(lex) );
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ rv = NEWNODE( AST::ExprNode_Tuple, ::std::move(ents) );
+ }
+ CHECK_TOK(tok, TOK_PAREN_CLOSE);
+ return rv;
+ }
+ case TOK_SQUARE_OPEN:
+ if( GET_TOK(tok, lex) == TOK_SQUARE_CLOSE )
+ {
+ // Empty literal
+ return NEWNODE( AST::ExprNode_Array, ::std::vector<ExprNodeP>() );
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ auto first = Parse_Expr0(lex);
+ if( GET_TOK(tok, lex) == TOK_SEMICOLON )
+ {
+ // Repetiion
+ auto count = Parse_Expr0(lex);
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ return NEWNODE( AST::ExprNode_Array, ::std::move(first), ::std::move(count) );
+ }
+ else
+ {
+ ::std::vector<ExprNodeP> items;
+ items.push_back( ::std::move(first) );
+ while( tok.type() == TOK_COMMA )
+ {
+ if( GET_TOK(tok, lex) == TOK_SQUARE_CLOSE )
+ break;
+ else
+ PUTBACK(tok, lex);
+ items.push_back( Parse_Expr0(lex) );
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_SQUARE_CLOSE);
+ return NEWNODE( AST::ExprNode_Array, ::std::move(items) );
+ }
+ }
+ throw ParseError::BugCheck(lex, "Array literal fell");
+ case TOK_MACRO:
+ return Parse_ExprMacro(lex, mv$(tok));
+ default:
+ throw ParseError::Unexpected(lex, tok);
+ }
+}
+ExprNodeP Parse_ExprMacro(TokenStream& lex, Token tok)
+{
+ ::std::string name = tok.str();
+ ::std::string ident;
+ if( GET_TOK(tok, lex) == TOK_IDENT ) {
+ ident = mv$(tok.str());
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+ TokenTree tt = Parse_TT(lex, true);
+ if( tt.is_token() ) {
+ throw ParseError::Unexpected(lex, tt.tok());
+ }
+ return NEWNODE(AST::ExprNode_Macro, mv$(name), mv$(ident), mv$(tt));
+}
+
+// Token Tree Parsing
+TokenTree Parse_TT(TokenStream& lex, bool unwrapped)
+{
+ TokenTree rv;
+ TRACE_FUNCTION_FR("", rv);
+
+ Token tok = lex.getToken();
+ eTokenType closer = TOK_PAREN_CLOSE;
+ switch(tok.type())
+ {
+ case TOK_PAREN_OPEN:
+ closer = TOK_PAREN_CLOSE;
+ break;
+ case TOK_SQUARE_OPEN:
+ closer = TOK_SQUARE_CLOSE;
+ break;
+ case TOK_BRACE_OPEN:
+ closer = TOK_BRACE_CLOSE;
+ break;
+ // HACK! mrustc parses #[ and #![ as composite tokens
+ // TODO: Split these into their component tokens.
+ case TOK_ATTR_OPEN:
+ case TOK_CATTR_OPEN:
+ if( unwrapped )
+ throw ParseError::Unexpected(lex, tok);
+ closer = TOK_SQUARE_CLOSE;
+ break;
+
+ case TOK_EOF:
+ case TOK_NULL:
+ case TOK_PAREN_CLOSE:
+ case TOK_SQUARE_CLOSE:
+ case TOK_BRACE_CLOSE:
+ throw ParseError::Unexpected(lex, tok);
+ default:
+ rv = TokenTree(lex.getHygiene(), mv$(tok) );
+ return rv;
+ }
+
+ ::std::vector<TokenTree> items;
+ if( !unwrapped )
+ items.push_back( TokenTree(lex.getHygiene(), mv$(tok)) );
+ while(GET_TOK(tok, lex) != closer && tok.type() != TOK_EOF)
+ {
+ if( tok.type() == TOK_NULL )
+ throw ParseError::Unexpected(lex, tok);
+ PUTBACK(tok, lex);
+ items.push_back(Parse_TT(lex, false));
+ }
+ if( !unwrapped )
+ items.push_back( TokenTree(lex.getHygiene(), mv$(tok)) );
+ rv = TokenTree(lex.getHygiene(), mv$(items));
+ return rv;
+}
diff --git a/src/parse/interpolated_fragment.hpp b/src/parse/interpolated_fragment.hpp
index b0be2efe..a3e72816 100644
--- a/src/parse/interpolated_fragment.hpp
+++ b/src/parse/interpolated_fragment.hpp
@@ -25,18 +25,18 @@ public:
PAT,
PATH,
TYPE,
-
+
EXPR,
STMT,
BLOCK,
-
+
META,
ITEM,
} m_type;
-
+
// Owned type-pruned pointer
void* m_ptr;
-
+
InterpolatedFragment(InterpolatedFragment&& );
InterpolatedFragment& operator=(InterpolatedFragment&& );
//InterpolatedFragment(const InterpolatedFragment& );
@@ -48,9 +48,9 @@ public:
InterpolatedFragment(::AST::Named<AST::Item> );
~InterpolatedFragment();
InterpolatedFragment(Type , ::AST::ExprNode*);
-
+
TokenTree& as_tt() { assert(m_type == TT); return *reinterpret_cast<TokenTree*>(m_ptr); }
const TokenTree& as_tt() const { assert(m_type == TT); return *reinterpret_cast<TokenTree*>(m_ptr); }
-
+
friend ::std::ostream& operator<<(::std::ostream& os, const InterpolatedFragment& x);
};
diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp
index dfd2a2d3..9b09b1d4 100644
--- a/src/parse/lex.cpp
+++ b/src/parse/lex.cpp
@@ -275,7 +275,7 @@ Token Lexer::getTokenInt()
try
{
Codepoint ch = this->getc();
-
+
if( ch == '#' && m_line == 1 && m_line_ofs == 1 ) {
switch( (ch = this->getc()).v )
{
@@ -326,8 +326,8 @@ Token Lexer::getTokenInt()
DEC,
HEX,
} num_mode = DEC;
-
-
+
+
// Handle integers/floats
uint64_t val = 0;
if( ch == '0' ) {
@@ -390,7 +390,7 @@ Token Lexer::getTokenInt()
if( ch == '.' )
{
ch = this->getc();
-
+
// Double/Triple Dot
if( ch == '.' )
{
@@ -403,7 +403,7 @@ Token Lexer::getTokenInt()
}
return Token(val, CORETYPE_ANY);
}
-
+
// Single dot followed by a non-digit, could be a float or an integer with a method/field access
if( !ch.isdigit() )
{
@@ -428,8 +428,8 @@ Token Lexer::getTokenInt()
}
if( num_mode != DEC )
TODO(this->getPosition(), "Non-decimal floats");
-
-
+
+
this->ungetc();
double fval = this->parseFloat(val);
if( issym(ch = this->getc()) )
@@ -441,7 +441,7 @@ Token Lexer::getTokenInt()
ch = this->getc();
}
this->ungetc();
-
+
if(0) ;
else if(suffix == "f32") num_type = CORETYPE_F32;
else if(suffix == "f64") num_type = CORETYPE_F64;
@@ -464,7 +464,7 @@ Token Lexer::getTokenInt()
ch = this->getc();
}
this->ungetc();
-
+
if(0) ;
else if(suffix == "i8") num_type = CORETYPE_I8;
else if(suffix == "i16") num_type = CORETYPE_I16;
@@ -495,13 +495,13 @@ Token Lexer::getTokenInt()
is_byte = true;
ch = this->getc();
}
-
+
if(ch == 'r') {
return this->getTokenInt_RawString(is_byte);
}
else {
assert(is_byte);
-
+
// Byte string
if( ch == '"' ) {
::std::string str;
@@ -579,7 +579,7 @@ Token Lexer::getTokenInt()
while(true)
{
ch = this->getc();
-
+
if( ch == '/' ) {
str += ch;
ch = this->getc();
@@ -704,7 +704,7 @@ Token Lexer::getTokenInt_RawString(bool is_byte)
catch( Lexer::EndOfFile e ) {
throw ParseError::Generic(*this, "EOF reached in raw string");
}
-
+
if( terminating_hashes > 0 )
{
assert(terminating_hashes > 0);
@@ -715,7 +715,7 @@ Token Lexer::getTokenInt_RawString(bool is_byte)
terminating_hashes += 1;
}
terminating_hashes = 0;
-
+
this->ungetc();
}
else {
@@ -800,9 +800,9 @@ double Lexer::parseFloat(uint64_t whole)
}
this->ungetc();
buf[ofs] = 0;
-
+
DEBUG("buf = " << buf << ", ch = '" << ch << "'");
-
+
return ::std::strtod(buf, NULL);
}
@@ -920,7 +920,7 @@ Codepoint Lexer::getc_cp()
// Two bytes
uint8_t e1 = this->getc_byte();
if( (e1 & 0xC0) != 0x80 ) return {0xFFFE};
-
+
uint32_t outval
= ((v1 & 0x1F) << 6)
| ((e1 & 0x3F) <<0)
@@ -933,7 +933,7 @@ Codepoint Lexer::getc_cp()
if( (e1 & 0xC0) != 0x80 ) return {0xFFFE};
uint8_t e2 = this->getc_byte();
if( (e2 & 0xC0) != 0x80 ) return {0xFFFE};
-
+
uint32_t outval
= ((v1 & 0x0F) << 12)
| ((e1 & 0x3F) << 6)
@@ -949,7 +949,7 @@ Codepoint Lexer::getc_cp()
if( (e2 & 0xC0) != 0x80 ) return {0xFFFE};
uint8_t e3 = this->getc_byte();
if( (e3 & 0xC0) != 0x80 ) return {0xFFFE};
-
+
uint32_t outval
= ((v1 & 0x07) << 18)
| ((e1 & 0x3F) << 12)
@@ -1004,7 +1004,7 @@ bool Codepoint::isxdigit() const {
s += (char)cp.v;
}
else if( cp.v < (0x1F+1)<<(1*6) ) {
-
+
s += (char)(0xC0 | ((cp.v >> 6) & 0x1F));
s += (char)(0x80 | ((cp.v >> 0) & 0x3F));
}
diff --git a/src/parse/lex.hpp b/src/parse/lex.hpp
index 572846da..871ab29a 100644
--- a/src/parse/lex.hpp
+++ b/src/parse/lex.hpp
@@ -40,7 +40,7 @@ class Lexer:
bool m_last_char_valid;
Codepoint m_last_char;
Token m_next_token; // Used when lexing generated two tokens
-
+
Ident::Hygiene m_hygiene;
public:
Lexer(const ::std::string& filename);
@@ -51,7 +51,7 @@ public:
private:
Token getTokenInt();
-
+
signed int getSymbol();
Token getTokenInt_RawString(bool is_byte);
Token getTokenInt_Identifier(Codepoint ch, Codepoint ch2='\0');
diff --git a/src/parse/parseerror.cpp b/src/parse/parseerror.cpp
index 116776a5..3c5d41fe 100644
--- a/src/parse/parseerror.cpp
+++ b/src/parse/parseerror.cpp
@@ -1,91 +1,91 @@
-/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * parse/parseerror.cpp
- * - Exceptions thrown for different types of parsing errors
- */
-#include "parseerror.hpp"
-#include <iostream>
-
-CompileError::Base::~Base() throw()
-{
-}
-
-CompileError::Generic::Generic(::std::string message):
- m_message(message)
-{
- ::std::cout << "Generic(" << message << ")" << ::std::endl;
-}
-CompileError::Generic::Generic(const TokenStream& lex, ::std::string message)
-{
- ::std::cout << lex.getPosition() << ": Generic(" << message << ")" << ::std::endl;
-}
-
-CompileError::BugCheck::BugCheck(const TokenStream& lex, ::std::string message):
- m_message(message)
-{
- ::std::cout << lex.getPosition() << "BugCheck(" << message << ")" << ::std::endl;
-}
-CompileError::BugCheck::BugCheck(::std::string message):
- m_message(message)
-{
- ::std::cout << "BugCheck(" << message << ")" << ::std::endl;
-}
-
-CompileError::Todo::Todo(::std::string message):
- m_message(message)
-{
- ::std::cout << "Todo(" << message << ")" << ::std::endl;
-}
-CompileError::Todo::Todo(const TokenStream& lex, ::std::string message):
- m_message(message)
-{
- ::std::cout << lex.getPosition() << ": Todo(" << message << ")" << ::std::endl;
-}
-CompileError::Todo::~Todo() throw()
-{
-}
-
-ParseError::BadChar::BadChar(const TokenStream& lex, char character)
-{
- ::std::cout << lex.getPosition() << ": BadChar(" << character << ")" << ::std::endl;
-}
-ParseError::BadChar::~BadChar() throw()
-{
-}
-
-ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok)//:
-// m_tok( mv$(tok) )
-{
- auto pos = tok.get_pos();
- if(pos.filename == "")
- pos = lex.getPosition();
- ::std::cout << pos << ": Unexpected(" << tok << ")" << ::std::endl;
-}
-ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Token exp)//:
-// m_tok( mv$(tok) )
-{
- auto pos = tok.get_pos();
- if(pos.filename == "")
- pos = lex.getPosition();
- ::std::cout << pos << ": Unexpected(" << tok << ", " << exp << ")" << ::std::endl;
-}
-ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp)
-{
- auto pos = tok.get_pos();
- if(pos.filename == "")
- pos = lex.getPosition();
- ::std::cout << pos << ": Unexpected " << tok << ", expected ";
- 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()
-{
-}
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * parse/parseerror.cpp
+ * - Exceptions thrown for different types of parsing errors
+ */
+#include "parseerror.hpp"
+#include <iostream>
+
+CompileError::Base::~Base() throw()
+{
+}
+
+CompileError::Generic::Generic(::std::string message):
+ m_message(message)
+{
+ ::std::cout << "Generic(" << message << ")" << ::std::endl;
+}
+CompileError::Generic::Generic(const TokenStream& lex, ::std::string message)
+{
+ ::std::cout << lex.getPosition() << ": Generic(" << message << ")" << ::std::endl;
+}
+
+CompileError::BugCheck::BugCheck(const TokenStream& lex, ::std::string message):
+ m_message(message)
+{
+ ::std::cout << lex.getPosition() << "BugCheck(" << message << ")" << ::std::endl;
+}
+CompileError::BugCheck::BugCheck(::std::string message):
+ m_message(message)
+{
+ ::std::cout << "BugCheck(" << message << ")" << ::std::endl;
+}
+
+CompileError::Todo::Todo(::std::string message):
+ m_message(message)
+{
+ ::std::cout << "Todo(" << message << ")" << ::std::endl;
+}
+CompileError::Todo::Todo(const TokenStream& lex, ::std::string message):
+ m_message(message)
+{
+ ::std::cout << lex.getPosition() << ": Todo(" << message << ")" << ::std::endl;
+}
+CompileError::Todo::~Todo() throw()
+{
+}
+
+ParseError::BadChar::BadChar(const TokenStream& lex, char character)
+{
+ ::std::cout << lex.getPosition() << ": BadChar(" << character << ")" << ::std::endl;
+}
+ParseError::BadChar::~BadChar() throw()
+{
+}
+
+ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok)//:
+// m_tok( mv$(tok) )
+{
+ auto pos = tok.get_pos();
+ if(pos.filename == "")
+ pos = lex.getPosition();
+ ::std::cout << pos << ": Unexpected(" << tok << ")" << ::std::endl;
+}
+ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Token exp)//:
+// m_tok( mv$(tok) )
+{
+ auto pos = tok.get_pos();
+ if(pos.filename == "")
+ pos = lex.getPosition();
+ ::std::cout << pos << ": Unexpected(" << tok << ", " << exp << ")" << ::std::endl;
+}
+ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp)
+{
+ auto pos = tok.get_pos();
+ if(pos.filename == "")
+ pos = lex.getPosition();
+ ::std::cout << pos << ": Unexpected " << tok << ", expected ";
+ 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/parseerror.hpp b/src/parse/parseerror.hpp
index 0a00f60a..d6bcab6b 100644
--- a/src/parse/parseerror.hpp
+++ b/src/parse/parseerror.hpp
@@ -1,40 +1,40 @@
-#ifndef PARSEERROR_HPP_INCLUDED
-#define PARSEERROR_HPP_INCLUDED
-
-#include <stdexcept>
-#include "tokenstream.hpp"
-#include <compile_error.hpp>
-
-namespace ParseError {
-
-using CompileError::Generic;
-using CompileError::BugCheck;
-using CompileError::Todo;
-
-class BadChar:
- public CompileError::Base
-{
- //char m_char;
-public:
- BadChar(const TokenStream& lex, char character);
- virtual ~BadChar() throw ();
-
-};
-
-class Unexpected:
- public CompileError::Base
-{
- Token m_tok;
-public:
- Unexpected(const TokenStream& lex, const Token& tok);
- Unexpected(const TokenStream& lex, const Token& tok, Token exp);
- Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp);
- virtual ~Unexpected() throw ();
-
-};
-
-#define ASSERT(lex, cnd) do { if( !(cnd) ) throw CompileError::BugCheck(lex, "Assertion failed: " __FILE__ " - " #cnd); } while(0)
-
-}
-
-#endif // PARSEERROR_HPP_INCLUDED
+#ifndef PARSEERROR_HPP_INCLUDED
+#define PARSEERROR_HPP_INCLUDED
+
+#include <stdexcept>
+#include "tokenstream.hpp"
+#include <compile_error.hpp>
+
+namespace ParseError {
+
+using CompileError::Generic;
+using CompileError::BugCheck;
+using CompileError::Todo;
+
+class BadChar:
+ public CompileError::Base
+{
+ //char m_char;
+public:
+ BadChar(const TokenStream& lex, char character);
+ virtual ~BadChar() throw ();
+
+};
+
+class Unexpected:
+ public CompileError::Base
+{
+ Token m_tok;
+public:
+ Unexpected(const TokenStream& lex, const Token& tok);
+ Unexpected(const TokenStream& lex, const Token& tok, Token exp);
+ Unexpected(const TokenStream& lex, const Token& tok, ::std::vector<eTokenType> exp);
+ virtual ~Unexpected() throw ();
+
+};
+
+#define ASSERT(lex, cnd) do { if( !(cnd) ) throw CompileError::BugCheck(lex, "Assertion failed: " __FILE__ " - " #cnd); } while(0)
+
+}
+
+#endif // PARSEERROR_HPP_INCLUDED
diff --git a/src/parse/paths.cpp b/src/parse/paths.cpp
index e600e51e..360c630f 100644
--- a/src/parse/paths.cpp
+++ b/src/parse/paths.cpp
@@ -17,17 +17,17 @@ AST::PathParams Parse_Path_GenericList(TokenStream& lex);
AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode)
{
TRACE_FUNCTION_F("generic_mode="<<generic_mode);
-
+
Token tok;
switch( GET_TOK(tok, lex) )
{
case TOK_INTERPOLATED_PATH:
return mv$(tok.frag_path());
-
+
case TOK_RWORD_SELF:
GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
return Parse_Path(lex, false, generic_mode);
-
+
case TOK_RWORD_SUPER: {
GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
unsigned int count = 1;
@@ -38,10 +38,10 @@ AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode)
}
return AST::Path(AST::Path::TagSuper(), count, Parse_PathNodes(lex, 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: {
@@ -69,7 +69,7 @@ AST::Path Parse_Path(TokenStream& lex, eParsePathGenericMode generic_mode)
return AST::Path(AST::Path::TagUfcs(), mv$(ty), AST::Path(), Parse_PathNodes(lex, generic_mode));
}
throw ""; }
-
+
default:
PUTBACK(tok, lex);
return Parse_Path(lex, false, generic_mode);
@@ -102,7 +102,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
::std::vector<AST::PathNode> Parse_PathNodes(TokenStream& lex, eParsePathGenericMode generic_mode)
{
TRACE_FUNCTION_F("generic_mode="<<generic_mode);
-
+
Token tok;
::std::vector<AST::PathNode> ret;
@@ -122,7 +122,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
// HACK! Handle breaking << into < <
if( tok.type() == TOK_DOUBLE_LT )
lex.putback( Token(TOK_LT) );
-
+
// Type-mode generics "::path::to::Type<A,B>"
params = Parse_Path_GenericList(lex);
GET_TOK(tok, lex);
@@ -146,7 +146,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
} while( GET_TOK(tok, lex) == TOK_COMMA );
}
CHECK_TOK(tok, TOK_PAREN_CLOSE);
-
+
TypeRef ret_type = TypeRef( TypeRef::TagUnit(), Span(tok.get_pos()) );
if( GET_TOK(tok, lex) == TOK_THINARROW ) {
ret_type = Parse_Type(lex, false);
@@ -155,14 +155,14 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
PUTBACK(tok, lex);
}
DEBUG("- Fn("<<args<<")->"<<ret_type<<"");
-
+
// Encode into path, by converting Fn(A,B)->C into Fn<(A,B),Ret=C>
params = ::AST::PathParams {
{},
::make_vec1( TypeRef(TypeRef::TagTuple(), lex.end_span(ps), mv$(args)) ),
::make_vec1( ::std::make_pair( ::std::string("Output"), mv$(ret_type) ) )
};
-
+
GET_TOK(tok, lex);
}
else
@@ -179,7 +179,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
// HACK! Handle breaking << into < <
if( tok.type() == TOK_DOUBLE_LT )
lex.putback( Token(TOK_LT) );
-
+
// Expr-mode generics "::path::to::function::<Type1,Type2>(arg1, arg2)"
params = Parse_Path_GenericList(lex);
if( GET_TOK(tok, lex) != TOK_DOUBLE_COLON ) {
@@ -205,7 +205,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
::std::vector<TypeRef> types;
::std::vector< ::std::string> lifetimes;
::std::vector< ::std::pair< ::std::string, TypeRef > > assoc_bounds;
-
+
do {
if( LOOK_AHEAD(lex) == TOK_GT || LOOK_AHEAD(lex) == TOK_DOUBLE_GT || LOOK_AHEAD(lex) == TOK_GTE || LOOK_AHEAD(lex) == TOK_DOUBLE_GT_EQUAL ) {
GET_TOK(tok, lex);
@@ -244,7 +244,7 @@ AST::Path Parse_Path(TokenStream& lex, bool is_abs, eParsePathGenericMode generi
else {
CHECK_TOK(tok, TOK_GT);
}
-
+
return ::AST::PathParams {
mv$( lifetimes ),
mv$( types ),
diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp
index b0149ddb..699e7fae 100644
--- a/src/parse/pattern.cpp
+++ b/src/parse/pattern.cpp
@@ -42,7 +42,7 @@ 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(ps, tok.str(), lex)));
@@ -51,7 +51,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
{
return mv$(tok.frag_pattern());
}
-
+
bool expect_bind = false;
auto bind_type = AST::PatternBinding::Type::MOVE;
bool is_mut = false;
@@ -80,7 +80,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
{
// Fall through
}
-
+
AST::PatternBinding binding;
// If a 'ref' or 'mut' annotation was seen, the next name must be a binding name
if( expect_bind )
@@ -94,7 +94,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
return AST::Pattern(AST::Pattern::TagBind(), mv$(bind_name), bind_type, is_mut);
}
binding = AST::PatternBinding( mv$(bind_name), bind_type, is_mut );
-
+
// '@' consumed, move on to next token
GET_TOK(tok, lex);
}
@@ -138,7 +138,7 @@ AST::Pattern Parse_Pattern(TokenStream& lex, bool is_refutable)
{
// Otherwise, fall through
}
-
+
PUTBACK(tok, lex);
auto pat = Parse_PatternReal(lex, is_refutable);
pat.binding() = mv$(binding);
@@ -159,13 +159,13 @@ AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable)
if( !ret.data().is_Value() )
throw ParseError::Generic(lex, "Using '...' with a non-value on left");
auto& ret_v = ret.data().as_Value();
-
+
auto right_pat = Parse_PatternReal1(lex, is_refutable);
if( !right_pat.data().is_Value() )
throw ParseError::Generic(lex, "Using '...' with a non-value on right");
auto rightval = mv$( right_pat.data().as_Value().start );
ret_v.end = mv$(rightval);
-
+
return ret;
}
else
@@ -177,10 +177,10 @@ AST::Pattern Parse_PatternReal(TokenStream& lex, bool is_refutable)
AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
{
TRACE_FUNCTION;
-
+
Token tok;
AST::Path path;
-
+
switch( GET_TOK(tok, lex) )
{
case TOK_UNDERSCORE:
@@ -260,7 +260,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
TODO(lex.getPosition(), "Convert :expr into a pattern value - " << *e);
}
} break;
-
+
case TOK_PAREN_OPEN:
return AST::Pattern( AST::Pattern::TagTuple(), Parse_PatternTuple(lex, is_refutable) );
case TOK_SQUARE_OPEN:
@@ -272,7 +272,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable)
AST::Pattern Parse_PatternReal_Path(TokenStream& lex, AST::Path path, bool is_refutable)
{
Token tok;
-
+
switch( GET_TOK(tok, lex) )
{
case TOK_PAREN_OPEN:
@@ -289,12 +289,12 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
{
auto sp = lex.start_span();
Token tok;
-
+
::std::vector< ::AST::Pattern> leading;
::std::vector< ::AST::Pattern> trailing;
::AST::PatternBinding inner_binding;
bool is_split = false;
-
+
while(GET_TOK(tok, lex) != TOK_SQUARE_CLOSE)
{
bool has_binding = true;
@@ -316,11 +316,11 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
else {
has_binding = false;
}
-
+
if( has_binding ) {
if(is_split)
ERROR(lex.end_span(sp), E0000, "Multiple instances of .. in a slice pattern");
-
+
inner_binding = mv$(binding);
is_split = true;
GET_TOK(tok, lex); // TOK_DOUBLE_DOT
@@ -334,12 +334,12 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
trailing.push_back( Parse_Pattern(lex, is_refutable) );
}
}
-
+
if( GET_TOK(tok, lex) != TOK_COMMA )
break;
}
CHECK_TOK(tok, TOK_SQUARE_CLOSE);
-
+
if( is_split )
{
return ::AST::Pattern( ::AST::Pattern::Data::make_SplitSlice({ mv$(leading), mv$(inner_binding), mv$(trailing) }) );
@@ -357,34 +357,34 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
TRACE_FUNCTION;
auto sp = lex.start_span();
Token tok;
-
+
::std::vector<AST::Pattern> leading;
while( LOOK_AHEAD(lex) != TOK_PAREN_CLOSE && LOOK_AHEAD(lex) != TOK_DOUBLE_DOT )
{
leading.push_back( Parse_Pattern(lex, is_refutable) );
-
+
if( GET_TOK(tok, lex) != TOK_COMMA ) {
CHECK_TOK(tok, TOK_PAREN_CLOSE);
return AST::Pattern::TuplePat { mv$(leading), false, {} };
}
}
-
+
if( LOOK_AHEAD(lex) != TOK_DOUBLE_DOT )
{
GET_TOK(tok, lex);
-
+
CHECK_TOK(tok, TOK_PAREN_CLOSE);
return AST::Pattern::TuplePat { mv$(leading), false, {} };
}
GET_CHECK_TOK(tok, lex, TOK_DOUBLE_DOT);
-
+
::std::vector<AST::Pattern> trailing;
if( GET_TOK(tok, lex) == TOK_COMMA )
{
while( LOOK_AHEAD(lex) != TOK_PAREN_CLOSE )
{
trailing.push_back( Parse_Pattern(lex, is_refutable) );
-
+
if( GET_TOK(tok, lex) != TOK_COMMA ) {
PUTBACK(tok, lex);
break;
@@ -392,7 +392,7 @@ AST::Pattern Parse_PatternReal_Slice(TokenStream& lex, bool is_refutable)
}
GET_TOK(tok, lex);
}
-
+
CHECK_TOK(tok, TOK_PAREN_CLOSE);
return ::AST::Pattern::TuplePat { mv$(leading), true, mv$(trailing) };
}
@@ -401,7 +401,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
{
TRACE_FUNCTION;
Token tok;
-
+
// #![feature(relaxed_adts)]
if( LOOK_AHEAD(lex) == TOK_INTEGER )
{
@@ -415,7 +415,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
if( ! pats.insert( ::std::make_pair(ofs, mv$(val)) ).second ) {
ERROR(lex.getPosition(), E0000, "Duplicate index");
}
-
+
if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE )
break;
CHECK_TOK(tok, TOK_COMMA);
@@ -425,7 +425,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
GET_TOK(tok, lex);
}
CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
+
bool has_split = false;
::std::vector<AST::Pattern> leading;
::std::vector<AST::Pattern> trailing;
@@ -447,10 +447,10 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
}
i ++;
}
-
+
return AST::Pattern(AST::Pattern::TagNamedTuple(), mv$(path), AST::Pattern::TuplePat { mv$(leading), has_split, mv$(trailing) });
}
-
+
bool is_exhaustive = true;
::std::vector< ::std::pair< ::std::string, AST::Pattern> > subpats;
do {
@@ -463,7 +463,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
GET_TOK(tok, lex);
break;
}
-
+
bool is_short_bind = false;
bool is_box = false;
auto bind_type = AST::PatternBinding::Type::MOVE;
@@ -489,12 +489,12 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
is_short_bind = true;
GET_TOK(tok, lex);
}
-
+
CHECK_TOK(tok, TOK_IDENT);
auto field_ident = lex.get_ident(mv$(tok));
::std::string field_name;
GET_TOK(tok, lex);
-
+
AST::Pattern pat;
if( is_short_bind || tok.type() != TOK_COLON ) {
PUTBACK(tok, lex);
@@ -511,11 +511,11 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut
field_name = mv$(field_ident.name);
pat = Parse_Pattern(lex, is_refutable);
}
-
+
subpats.push_back( ::std::make_pair(mv$(field_name), mv$(pat)) );
} while( GET_TOK(tok, lex) == TOK_COMMA );
CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
+
return AST::Pattern(AST::Pattern::TagStruct(), ::std::move(path), ::std::move(subpats), is_exhaustive);
}
diff --git a/src/parse/root.cpp b/src/parse/root.cpp
index 5a244543..e5f5b5f4 100644
--- a/src/parse/root.cpp
+++ b/src/parse/root.cpp
@@ -1,1879 +1,1879 @@
-/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * parse/root.cpp
- * - Parsing at the module level (highest-level parsing)
- *
- * Entrypoint:
- * - Parse_Crate : Handles crate attrbutes, and passes on to Parse_ModRoot
- * - Parse_ModRoot
- */
-#include <ast/ast.hpp>
-#include <ast/crate.hpp>
-#include "parseerror.hpp"
-#include "common.hpp"
-#include <cassert>
-#include <hir/hir.hpp> // ABI_RUST - TODO: Move elsewhere?
-#include <expand/cfg.hpp> // check_cfg - for `mod nonexistant;`
-#include <fstream> // Used by directory path
-#include "lex.hpp" // New file lexer
-
-template<typename T>
-Spanned<T> get_spanned(TokenStream& lex, ::std::function<T()> f) {
- auto ps = lex.start_span();
- auto v = f();
- return Spanned<T> {
- lex.end_span(ps),
- mv$(v)
- };
-}
-#define GET_SPANNED(type, lex, val) get_spanned< type >(lex, [&](){ return val; })
-
-// Check the next two tokens
-#define LOOKAHEAD2(lex, tok1, tok2) ((lex).lookahead(0) == (tok1) && (lex).lookahead(1) == (tok2))
-
-::std::string dirname(::std::string input) {
- while( input.size() > 0 && input.back() != '/' ) {
- input.pop_back();
- }
- return input;
-}
-
-AST::MetaItem Parse_MetaItem(TokenStream& lex);
-void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::MetaItems& mod_attrs);
-
-::std::vector< ::std::string> Parse_HRB(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
-
- ::std::vector< ::std::string> lifetimes;
- GET_CHECK_TOK(tok, lex, TOK_LT);
- do {
- GET_TOK(tok, lex);
-
- ::AST::MetaItems attrs;
- while(tok.type() == TOK_ATTR_OPEN)
- {
- attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- (void)attrs; // TODO: Attributes on generic params
-
- switch(tok.type())
- {
- 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);
- return lifetimes;
-}
-/// Parse type parameters in a definition
-void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_type, ::std::vector< ::std::string> lifetimes = {})
-{
- TRACE_FUNCTION;
- Token tok;
-
- do
- {
- ::std::vector< ::std::string> hrls;
- if(GET_TOK(tok, lex) == TOK_LIFETIME) {
- ret.add_bound(AST::GenericBound::make_TypeLifetime( {
- checked_type.clone(), tok.str()
- } ));
- }
- else if( tok.type() == TOK_QMARK ) {
- ret.add_bound(AST::GenericBound::make_MaybeTrait( {
- checked_type.clone(), Parse_Path(lex, PATH_GENERIC_TYPE)
- } ));
- }
- else {
- if( tok.type() == TOK_RWORD_FOR )
- {
- hrls = Parse_HRB(lex);
- }
- else {
- PUTBACK(tok, lex);
- }
- (void)hrls; // TODO: HRLs
-
- ret.add_bound( AST::GenericBound::make_IsTrait({
- checked_type.clone(), mv$(lifetimes), Parse_Path(lex, PATH_GENERIC_TYPE)
- }) );
- }
- } while( GET_TOK(tok, lex) == TOK_PLUS );
- PUTBACK(tok, lex);
-}
-
-/// Parse type parameters within '<' and '>' (definition)
-AST::GenericParams Parse_GenericParams(TokenStream& lex)
-{
- TRACE_FUNCTION;
-
- AST::GenericParams ret;
- Token tok;
- do {
- if( GET_TOK(tok, lex) == TOK_GT ) {
- break ;
- }
-
- ::AST::MetaItems attrs;
- while(tok.type() == TOK_ATTR_OPEN)
- {
- attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- (void)attrs; // TODO: Attributes on generic params
-
- if( tok.type() == TOK_IDENT )
- {
- // TODO: Hygine
- ::std::string param_name = mv$(tok.str());
- ret.add_ty_param( AST::TypeParam( param_name ) );
-
- auto param_ty = TypeRef(lex.getPosition(), param_name);
- if( GET_TOK(tok, lex) == TOK_COLON )
- {
- Parse_TypeBound(lex, ret, mv$(param_ty));
- GET_TOK(tok, lex);
- }
-
- if( tok.type() == TOK_EQUAL )
- {
- ret.ty_params().back().setDefault( Parse_Type(lex) );
- GET_TOK(tok, lex);
- }
- }
- else if( tok.type() == TOK_LIFETIME )
- {
- // TODO: Should lifetimes have hygine?
- ::std::string param_name = tok.str();
- ret.add_lft_param( param_name );
- if( GET_TOK(tok, lex) == TOK_COLON )
- {
- do {
- GET_CHECK_TOK(tok, lex, TOK_LIFETIME);
- ret.add_bound(AST::GenericBound::make_Lifetime( {param_name, tok.str()} ));
- } while( GET_TOK(tok, lex) == TOK_PLUS );
- }
- }
- else
- {
- throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_LIFETIME});
- }
- } while( tok.type() == TOK_COMMA );
- PUTBACK(tok, lex);
- return ret;
-}
-
-
-/// Parse the contents of a 'where' clause
-void Parse_WhereClause(TokenStream& lex, AST::GenericParams& params)
-{
- TRACE_FUNCTION;
- Token tok;
-
- do {
- GET_TOK(tok, lex);
- if( tok.type() == TOK_BRACE_OPEN ) {
- break;
- }
-
- if( tok.type() == TOK_LIFETIME )
- {
- auto lhs = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- do {
- GET_CHECK_TOK(tok, lex, TOK_LIFETIME);
- auto rhs = mv$(tok.str());
- params.add_bound( AST::GenericBound::make_Lifetime({lhs, rhs}) );
- } while( GET_TOK(tok, lex) == TOK_PLUS );
- PUTBACK(tok, lex);
- }
- // Higher-ranked types/lifetimes
- else if( tok.type() == TOK_RWORD_FOR )
- {
- ::std::vector< ::std::string> lifetimes = Parse_HRB(lex);
-
- TypeRef type = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- Parse_TypeBound(lex,params, mv$(type), mv$(lifetimes));
- }
- else
- {
- PUTBACK(tok, lex);
- TypeRef type = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- Parse_TypeBound(lex, params, mv$(type));
- }
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- PUTBACK(tok, lex);
-}
-
-// Parse a single function argument
-::std::pair< AST::Pattern, TypeRef> Parse_Function_Arg(TokenStream& lex, bool expect_named)
-{
- TRACE_FUNCTION_F("expect_named = " << expect_named);
- Token tok;
-
- AST::Pattern pat;
-
- // If any of the following
- // - Expecting a named parameter (i.e. defining a function in root or impl)
- // - Next token is an underscore (only valid as a pattern here)
- // - Next token is 'mut' (a mutable parameter slot)
- // - Next two are <ident> ':' (a trivial named parameter)
- // NOTE: When not expecting a named param, destructuring patterns are not allowed
- if( expect_named
- || LOOK_AHEAD(lex) == TOK_UNDERSCORE
- || LOOK_AHEAD(lex) == TOK_RWORD_MUT
- || (LOOK_AHEAD(lex) == TOK_IDENT && lex.lookahead(1) == TOK_COLON)
- )
- {
- // Function args can't be refuted
- pat = Parse_Pattern(lex, false);
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- }
-
- TypeRef type = Parse_Type(lex);
-
-
- return ::std::make_pair( ::std::move(pat), ::std::move(type) );
-}
-
-/// Parse a function definition (after the 'fn <name>')
-AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_self, bool can_be_prototype, bool is_unsafe, bool is_const)
-{
- TRACE_FUNCTION;
- ProtoSpan ps = lex.start_span();
-
- Token tok;
-
- // Parameters
- AST::GenericParams params;
- if( GET_TOK(tok, lex) == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- }
- else {
- PUTBACK(tok, lex);
- }
-
- AST::Function::Arglist args;
-
- GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
- GET_TOK(tok, lex);
-
- // Handle self
- if( tok.type() == TOK_AMP )
- {
- // By-reference method?
- // TODO: If a lifetime is seen (and not a prototype), it is definitely a self binding
-
- unsigned int ofs = 0;
- if( lex.lookahead(0) == TOK_LIFETIME )
- ofs ++;
-
- if( lex.lookahead(ofs) == TOK_RWORD_SELF || (lex.lookahead(ofs) == TOK_RWORD_MUT && lex.lookahead(ofs+1) == TOK_RWORD_SELF) )
- {
- auto ps = lex.start_span();
- ::std::string lifetime;
- if( GET_TOK(tok, lex) == TOK_LIFETIME ) {
- lifetime = tok.str();
- GET_TOK(tok, lex);
- }
- auto ty_sp = lex.end_span(ps);
-
- if( tok.type() == TOK_RWORD_MUT )
- {
- GET_CHECK_TOK(tok, lex, TOK_RWORD_SELF);
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, true, TypeRef(ty_sp, "Self", 0xFFFF))) );
- }
- else
- {
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, false, TypeRef(ty_sp, "Self", 0xFFFF))) );
- }
- DEBUG("TODO: UFCS / self lifetimes");
- if( allow_self == false )
- throw ParseError::Generic(lex, "Self binding not expected");
- //args.push_back( ::std::make_pair(
- // AST::Pattern(),
- // TypeRef(TypeRef::TagReference(), lifetime, (fcn_class == AST::Function::CLASS_MUTMETHOD), )
- //) );
-
- // Prime tok for next step
- GET_TOK(tok, lex);
- }
- else
- {
- // Unbound method
- }
- }
- else if( tok.type() == TOK_RWORD_MUT )
- {
- if( LOOK_AHEAD(lex) == TOK_RWORD_SELF )
- {
- GET_TOK(tok, lex);
- if( allow_self == false )
- throw ParseError::Generic(lex, "Self binding not expected");
- TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF );
- if( GET_TOK(tok, lex) == TOK_COLON ) {
- // Typed mut self
- ty = Parse_Type(lex);
- }
- else {
- PUTBACK(tok, lex);
- }
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), mv$(ty)) );
- GET_TOK(tok, lex);
- }
- }
- else if( tok.type() == TOK_RWORD_SELF )
- {
- // By-value method
- if( allow_self == false )
- throw ParseError::Generic(lex, "Self binding not expected");
- TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF );
- if( GET_TOK(tok, lex) == TOK_COLON ) {
- // Typed mut self
- ty = Parse_Type(lex);
- }
- else {
- PUTBACK(tok, lex);
- }
- args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), mv$(ty)) );
- GET_TOK(tok, lex);
- }
- else
- {
- // Unbound method
- }
-
- bool is_variadic = false;
- if( tok.type() != TOK_PAREN_CLOSE )
- {
- // Comma after self
- if( args.size() )
- {
- CHECK_TOK(tok, TOK_COMMA);
- }
- else {
- PUTBACK(tok, lex);
- }
-
- // Argument list
- do {
- if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) {
- GET_TOK(tok, lex);
- break;
- }
- if( LOOK_AHEAD(lex) == TOK_TRIPLE_DOT ) {
- GET_TOK(tok, lex);
- is_variadic = true;
- GET_TOK(tok, lex);
- break;
- }
- args.push_back( Parse_Function_Arg(lex, !can_be_prototype) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
- }
- else {
- // Eat 'tok', negative comparison
- }
-
- TypeRef ret_type = TypeRef(TypeRef::TagUnit(), Span(tok.get_pos()));
- if( GET_TOK(tok, lex) == TOK_THINARROW )
- {
- // Return type
- ret_type = Parse_Type(lex);
- }
- else
- {
- PUTBACK(tok, lex);
- }
-
- if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
- {
- Parse_WhereClause(lex, params);
- }
- else {
- PUTBACK(tok, lex);
- }
-
- return AST::Function(lex.end_span(ps), mv$(params), mv$(abi), is_unsafe, is_const, is_variadic, mv$(ret_type), mv$(args));
-}
-
-AST::Function Parse_FunctionDefWithCode(TokenStream& lex, ::std::string abi, bool allow_self, bool is_unsafe, bool is_const)
-{
- Token tok;
- auto ret = Parse_FunctionDef(lex, abi, allow_self, false, is_unsafe, is_const);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
- PUTBACK(tok, lex);
- ret.set_code( Parse_ExprBlock(lex) );
- return ret;
-}
-
-AST::TypeAlias Parse_TypeAlias(TokenStream& lex)
-{
- TRACE_FUNCTION;
-
- Token tok;
-
- // Params
- AST::GenericParams params;
- if( GET_TOK(tok, lex) == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- GET_TOK(tok, lex);
- }
-
- if( tok.type() == TOK_RWORD_WHERE )
- {
- Parse_WhereClause(lex, params);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_EQUAL);
-
- // Type
- TypeRef type = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
-
- return AST::TypeAlias( ::std::move(params), ::std::move(type) );
-}
-
-AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items)
-{
- TRACE_FUNCTION;
-
- Token tok;
-
- tok = lex.getToken();
- AST::GenericParams params;
- if( tok.type() == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- if(GET_TOK(tok, lex) == TOK_RWORD_WHERE)
- {
- Parse_WhereClause(lex, params);
- tok = lex.getToken();
- }
- }
- if(tok.type() == TOK_PAREN_OPEN)
- {
- // Tuple structs
- ::std::vector<AST::TupleItem> refs;
- while(GET_TOK(tok, lex) != TOK_PAREN_CLOSE)
- {
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, item_attrs);
-
- bool is_pub = false;
- if(tok.type() == TOK_RWORD_PUB)
- is_pub = true;
- else
- PUTBACK(tok, lex);
-
- refs.push_back( AST::TupleItem( mv$(item_attrs), is_pub, Parse_Type(lex) ) );
- if( GET_TOK(tok, lex) != TOK_COMMA )
- break;
- }
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
-
- if(LOOK_AHEAD(lex) == TOK_RWORD_WHERE)
- {
- GET_TOK(tok, lex);
- Parse_WhereClause(lex, params);
- }
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- //if( refs.size() == 0 )
- // WARNING( , W000, "Use 'struct Name;' instead of 'struct Name();' ... ning-nong");
- return AST::Struct(mv$(params), mv$(refs));
- }
- else if(tok.type() == TOK_SEMICOLON)
- {
- // Unit-like struct
- return AST::Struct(mv$(params), ::std::vector<AST::TupleItem>());
- }
- else if(tok.type() == TOK_BRACE_OPEN)
- {
- ::std::vector<AST::StructItem> items;
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
- {
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, item_attrs);
-
- bool is_pub = false;
- if(tok.type() == TOK_RWORD_PUB) {
- is_pub = true;
- GET_TOK(tok, lex);
- }
-
- CHECK_TOK(tok, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- TypeRef type = Parse_Type(lex);
-
- items.push_back( AST::StructItem( mv$(item_attrs), is_pub, mv$(name), mv$(type) ) );
- if(GET_TOK(tok, lex) == TOK_BRACE_CLOSE)
- break;
- CHECK_TOK(tok, TOK_COMMA);
- }
- //if( items.size() == 0 )
- // WARNING( , W000, "Use 'struct Name;' instead of 'struct Nam { };' ... ning-nong");
- return AST::Struct(::std::move(params), ::std::move(items));
- }
- else
- {
- throw ParseError::Unexpected(lex, tok);
- }
-}
-
-AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
-{
- TRACE_FUNCTION;
-
- Token tok;
-
- AST::GenericParams params;
- if( GET_TOK(tok, lex) == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- tok = lex.getToken();
- }
-
- // Trait bounds "trait Trait : 'lifetime + OtherTrait + OtherTrait2"
- ::std::vector<Spanned<AST::Path> > supertraits;
- if(tok.type() == TOK_COLON)
- {
- do {
- if( GET_TOK(tok, lex) == TOK_LIFETIME ) {
- // TODO: Need a better way of indiciating 'static than just an invalid path
- supertraits.push_back( make_spanned( Span(tok.get_pos()), AST::Path() ) );
- }
- else {
- PUTBACK(tok, lex);
- supertraits.push_back( GET_SPANNED(::AST::Path, lex, Parse_Path(lex, PATH_GENERIC_TYPE)) );
- }
- } while( GET_TOK(tok, lex) == TOK_PLUS );
- }
-
- // TODO: Support "for Sized?"
- if(tok.type() == TOK_RWORD_WHERE)
- {
- //if( params.ty_params().size() == 0 )
- // throw ParseError::Generic("Where clause with no generic params");
- Parse_WhereClause(lex, params);
- tok = lex.getToken();
- }
-
-
- AST::Trait trait( mv$(params), mv$(supertraits) );
-
- CHECK_TOK(tok, TOK_BRACE_OPEN);
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
- {
-
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, item_attrs);
-
- auto ps = lex.start_span();
- if( tok.type() == TOK_MACRO ) {
- auto inv = Parse_MacroInvocation( ps, mv$(tok.str()), lex );
- // - Silently consume ';' after the macro
- if( GET_TOK(tok, lex) != TOK_SEMICOLON )
- PUTBACK(tok, lex);
-
- trait.items().push_back( AST::Named<AST::Item>("", AST::Item(mv$(inv)), false) );
- continue ;
- }
-
- bool is_specialisable = false;
- if( tok.type() == TOK_IDENT && tok.str() == "default" ) {
- is_specialisable = true;
- GET_TOK(tok, lex);
- }
- // TODO: Mark specialisation
- (void)is_specialisable;
-
- bool fn_is_const = false;
- bool fn_is_unsafe = false;
- ::std::string abi = ABI_RUST;
- switch(tok.type())
- {
- case TOK_RWORD_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);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_SEMICOLON);
-
- // TODO: Attributes on associated statics
- trait.add_static( mv$(name), ::AST::Static(AST::Static::STATIC, mv$(ty), val)/*, mv$(item_attrs)*/ );
- 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);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_SEMICOLON);
-
- // TODO: Attributes on associated constants
- trait.add_static( mv$(name), ::AST::Static(AST::Static::CONST, mv$(ty), val)/*, mv$(item_attrs)*/ );
- break; }
- // Associated type
- case TOK_RWORD_TYPE: {
- auto atype_params = ::AST::GenericParams { };
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- if( GET_TOK(tok, lex) == TOK_COLON )
- {
- // Bounded associated type
- Parse_TypeBound(lex, atype_params, TypeRef(lex.getPosition(), "Self", 0xFFFF));
- GET_TOK(tok, lex);
- }
- if( tok.type() == TOK_RWORD_WHERE ) {
- throw ParseError::Todo(lex, "Where clause on associated type");
- }
-
- TypeRef default_type = TypeRef( lex.getPosition() );
- if( tok.type() == TOK_EQUAL ) {
- default_type = Parse_Type(lex);
- GET_TOK(tok, lex);
- }
-
- CHECK_TOK(tok, TOK_SEMICOLON);
- trait.add_type( ::std::move(name), ::std::move(default_type) );
- trait.items().back().data.as_Type().params() = mv$(atype_params);
- break; }
-
- // Functions (possibly unsafe)
- // TODO: Const?
- case TOK_RWORD_UNSAFE:
- fn_is_unsafe = true;
- if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN )
- case TOK_RWORD_EXTERN:
- {
- abi = "C";
- if( GET_TOK(tok, lex) == TOK_STRING )
- abi = tok.str();
- else
- PUTBACK(tok, lex);
-
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_RWORD_FN);
- case TOK_RWORD_FN: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string name = mv$(tok.str());
- // Self allowed, prototype-form allowed (optional names and no code)
- auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const);
- if( GET_TOK(tok, lex) == TOK_BRACE_OPEN )
- {
- PUTBACK(tok, lex);
- fcn.set_code( Parse_ExprBlock(lex) );
- }
- else if( tok.type() == TOK_SEMICOLON )
- {
- // Accept it
- }
- else
- {
- throw ParseError::Unexpected(lex, tok);
- }
- // TODO: Store `item_attrs`
- trait.add_function( ::std::move(name), /*mv$(item_attrs),*/ ::std::move(fcn) );
- break; }
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- }
-
- return trait;
-}
-
-AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items)
-{
- TRACE_FUNCTION;
-
- Token tok;
-
- tok = lex.getToken();
- // Type params supporting "where"
- AST::GenericParams params;
- if( tok.type() == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- if(GET_TOK(tok, lex) == TOK_RWORD_WHERE)
- {
- Parse_WhereClause(lex, params);
- tok = lex.getToken();
- }
- }
-
- // Body
- CHECK_TOK(tok, TOK_BRACE_OPEN);
- ::std::vector<AST::EnumVariant> variants;
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
- {
- auto sp = lex.start_span();
-
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, item_attrs);
-
- CHECK_TOK(tok, TOK_IDENT);
- ::std::string name = mv$(tok.str());
- if( GET_TOK(tok, lex) == TOK_PAREN_OPEN )
- {
- ::std::vector<TypeRef> types;
- // Get type list
- do
- {
- if(LOOK_AHEAD(lex) == TOK_PAREN_CLOSE)
- {
- GET_TOK(tok, lex);
- break;
- }
-
- AST::MetaItems field_attrs;
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
- {
- GET_TOK(tok, lex);
- field_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- types.push_back( Parse_Type(lex) );
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
- 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
- {
- if(LOOK_AHEAD(lex) == TOK_BRACE_CLOSE)
- {
- GET_TOK(tok, lex);
- break;
- }
-
- AST::MetaItems field_attrs;
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
- {
- GET_TOK(tok, lex);
- field_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- 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::StructItem(mv$(field_attrs), true, mv$(name), mv$(ty)) );
- } 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 )
- {
- auto node = Parse_Expr(lex);
- variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(node)) );
- GET_TOK(tok, lex);
- }
- else
- {
- variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), ::AST::Expr()) );
- }
-
- if( tok.type() != TOK_COMMA )
- break;
- }
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
-
- return AST::Enum( mv$(params), mv$(variants) );
-}
-
-::AST::Union Parse_Union(TokenStream& lex, AST::MetaItems& meta_items)
-{
- Token tok;
-
- TRACE_FUNCTION;
-
- AST::GenericParams params;
- if( GET_TOK(tok, lex) == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- if(GET_TOK(tok, lex) == TOK_RWORD_WHERE)
- {
- Parse_WhereClause(lex, params);
- tok = lex.getToken();
- }
- }
-
- ::std::vector< ::AST::StructItem> variants;
-
- CHECK_TOK(tok, TOK_BRACE_OPEN);
- do {
- if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) {
- GET_TOK(tok, lex);
- break ;
- }
-
- AST::MetaItems item_attrs;
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
- {
- GET_TOK(tok, lex);
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
- SET_ATTRS(lex, item_attrs);
-
- bool is_pub = false;
- if( LOOK_AHEAD(lex) == TOK_RWORD_PUB ) {
- is_pub = true;
- GET_TOK(tok, lex);
- }
-
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
-
- auto ty = Parse_Type(lex);
-
- variants.push_back( ::AST::StructItem( mv$(item_attrs), is_pub, mv$(name), mv$(ty) ) );
-
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- CHECK_TOK(tok, TOK_BRACE_CLOSE);
-
- return ::AST::Union( mv$(params), mv$(variants) );
-}
-
-/// Parse a meta-item declaration (either #![ or #[)
-AST::MetaItem Parse_MetaItem(TokenStream& lex)
-{
- TRACE_FUNCTION;
- Token tok;
- GET_TOK(tok, lex);
-
- if( tok.type() == TOK_INTERPOLATED_META ) {
- return mv$(tok.frag_meta());
- }
-
- CHECK_TOK(tok, TOK_IDENT);
- ::std::string name = mv$(tok.str());
- switch(GET_TOK(tok, lex))
- {
- case TOK_EQUAL:
- GET_CHECK_TOK(tok, lex, TOK_STRING);
- return AST::MetaItem(name, tok.str());
- case TOK_PAREN_OPEN: {
- ::std::vector<AST::MetaItem> items;
- do {
- if(LOOK_AHEAD(lex) == TOK_PAREN_CLOSE) {
- GET_TOK(tok, lex);
- break;
- }
- items.push_back(Parse_MetaItem(lex));
- } while(GET_TOK(tok, lex) == TOK_COMMA);
- CHECK_TOK(tok, TOK_PAREN_CLOSE);
- return AST::MetaItem(name, mv$(items)); }
- default:
- PUTBACK(tok, lex);
- return AST::MetaItem(name);
- }
-}
-
-::AST::Item Parse_Impl(TokenStream& lex, AST::MetaItems attrs, bool is_unsafe=false)
-{
- TRACE_FUNCTION;
- Token tok;
- auto ps = lex.start_span();
-
- AST::GenericParams params;
- // 1. (optional) type parameters
- if( GET_TOK(tok, lex) == TOK_LT )
- {
- params = Parse_GenericParams(lex);
- GET_CHECK_TOK(tok, lex, TOK_GT);
- }
- else {
- PUTBACK(tok, lex);
- }
- // 2. Either a trait name (with type params), or the type to impl
-
- Spanned<AST::Path> trait_path;
-
- // - Handle negative impls specially, which must be a trait
- // "impl !Trait for Type {}"
- if( GET_TOK(tok, lex) == TOK_EXCLAM )
- {
- trait_path = GET_SPANNED(::AST::Path, lex, Parse_Path(lex, PATH_GENERIC_TYPE));
- GET_CHECK_TOK(tok, lex, TOK_RWORD_FOR);
- auto impl_type = Parse_Type(lex, true);
-
- if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
- {
- Parse_WhereClause(lex, params);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_BRACE_OPEN);
- // negative impls can't have any content
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
-
- return ::AST::Item::make_NegImpl( AST::ImplDef(lex.end_span(ps), mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ) );
- }
-
- // - Don't care which at this stage
- PUTBACK(tok, lex);
-
- auto impl_type = Parse_Type(lex, true);
-
- if( GET_TOK(tok, lex) == TOK_RWORD_FOR )
- {
- // Trickery! All traits parse as valid types, so this works.
- if( !impl_type.is_path() )
- throw ParseError::Generic(lex, "Trait was not a path");
- trait_path = Spanned< AST::Path> {
- impl_type.span(),
- mv$(impl_type.path())
- };
- // Implementing a trait for another type, get the target type
- if( GET_TOK(tok, lex) == TOK_DOUBLE_DOT )
- {
- // Default impl
- impl_type = TypeRef(TypeRef::TagInvalid(), lex.getPosition());
- }
- else
- {
- PUTBACK(tok, lex);
- impl_type = Parse_Type(lex, true);
- }
- }
- else {
- PUTBACK(tok, lex);
- }
-
- // Where clause
- if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
- {
- Parse_WhereClause(lex, params);
- }
- else {
- PUTBACK(tok, lex);
- }
- GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
-
- while( LOOK_AHEAD(lex) == TOK_CATTR_OPEN )
- {
- GET_TOK(tok, lex);
- attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- AST::Impl impl( AST::ImplDef( lex.end_span(ps), mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ) );
-
- // A sequence of method implementations
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
- {
- auto ps = lex.start_span();
- if( tok.type() == TOK_MACRO )
- {
- impl.add_macro_invocation( Parse_MacroInvocation( ps, mv$(tok.str()), lex ) );
- // - Silently consume ';' after the macro
- if( GET_TOK(tok, lex) != TOK_SEMICOLON )
- PUTBACK(tok, lex);
- }
- else
- {
- PUTBACK(tok, lex);
- Parse_Impl_Item(lex, impl);
- }
- }
-
- return ::AST::Item::make_Impl( mv$(impl) );
-}
-
-void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
-{
- TRACE_FUNCTION;
- Token tok;
-
- GET_TOK(tok, lex);
-
- AST::MetaItems item_attrs;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- item_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, item_attrs);
-
- auto ps = lex.start_span();
-
- bool is_public = false;
- if(tok.type() == TOK_RWORD_PUB) {
- is_public = true;
- GET_TOK(tok, lex);
- }
-
- bool is_specialisable = false;
- if( tok.type() == TOK_IDENT && tok.str() == "default" ) {
- is_specialisable = true;
- GET_TOK(tok, lex);
- }
-
- ::std::string abi = ABI_RUST;
- bool fn_is_unsafe = false;
- bool fn_is_const = false;
- switch(tok.type())
- {
- case TOK_RWORD_TYPE: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_EQUAL);
- impl.add_type(is_public, is_specialisable, name, Parse_Type(lex));
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- break; }
- case TOK_RWORD_UNSAFE:
- fn_is_unsafe = true;
- GET_TOK(tok, lex);
- if( tok.type() == TOK_RWORD_CONST )
- case TOK_RWORD_CONST:
- {
- GET_TOK(tok, lex);
- if( tok.type() != TOK_RWORD_FN && tok.type() != TOK_RWORD_UNSAFE && !fn_is_unsafe )
- {
- 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);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
-
- auto i = ::AST::Static(AST::Static::CONST, mv$(ty), mv$(val));
- // TODO: Attributes on associated constants
- impl.add_static( is_public, is_specialisable, mv$(name), mv$(i) /*, mv$(item_attrs)*/ );
- break ;
- }
- else if( tok.type() == TOK_RWORD_UNSAFE )
- {
- fn_is_unsafe = true;
- GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
- }
- fn_is_const = true;
- }
- if( tok.type() == TOK_RWORD_EXTERN )
- // FALL
- case TOK_RWORD_EXTERN:
- {
- abi = "C";
- if( GET_TOK(tok, lex) == TOK_STRING )
- abi = tok.str();
- else
- PUTBACK(tok, lex);
-
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_RWORD_FN);
- // FALL
- case TOK_RWORD_FN: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- // TODO: Hygine on function names? - Not in impl blocks?
- ::std::string name = mv$(tok.str());
- DEBUG("Function " << name);
- // - Self allowed, can't be prototype-form
- auto fcn = Parse_FunctionDefWithCode(lex, abi, true, fn_is_unsafe, fn_is_const);
- impl.add_function(is_public, is_specialisable, mv$(name), mv$(fcn));
- break; }
-
- default:
- throw ParseError::Unexpected(lex, tok);
- }
-
- impl.items().back().data->span = lex.end_span(ps);
- impl.items().back().data->attrs = mv$(item_attrs); // Empty for functions
-}
-
-AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::MetaItems& block_attrs)
-{
- TRACE_FUNCTION;
- Token tok;
-
- while( GET_TOK(tok, lex) == TOK_CATTR_OPEN )
- {
- block_attrs.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
- PUTBACK(tok, lex);
-
- AST::ExternBlock rv { abi };
-
- while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
- {
- AST::MetaItems meta_items;
- while( tok.type() == TOK_ATTR_OPEN )
- {
- meta_items.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- GET_TOK(tok, lex);
- }
- SET_ATTRS(lex, meta_items);
-
- auto ps = lex.start_span();
-
- bool is_public = false;
- if( tok.type() == TOK_RWORD_PUB ) {
- is_public = true;
- GET_TOK(tok, lex);
- }
- switch(tok.type())
- {
- case TOK_RWORD_FN: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- // parse function as prototype
- // - no self, is prototype, is unsafe and not const
- auto i = ::AST::Item( Parse_FunctionDef(lex, abi, false, true, true,false) );
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
-
- i.attrs = mv$(meta_items);
- i.span = lex.end_span(ps);
-
- rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
- break; }
- case TOK_RWORD_STATIC: {
- bool is_mut = false;
- if( GET_TOK(tok, lex) == TOK_RWORD_MUT )
- is_mut = true;
- else
- PUTBACK(tok, lex);
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- auto type = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
-
- auto i = ::AST::Item(::AST::Static( (is_mut ? ::AST::Static::MUT : ::AST::Static::STATIC), mv$(type), ::AST::Expr() ));
- i.attrs = mv$(meta_items);
- i.span = lex.end_span(ps);
- rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
- break; }
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC});
- }
- }
-
- return rv;
-}
-
-void Parse_Use_Wildcard(Span sp, AST::Path base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
-{
- fcn( AST::UseStmt(mv$(sp), mv$(base_path)), "" ); // HACK! Empty path indicates wilcard import
-}
-void Parse_Use_Set(TokenStream& lex, const ProtoSpan& ps, const AST::Path& base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
-{
- TRACE_FUNCTION;
-
- Token tok;
- do {
- AST::Path path;
- ::std::string name;
- if( GET_TOK(tok, lex) == TOK_RWORD_SELF ) {
- path = ::AST::Path(base_path);
- name = base_path[base_path.size()-1].name();
- }
- else if( tok.type() == TOK_BRACE_CLOSE ) {
- break ;
- }
- else {
- CHECK_TOK(tok, TOK_IDENT);
- path = base_path + AST::PathNode(tok.str(), {});
- name = mv$(tok.str());
- }
-
- if( GET_TOK(tok, lex) == TOK_RWORD_AS ) {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- name = mv$(tok.str());
- }
- else {
- PUTBACK(tok, lex);
- }
- fcn(AST::UseStmt(lex.end_span(ps), mv$(path)), mv$(name));
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- PUTBACK(tok, lex);
-}
-
-void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
-{
- TRACE_FUNCTION;
-
- Token tok;
- AST::Path path = AST::Path("", {});
- ::std::vector<AST::PathNode> nodes;
- ProtoSpan span_start = lex.start_span();
-
- switch( GET_TOK(tok, lex) )
- {
- case TOK_RWORD_SELF:
- path = AST::Path( AST::Path::TagSelf(), {} ); // relative path
- break;
- case TOK_RWORD_SUPER: {
- unsigned int count = 1;
- while( LOOK_AHEAD(lex) == TOK_DOUBLE_COLON && lex.lookahead(1) == TOK_RWORD_SUPER ) {
- GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
- GET_CHECK_TOK(tok, lex, TOK_RWORD_SUPER);
- count += 1;
- }
- path = AST::Path( AST::Path::TagSuper(), count, {} );
- break; }
- case TOK_IDENT:
- path.append( AST::PathNode(mv$(tok.str()), {}) );
- break;
- // Leading :: is allowed and ignored for the $crate feature
- case TOK_DOUBLE_COLON:
- // Absolute path
- // HACK! mrustc emits $crate as `::"crate-name"`
- if( LOOK_AHEAD(lex) == TOK_STRING )
- {
- GET_CHECK_TOK(tok, lex, TOK_STRING);
- path = ::AST::Path(tok.str(), {});
- GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
- }
- else {
- PUTBACK(tok, lex);
- }
- break;
- case TOK_BRACE_OPEN:
- Parse_Use_Set(lex, span_start, path, fcn);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- return;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON )
- {
- if( GET_TOK(tok, lex) == TOK_IDENT )
- {
- path.append( AST::PathNode( mv$(tok.str()), {}) );
- }
- else
- {
- //path.set_span( lex.end_span(span_start) );
- switch( tok.type() )
- {
- case TOK_BRACE_OPEN:
- Parse_Use_Set(lex, span_start, mv$(path), fcn);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- break ;
- case TOK_STAR:
- Parse_Use_Wildcard( lex.end_span(span_start), mv$(path), fcn );
- break ;
- default:
- throw ParseError::Unexpected(lex, tok);
- }
- // early return - This branch is either the end of the use statement, or a syntax error
- return ;
- }
- }
- //path.set_span( lex.end_span(span_start) );
-
- ::std::string name;
- // This should only be allowed if the last token was an ident
- // - Above checks ensure this
- if( tok.type() == TOK_RWORD_AS )
- {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- name = mv$(tok.str());
- }
- else
- {
- PUTBACK(tok, lex);
- assert(path.nodes().size() > 0);
- name = path.nodes().back().name();
- }
-
- fcn( AST::UseStmt(lex.end_span(span_start), mv$(path)), name);
-}
-
-
-::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, ::std::string name, TokenStream& lex)
-{
- Token tok;
- ::std::string ident;
- if( GET_TOK(tok, lex) == TOK_IDENT ) {
- ident = mv$(tok.str());
- }
- else {
- PUTBACK(tok, lex);
- }
- DEBUG("name=" << name << ", ident=" << ident);
- TokenTree tt = Parse_TT(lex, true);
- return ::AST::MacroInvocation( lex.end_span(span_start), mv$(name), mv$(ident), mv$(tt));
-}
-
-::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::MetaItems meta_items)
-{
- TRACE_FUNCTION_F("mod_path="<<mod_path<<", meta_items="<<meta_items);
- Token tok;
-
- while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN /* || LOOKAHEAD2(lex, TOK_HASH, TOK_SQUARE_OPEN) */ )
- {
- // Attributes!
- GET_CHECK_TOK(tok, lex, TOK_ATTR_OPEN);
- meta_items.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
-
- if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_ITEM ) {
- GET_TOK(tok, lex);
- auto rv = tok.take_frag_item();
- // Transfer new attributes onto the item
- for(auto& mi : meta_items.m_items)
- rv.data.attrs.m_items.push_back( mv$(mi) );
- return rv;
- }
-
- auto ps = lex.start_span();
-
- ::std::string item_name;
- ::AST::Item item_data;
-
- if( LOOK_AHEAD(lex) == TOK_MACRO ) {
- GET_TOK(tok, lex);
-
- ::std::string name = mv$(tok.str());
- bool is_braced = (LOOK_AHEAD(lex) == TOK_BRACE_OPEN || LOOKAHEAD2(lex, TOK_IDENT, TOK_BRACE_OPEN));
- item_data = ::AST::Item( Parse_MacroInvocation( ps, mv$(name), lex ) );
-
- if( !is_braced ) {
- // - Consume the ';' after the macro
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- }
-
- item_data.attrs = mv$(meta_items);
- item_data.span = lex.end_span(ps);
-
- return ::AST::Named< ::AST::Item> { "", mv$(item_data), false };
- }
-
- bool is_public = false;
- if( GET_TOK(tok, lex) == TOK_RWORD_PUB ) {
- is_public = true;
- }
- else {
- PUTBACK(tok, lex);
- }
-
- switch( GET_TOK(tok, lex) )
- {
- case TOK_RWORD_USE:
- // NOTE: The only problem here is with things like `use foo::{a, b, c}` - all others are a single statement.
- // - These are caught by the condition in the closure
- Parse_Use(lex, [&](AST::UseStmt p, std::string s) {
- DEBUG(mod_path << " - use " << p << " as '" << s << "'");
- if( !item_data.is_None() )
- TODO(lex.getPosition(), "Encode multi-item use statements as a single Item");
- item_data = ::AST::Item(mv$(p));
- item_name = mv$(s);
- });
- assert( !item_data.is_None() );
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- break;
-
- case TOK_RWORD_EXTERN:
- switch( GET_TOK(tok, lex) )
- {
- // `extern "<ABI>" fn ...`
- // `extern "<ABI>" { ...`
- case TOK_STRING: {
- ::std::string abi = tok.str();
- switch(GET_TOK(tok, lex))
- {
- // `extern "<ABI>" fn ...`
- case TOK_RWORD_FN: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, false,false) );
- break; }
- // `extern "ABI" {`
- case TOK_BRACE_OPEN:
- item_name = "";
- item_data = ::AST::Item( Parse_ExternBlock(lex, mv$(abi), meta_items) );
- break;
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_BRACE_OPEN});
- }
- break; }
- // `extern fn ...`
- case TOK_RWORD_FN:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, "C", false, false,false) );
- break;
-
- // NOTE: `extern { ...` is handled in caller
- case TOK_BRACE_OPEN:
- item_name = "";
- item_data = ::AST::Item( Parse_ExternBlock(lex, "C", meta_items) );
- break;
-
- // `extern crate "crate-name" as crate_name;`
- // `extern crate crate_name;`
- // `extern crate crate_name as other_name;`
- case TOK_RWORD_CRATE:
- switch( GET_TOK(tok, lex) )
- {
- // `extern crate "crate-name" as crate_name;`
- // NOTE: rustc doesn't allow this, keep in mrustc for for reparse support
- case TOK_STRING:
- item_data = ::AST::Item::make_Crate({ tok.str() });
- GET_CHECK_TOK(tok, lex, TOK_RWORD_AS);
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- break;
- // `extern crate crate_name;`
- // `extern crate crate_name as other_name;`
- case TOK_IDENT:
- item_name = mv$(tok.str());
- if(GET_TOK(tok, lex) == TOK_RWORD_AS) {
- item_data = ::AST::Item::make_Crate({ mv$(item_name) });
-
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- }
- else {
- PUTBACK(tok, lex);
- item_data = ::AST::Item::make_Crate({ item_name });
- }
- break;
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_IDENT});
- }
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- break;
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_RWORD_FN, TOK_BRACE_OPEN, TOK_RWORD_CRATE});
- }
- break;
-
- // `const NAME`
- // `const [unsafe] fn`
- case TOK_RWORD_CONST:
- switch( GET_TOK(tok, lex) )
- {
- case TOK_IDENT: {
- item_name = mv$(tok.str());
-
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- TypeRef type = Parse_Type(lex);
- GET_CHECK_TOK(tok, lex, TOK_EQUAL);
- AST::Expr val = Parse_Expr(lex);
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- item_data = ::AST::Item( ::AST::Static(AST::Static::CONST, mv$(type), mv$(val)) );
- break; }
- case TOK_RWORD_UNSAFE:
- GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,true/*unsafe,const*/) );
- break;
- case TOK_RWORD_FN:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- // - self not allowed, not prototype
- item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,true/*unsafe,const*/) );
- break;
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_RWORD_FN});
- }
- break;
- // `static NAME`
- // `static mut NAME`
- case TOK_RWORD_STATIC: {
- bool is_mut = false;
- if(GET_TOK(tok, lex) == TOK_RWORD_MUT) {
- is_mut = true;
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_IDENT);
- item_name = mv$(tok.str());
-
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- TypeRef type = Parse_Type(lex);
-
- GET_CHECK_TOK(tok, lex, TOK_EQUAL);
-
- AST::Expr val = Parse_Expr(lex);
-
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- item_data = ::AST::Item( ::AST::Static( (is_mut ? AST::Static::MUT : AST::Static::STATIC), mv$(type), mv$(val)) );
- break; }
-
- // `unsafe fn`
- // `unsafe trait`
- // `unsafe impl`
- case TOK_RWORD_UNSAFE:
- 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 {
- PUTBACK(tok, lex);
- }
- GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, true,false/*unsafe,const*/) );
- break; }
- // `unsafe fn`
- case TOK_RWORD_FN:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- // - self not allowed, not prototype
- item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,false/*unsafe,const*/) );
- break;
- // `unsafe trait`
- case TOK_RWORD_TRAIT:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- // TODO: Mark as unsafe
- meta_items.push_back( AST::MetaItem("#UNSAFE") );
- item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) );
- break;
- // `unsafe impl`
- case TOK_RWORD_IMPL:
- return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items), true), false };
- default:
- throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_TRAIT, TOK_RWORD_IMPL});
- }
- break;
- // `fn`
- case TOK_RWORD_FN:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- // - self not allowed, not prototype
- item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,false/*unsafe,const*/) );
- break;
- // `type`
- case TOK_RWORD_TYPE:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_TypeAlias(lex) );
- break;
- // `struct`
- case TOK_RWORD_STRUCT:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_Struct(lex, meta_items) );
- break;
- // `enum`
- case TOK_RWORD_ENUM:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_EnumDef(lex, meta_items) );
- break;
- // Contextual keywords
- case TOK_IDENT:
- if( tok.str() == "union" ) {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_Union(lex, meta_items) );
- }
- else {
- throw ParseError::Unexpected(lex, tok);
- }
- break;
- // `impl`
- case TOK_RWORD_IMPL:
- return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items)), false };
- // `trait`
- case TOK_RWORD_TRAIT:
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
- item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) );
- break;
-
- case TOK_RWORD_MOD: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- DEBUG("Sub module '" << name << "'");
- AST::Module submod( mod_path + name );
-
- // Rules for external files (/ path handling):
- // - IF using stdin (path='-') - Disallow and propagate '-' as path
- // - IF a #[path] attribute was passed, allow
- // - IF in crate root or mod.rs, allow (input flag)
- // - else, disallow and set flag
- ::std::string path_attr = (meta_items.has("path") ? meta_items.get("path")->string() : "");
-
- //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON);
-
- ::std::string sub_path;
- bool sub_file_controls_dir = true;
- if( mod_fileinfo.path == "-" ) {
- if( path_attr.size() ) {
- ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin");
- }
- sub_path = "-";
- }
- else if( path_attr.size() > 0 )
- {
- sub_path = dirname(mod_fileinfo.path) + path_attr;
- }
- else if( mod_fileinfo.controls_dir )
- {
- sub_path = dirname(mod_fileinfo.path) + name;
- }
- else
- {
- sub_path = mod_fileinfo.path;
- sub_file_controls_dir = false;
- }
- DEBUG("Mod '" << name << "', sub_path = " << sub_path);
-
- submod.m_file_info.path = sub_path;
- submod.m_file_info.controls_dir = sub_file_controls_dir;
-
- // Check #[cfg] and don't load if it fails
- struct H {
- static bool check_item_cfg(const ::AST::MetaItems& attrs)
- {
- for(const auto& at : attrs.m_items) {
- if( at.name() == "cfg" && !check_cfg(attrs.m_span, at) ) {
- return false;
- }
- }
- return true;
- }
- };
-
- switch( GET_TOK(tok, lex) )
- {
- case TOK_BRACE_OPEN:
- submod.m_file_info.path = sub_path + "/";
- Parse_ModRoot(lex, submod, meta_items);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- break;
- case TOK_SEMICOLON:
- if( sub_path == "-" ) {
- ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin");
- }
- else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir )
- {
- ERROR(lex.getPosition(), E0000, "Can't load from files outside of mod.rs or crate root");
- }
- else if( !H::check_item_cfg(meta_items) ) {
- // Ignore - emit Item::None
- item_name = mv$(name);
- item_data = ::AST::Item( );
- break ;
- }
- else
- {
- ::std::string newpath_dir = sub_path + "/";
- ::std::string newpath_file = path_attr.size() > 0 ? sub_path : sub_path + ".rs";
- DEBUG("newpath_dir = '" << newpath_dir << "', newpath_file = '" << newpath_file << "'");
- ::std::ifstream ifs_dir (newpath_dir + "mod.rs");
- ::std::ifstream ifs_file(newpath_file);
- if( ifs_dir.is_open() && ifs_file.is_open() )
- {
- // Collision
- ERROR(lex.getPosition(), E0000, "Both modname.rs and modname/mod.rs exist");
- }
- else if( ifs_dir.is_open() )
- {
- // Load from dir
- submod.m_file_info.path = newpath_dir + "mod.rs";
- }
- else if( ifs_file.is_open() )
- {
- submod.m_file_info.path = newpath_file;
- }
- else
- {
- // Can't find file
- ERROR(lex.getPosition(), E0000, "Can't find file for '" << name << "' in '" << mod_fileinfo.path << "'");
- }
- DEBUG("- path = " << submod.m_file_info.path);
- Lexer sub_lex(submod.m_file_info.path);
- Parse_ModRoot(sub_lex, submod, meta_items);
- GET_CHECK_TOK(tok, sub_lex, TOK_EOF);
- }
- break;
- default:
- throw ParseError::Generic("Expected { or ; after module name");
- }
- item_name = mv$(name);
- item_data = ::AST::Item( mv$(submod) );
- break; }
-
- default:
- throw ParseError::Unexpected(lex, tok);
- }
-
- item_data.attrs = mv$(meta_items);
- item_data.span = lex.end_span(ps);
-
- return ::AST::Named< ::AST::Item> { mv$(item_name), mv$(item_data), is_public };
-}
-
-void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items)
-{
- SET_MODULE(lex, mod);
- lex.parse_state().parent_attrs = &meta_items;
-
- //TRACE_FUNCTION;
- Token tok;
-
- // `use ...`
- if( LOOK_AHEAD(lex) == TOK_RWORD_USE || (lex.lookahead(0) == TOK_RWORD_PUB && lex.lookahead(1) == TOK_RWORD_USE) )
- {
- bool is_public = false;
- if( GET_TOK(tok, lex) == TOK_RWORD_PUB ) {
- is_public = true;
- GET_TOK(tok, lex);
- }
-
- Parse_Use(lex, [&mod,is_public,&meta_items](AST::UseStmt p, std::string s) {
- DEBUG(mod.path() << " - use " << p << " as '" << s << "'");
- mod.add_alias(is_public, mv$(p), s, meta_items.clone());
- });
- GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
- }
- else
- {
- mod.add_item( Parse_Mod_Item_S(lex, mod.m_file_info, mod.path(), mv$(meta_items)) );
- }
-}
-
-void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod)
-{
- Token tok;
-
- for(;;)
- {
- // Check 1 - End of module (either via a closing brace, or EOF)
- switch(GET_TOK(tok, lex))
- {
- case TOK_BRACE_CLOSE:
- case TOK_EOF:
- PUTBACK(tok, lex);
- return;
- default:
- PUTBACK(tok, lex);
- break;
- }
-
- // Attributes on the following item
- AST::MetaItems meta_items;
- while( GET_TOK(tok, lex) == TOK_ATTR_OPEN )
- {
- meta_items.push_back( Parse_MetaItem(lex) );
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
- }
- PUTBACK(tok, lex);
- DEBUG("meta_items = " << meta_items);
-
- Parse_Mod_Item(lex, mod, mv$(meta_items));
- }
-}
-
-void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::MetaItems& mod_attrs)
-{
- TRACE_FUNCTION;
-
- Token tok;
-
- // Attributes on module/crate (will continue loop)
- while( GET_TOK(tok, lex) == TOK_CATTR_OPEN )
- {
- AST::MetaItem item = Parse_MetaItem(lex);
- GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
-
- mod_attrs.push_back( mv$(item) );
- }
- PUTBACK(tok, lex);
-
- Parse_ModRoot_Items(lex, mod);
-}
-
-AST::Crate Parse_Crate(::std::string mainfile)
-{
- Token tok;
-
- Lexer lex(mainfile);
-
- size_t p = mainfile.find_last_of('/');
- ::std::string mainpath = (p != ::std::string::npos ? ::std::string(mainfile.begin(), mainfile.begin()+p+1) : "./");
-
- AST::Crate crate;
-
- crate.root_module().m_file_info.path = mainpath;
- crate.root_module().m_file_info.controls_dir = true;
-
- Parse_ModRoot(lex, crate.root_module(), crate.m_attrs);
-
- return crate;
-}
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * parse/root.cpp
+ * - Parsing at the module level (highest-level parsing)
+ *
+ * Entrypoint:
+ * - Parse_Crate : Handles crate attrbutes, and passes on to Parse_ModRoot
+ * - Parse_ModRoot
+ */
+#include <ast/ast.hpp>
+#include <ast/crate.hpp>
+#include "parseerror.hpp"
+#include "common.hpp"
+#include <cassert>
+#include <hir/hir.hpp> // ABI_RUST - TODO: Move elsewhere?
+#include <expand/cfg.hpp> // check_cfg - for `mod nonexistant;`
+#include <fstream> // Used by directory path
+#include "lex.hpp" // New file lexer
+
+template<typename T>
+Spanned<T> get_spanned(TokenStream& lex, ::std::function<T()> f) {
+ auto ps = lex.start_span();
+ auto v = f();
+ return Spanned<T> {
+ lex.end_span(ps),
+ mv$(v)
+ };
+}
+#define GET_SPANNED(type, lex, val) get_spanned< type >(lex, [&](){ return val; })
+
+// Check the next two tokens
+#define LOOKAHEAD2(lex, tok1, tok2) ((lex).lookahead(0) == (tok1) && (lex).lookahead(1) == (tok2))
+
+::std::string dirname(::std::string input) {
+ while( input.size() > 0 && input.back() != '/' ) {
+ input.pop_back();
+ }
+ return input;
+}
+
+AST::MetaItem Parse_MetaItem(TokenStream& lex);
+void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::MetaItems& mod_attrs);
+
+::std::vector< ::std::string> Parse_HRB(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ ::std::vector< ::std::string> lifetimes;
+ GET_CHECK_TOK(tok, lex, TOK_LT);
+ do {
+ GET_TOK(tok, lex);
+
+ ::AST::MetaItems attrs;
+ while(tok.type() == TOK_ATTR_OPEN)
+ {
+ attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ GET_TOK(tok, lex);
+ }
+ (void)attrs; // TODO: Attributes on generic params
+
+ switch(tok.type())
+ {
+ 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);
+ return lifetimes;
+}
+/// Parse type parameters in a definition
+void Parse_TypeBound(TokenStream& lex, AST::GenericParams& ret, TypeRef checked_type, ::std::vector< ::std::string> lifetimes = {})
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ do
+ {
+ ::std::vector< ::std::string> hrls;
+ if(GET_TOK(tok, lex) == TOK_LIFETIME) {
+ ret.add_bound(AST::GenericBound::make_TypeLifetime( {
+ checked_type.clone(), tok.str()
+ } ));
+ }
+ else if( tok.type() == TOK_QMARK ) {
+ ret.add_bound(AST::GenericBound::make_MaybeTrait( {
+ checked_type.clone(), Parse_Path(lex, PATH_GENERIC_TYPE)
+ } ));
+ }
+ else {
+ if( tok.type() == TOK_RWORD_FOR )
+ {
+ hrls = Parse_HRB(lex);
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+ (void)hrls; // TODO: HRLs
+
+ ret.add_bound( AST::GenericBound::make_IsTrait({
+ checked_type.clone(), mv$(lifetimes), Parse_Path(lex, PATH_GENERIC_TYPE)
+ }) );
+ }
+ } while( GET_TOK(tok, lex) == TOK_PLUS );
+ PUTBACK(tok, lex);
+}
+
+/// Parse type parameters within '<' and '>' (definition)
+AST::GenericParams Parse_GenericParams(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+
+ AST::GenericParams ret;
+ Token tok;
+ do {
+ if( GET_TOK(tok, lex) == TOK_GT ) {
+ break ;
+ }
+
+ ::AST::MetaItems attrs;
+ while(tok.type() == TOK_ATTR_OPEN)
+ {
+ attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ GET_TOK(tok, lex);
+ }
+ (void)attrs; // TODO: Attributes on generic params
+
+ if( tok.type() == TOK_IDENT )
+ {
+ // TODO: Hygine
+ ::std::string param_name = mv$(tok.str());
+ ret.add_ty_param( AST::TypeParam( param_name ) );
+
+ auto param_ty = TypeRef(lex.getPosition(), param_name);
+ if( GET_TOK(tok, lex) == TOK_COLON )
+ {
+ Parse_TypeBound(lex, ret, mv$(param_ty));
+ GET_TOK(tok, lex);
+ }
+
+ if( tok.type() == TOK_EQUAL )
+ {
+ ret.ty_params().back().setDefault( Parse_Type(lex) );
+ GET_TOK(tok, lex);
+ }
+ }
+ else if( tok.type() == TOK_LIFETIME )
+ {
+ // TODO: Should lifetimes have hygine?
+ ::std::string param_name = tok.str();
+ ret.add_lft_param( param_name );
+ if( GET_TOK(tok, lex) == TOK_COLON )
+ {
+ do {
+ GET_CHECK_TOK(tok, lex, TOK_LIFETIME);
+ ret.add_bound(AST::GenericBound::make_Lifetime( {param_name, tok.str()} ));
+ } while( GET_TOK(tok, lex) == TOK_PLUS );
+ }
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_LIFETIME});
+ }
+ } while( tok.type() == TOK_COMMA );
+ PUTBACK(tok, lex);
+ return ret;
+}
+
+
+/// Parse the contents of a 'where' clause
+void Parse_WhereClause(TokenStream& lex, AST::GenericParams& params)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ do {
+ GET_TOK(tok, lex);
+ if( tok.type() == TOK_BRACE_OPEN ) {
+ break;
+ }
+
+ if( tok.type() == TOK_LIFETIME )
+ {
+ auto lhs = mv$(tok.str());
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ do {
+ GET_CHECK_TOK(tok, lex, TOK_LIFETIME);
+ auto rhs = mv$(tok.str());
+ params.add_bound( AST::GenericBound::make_Lifetime({lhs, rhs}) );
+ } while( GET_TOK(tok, lex) == TOK_PLUS );
+ PUTBACK(tok, lex);
+ }
+ // Higher-ranked types/lifetimes
+ else if( tok.type() == TOK_RWORD_FOR )
+ {
+ ::std::vector< ::std::string> lifetimes = Parse_HRB(lex);
+
+ TypeRef type = Parse_Type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ Parse_TypeBound(lex,params, mv$(type), mv$(lifetimes));
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ TypeRef type = Parse_Type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ Parse_TypeBound(lex, params, mv$(type));
+ }
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ PUTBACK(tok, lex);
+}
+
+// Parse a single function argument
+::std::pair< AST::Pattern, TypeRef> Parse_Function_Arg(TokenStream& lex, bool expect_named)
+{
+ TRACE_FUNCTION_F("expect_named = " << expect_named);
+ Token tok;
+
+ AST::Pattern pat;
+
+ // If any of the following
+ // - Expecting a named parameter (i.e. defining a function in root or impl)
+ // - Next token is an underscore (only valid as a pattern here)
+ // - Next token is 'mut' (a mutable parameter slot)
+ // - Next two are <ident> ':' (a trivial named parameter)
+ // NOTE: When not expecting a named param, destructuring patterns are not allowed
+ if( expect_named
+ || LOOK_AHEAD(lex) == TOK_UNDERSCORE
+ || LOOK_AHEAD(lex) == TOK_RWORD_MUT
+ || (LOOK_AHEAD(lex) == TOK_IDENT && lex.lookahead(1) == TOK_COLON)
+ )
+ {
+ // Function args can't be refuted
+ pat = Parse_Pattern(lex, false);
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ }
+
+ TypeRef type = Parse_Type(lex);
+
+
+ return ::std::make_pair( ::std::move(pat), ::std::move(type) );
+}
+
+/// Parse a function definition (after the 'fn <name>')
+AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_self, bool can_be_prototype, bool is_unsafe, bool is_const)
+{
+ TRACE_FUNCTION;
+ ProtoSpan ps = lex.start_span();
+
+ Token tok;
+
+ // Parameters
+ AST::GenericParams params;
+ if( GET_TOK(tok, lex) == TOK_LT )
+ {
+ params = Parse_GenericParams(lex);
+ GET_CHECK_TOK(tok, lex, TOK_GT);
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+
+ AST::Function::Arglist args;
+
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
+ GET_TOK(tok, lex);
+
+ // Handle self
+ if( tok.type() == TOK_AMP )
+ {
+ // By-reference method?
+ // TODO: If a lifetime is seen (and not a prototype), it is definitely a self binding
+
+ unsigned int ofs = 0;
+ if( lex.lookahead(0) == TOK_LIFETIME )
+ ofs ++;
+
+ if( lex.lookahead(ofs) == TOK_RWORD_SELF || (lex.lookahead(ofs) == TOK_RWORD_MUT && lex.lookahead(ofs+1) == TOK_RWORD_SELF) )
+ {
+ auto ps = lex.start_span();
+ ::std::string lifetime;
+ if( GET_TOK(tok, lex) == TOK_LIFETIME ) {
+ lifetime = tok.str();
+ GET_TOK(tok, lex);
+ }
+ auto ty_sp = lex.end_span(ps);
+
+ if( tok.type() == TOK_RWORD_MUT )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_SELF);
+ args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, true, TypeRef(ty_sp, "Self", 0xFFFF))) );
+ }
+ else
+ {
+ args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), TypeRef(TypeRef::TagReference(), ty_sp, false, TypeRef(ty_sp, "Self", 0xFFFF))) );
+ }
+ DEBUG("TODO: UFCS / self lifetimes");
+ if( allow_self == false )
+ throw ParseError::Generic(lex, "Self binding not expected");
+ //args.push_back( ::std::make_pair(
+ // AST::Pattern(),
+ // TypeRef(TypeRef::TagReference(), lifetime, (fcn_class == AST::Function::CLASS_MUTMETHOD), )
+ //) );
+
+ // Prime tok for next step
+ GET_TOK(tok, lex);
+ }
+ else
+ {
+ // Unbound method
+ }
+ }
+ else if( tok.type() == TOK_RWORD_MUT )
+ {
+ if( LOOK_AHEAD(lex) == TOK_RWORD_SELF )
+ {
+ GET_TOK(tok, lex);
+ if( allow_self == false )
+ throw ParseError::Generic(lex, "Self binding not expected");
+ TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF );
+ if( GET_TOK(tok, lex) == TOK_COLON ) {
+ // Typed mut self
+ ty = Parse_Type(lex);
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+ args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), mv$(ty)) );
+ GET_TOK(tok, lex);
+ }
+ }
+ else if( tok.type() == TOK_RWORD_SELF )
+ {
+ // By-value method
+ if( allow_self == false )
+ throw ParseError::Generic(lex, "Self binding not expected");
+ TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF );
+ if( GET_TOK(tok, lex) == TOK_COLON ) {
+ // Typed mut self
+ ty = Parse_Type(lex);
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+ args.push_back( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "self"), mv$(ty)) );
+ GET_TOK(tok, lex);
+ }
+ else
+ {
+ // Unbound method
+ }
+
+ bool is_variadic = false;
+ if( tok.type() != TOK_PAREN_CLOSE )
+ {
+ // Comma after self
+ if( args.size() )
+ {
+ CHECK_TOK(tok, TOK_COMMA);
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+
+ // Argument list
+ do {
+ if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE ) {
+ GET_TOK(tok, lex);
+ break;
+ }
+ if( LOOK_AHEAD(lex) == TOK_TRIPLE_DOT ) {
+ GET_TOK(tok, lex);
+ is_variadic = true;
+ GET_TOK(tok, lex);
+ break;
+ }
+ args.push_back( Parse_Function_Arg(lex, !can_be_prototype) );
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ CHECK_TOK(tok, TOK_PAREN_CLOSE);
+ }
+ else {
+ // Eat 'tok', negative comparison
+ }
+
+ TypeRef ret_type = TypeRef(TypeRef::TagUnit(), Span(tok.get_pos()));
+ if( GET_TOK(tok, lex) == TOK_THINARROW )
+ {
+ // Return type
+ ret_type = Parse_Type(lex);
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ }
+
+ if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
+ {
+ Parse_WhereClause(lex, params);
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+
+ return AST::Function(lex.end_span(ps), mv$(params), mv$(abi), is_unsafe, is_const, is_variadic, mv$(ret_type), mv$(args));
+}
+
+AST::Function Parse_FunctionDefWithCode(TokenStream& lex, ::std::string abi, bool allow_self, bool is_unsafe, bool is_const)
+{
+ Token tok;
+ auto ret = Parse_FunctionDef(lex, abi, allow_self, false, is_unsafe, is_const);
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
+ PUTBACK(tok, lex);
+ ret.set_code( Parse_ExprBlock(lex) );
+ return ret;
+}
+
+AST::TypeAlias Parse_TypeAlias(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+
+ // Params
+ AST::GenericParams params;
+ if( GET_TOK(tok, lex) == TOK_LT )
+ {
+ params = Parse_GenericParams(lex);
+ GET_CHECK_TOK(tok, lex, TOK_GT);
+ GET_TOK(tok, lex);
+ }
+
+ if( tok.type() == TOK_RWORD_WHERE )
+ {
+ Parse_WhereClause(lex, params);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_EQUAL);
+
+ // Type
+ TypeRef type = Parse_Type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+
+ return AST::TypeAlias( ::std::move(params), ::std::move(type) );
+}
+
+AST::Struct Parse_Struct(TokenStream& lex, const AST::MetaItems& meta_items)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+
+ tok = lex.getToken();
+ AST::GenericParams params;
+ if( tok.type() == TOK_LT )
+ {
+ params = Parse_GenericParams(lex);
+ GET_CHECK_TOK(tok, lex, TOK_GT);
+ if(GET_TOK(tok, lex) == TOK_RWORD_WHERE)
+ {
+ Parse_WhereClause(lex, params);
+ tok = lex.getToken();
+ }
+ }
+ if(tok.type() == TOK_PAREN_OPEN)
+ {
+ // Tuple structs
+ ::std::vector<AST::TupleItem> refs;
+ while(GET_TOK(tok, lex) != TOK_PAREN_CLOSE)
+ {
+ AST::MetaItems item_attrs;
+ while( tok.type() == TOK_ATTR_OPEN )
+ {
+ item_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ GET_TOK(tok, lex);
+ }
+ SET_ATTRS(lex, item_attrs);
+
+ bool is_pub = false;
+ if(tok.type() == TOK_RWORD_PUB)
+ is_pub = true;
+ else
+ PUTBACK(tok, lex);
+
+ refs.push_back( AST::TupleItem( mv$(item_attrs), is_pub, Parse_Type(lex) ) );
+ if( GET_TOK(tok, lex) != TOK_COMMA )
+ break;
+ }
+ CHECK_TOK(tok, TOK_PAREN_CLOSE);
+
+ if(LOOK_AHEAD(lex) == TOK_RWORD_WHERE)
+ {
+ GET_TOK(tok, lex);
+ Parse_WhereClause(lex, params);
+ }
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ //if( refs.size() == 0 )
+ // WARNING( , W000, "Use 'struct Name;' instead of 'struct Name();' ... ning-nong");
+ return AST::Struct(mv$(params), mv$(refs));
+ }
+ else if(tok.type() == TOK_SEMICOLON)
+ {
+ // Unit-like struct
+ return AST::Struct(mv$(params), ::std::vector<AST::TupleItem>());
+ }
+ else if(tok.type() == TOK_BRACE_OPEN)
+ {
+ ::std::vector<AST::StructItem> items;
+ while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
+ {
+ AST::MetaItems item_attrs;
+ while( tok.type() == TOK_ATTR_OPEN )
+ {
+ item_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ GET_TOK(tok, lex);
+ }
+ SET_ATTRS(lex, item_attrs);
+
+ bool is_pub = false;
+ if(tok.type() == TOK_RWORD_PUB) {
+ is_pub = true;
+ GET_TOK(tok, lex);
+ }
+
+ CHECK_TOK(tok, TOK_IDENT);
+ auto name = mv$(tok.str());
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ TypeRef type = Parse_Type(lex);
+
+ items.push_back( AST::StructItem( mv$(item_attrs), is_pub, mv$(name), mv$(type) ) );
+ if(GET_TOK(tok, lex) == TOK_BRACE_CLOSE)
+ break;
+ CHECK_TOK(tok, TOK_COMMA);
+ }
+ //if( items.size() == 0 )
+ // WARNING( , W000, "Use 'struct Name;' instead of 'struct Nam { };' ... ning-nong");
+ return AST::Struct(::std::move(params), ::std::move(items));
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
+}
+
+AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+
+ AST::GenericParams params;
+ if( GET_TOK(tok, lex) == TOK_LT )
+ {
+ params = Parse_GenericParams(lex);
+ GET_CHECK_TOK(tok, lex, TOK_GT);
+ tok = lex.getToken();
+ }
+
+ // Trait bounds "trait Trait : 'lifetime + OtherTrait + OtherTrait2"
+ ::std::vector<Spanned<AST::Path> > supertraits;
+ if(tok.type() == TOK_COLON)
+ {
+ do {
+ if( GET_TOK(tok, lex) == TOK_LIFETIME ) {
+ // TODO: Need a better way of indiciating 'static than just an invalid path
+ supertraits.push_back( make_spanned( Span(tok.get_pos()), AST::Path() ) );
+ }
+ else {
+ PUTBACK(tok, lex);
+ supertraits.push_back( GET_SPANNED(::AST::Path, lex, Parse_Path(lex, PATH_GENERIC_TYPE)) );
+ }
+ } while( GET_TOK(tok, lex) == TOK_PLUS );
+ }
+
+ // TODO: Support "for Sized?"
+ if(tok.type() == TOK_RWORD_WHERE)
+ {
+ //if( params.ty_params().size() == 0 )
+ // throw ParseError::Generic("Where clause with no generic params");
+ Parse_WhereClause(lex, params);
+ tok = lex.getToken();
+ }
+
+
+ AST::Trait trait( mv$(params), mv$(supertraits) );
+
+ CHECK_TOK(tok, TOK_BRACE_OPEN);
+ while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
+ {
+
+ AST::MetaItems item_attrs;
+ while( tok.type() == TOK_ATTR_OPEN )
+ {
+ item_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ GET_TOK(tok, lex);
+ }
+ SET_ATTRS(lex, item_attrs);
+
+ auto ps = lex.start_span();
+ if( tok.type() == TOK_MACRO ) {
+ auto inv = Parse_MacroInvocation( ps, mv$(tok.str()), lex );
+ // - Silently consume ';' after the macro
+ if( GET_TOK(tok, lex) != TOK_SEMICOLON )
+ PUTBACK(tok, lex);
+
+ trait.items().push_back( AST::Named<AST::Item>("", AST::Item(mv$(inv)), false) );
+ continue ;
+ }
+
+ bool is_specialisable = false;
+ if( tok.type() == TOK_IDENT && tok.str() == "default" ) {
+ is_specialisable = true;
+ GET_TOK(tok, lex);
+ }
+ // TODO: Mark specialisation
+ (void)is_specialisable;
+
+ bool fn_is_const = false;
+ bool fn_is_unsafe = false;
+ ::std::string abi = ABI_RUST;
+ switch(tok.type())
+ {
+ case TOK_RWORD_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);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_SEMICOLON);
+
+ // TODO: Attributes on associated statics
+ trait.add_static( mv$(name), ::AST::Static(AST::Static::STATIC, mv$(ty), val)/*, mv$(item_attrs)*/ );
+ 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);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_SEMICOLON);
+
+ // TODO: Attributes on associated constants
+ trait.add_static( mv$(name), ::AST::Static(AST::Static::CONST, mv$(ty), val)/*, mv$(item_attrs)*/ );
+ break; }
+ // Associated type
+ case TOK_RWORD_TYPE: {
+ auto atype_params = ::AST::GenericParams { };
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = mv$(tok.str());
+ if( GET_TOK(tok, lex) == TOK_COLON )
+ {
+ // Bounded associated type
+ Parse_TypeBound(lex, atype_params, TypeRef(lex.getPosition(), "Self", 0xFFFF));
+ GET_TOK(tok, lex);
+ }
+ if( tok.type() == TOK_RWORD_WHERE ) {
+ throw ParseError::Todo(lex, "Where clause on associated type");
+ }
+
+ TypeRef default_type = TypeRef( lex.getPosition() );
+ if( tok.type() == TOK_EQUAL ) {
+ default_type = Parse_Type(lex);
+ GET_TOK(tok, lex);
+ }
+
+ CHECK_TOK(tok, TOK_SEMICOLON);
+ trait.add_type( ::std::move(name), ::std::move(default_type) );
+ trait.items().back().data.as_Type().params() = mv$(atype_params);
+ break; }
+
+ // Functions (possibly unsafe)
+ // TODO: Const?
+ case TOK_RWORD_UNSAFE:
+ fn_is_unsafe = true;
+ if( GET_TOK(tok, lex) == TOK_RWORD_EXTERN )
+ case TOK_RWORD_EXTERN:
+ {
+ abi = "C";
+ if( GET_TOK(tok, lex) == TOK_STRING )
+ abi = tok.str();
+ else
+ PUTBACK(tok, lex);
+
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_RWORD_FN);
+ case TOK_RWORD_FN: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ ::std::string name = mv$(tok.str());
+ // Self allowed, prototype-form allowed (optional names and no code)
+ auto fcn = Parse_FunctionDef(lex, abi, true, true, fn_is_unsafe, fn_is_const);
+ if( GET_TOK(tok, lex) == TOK_BRACE_OPEN )
+ {
+ PUTBACK(tok, lex);
+ fcn.set_code( Parse_ExprBlock(lex) );
+ }
+ else if( tok.type() == TOK_SEMICOLON )
+ {
+ // Accept it
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ // TODO: Store `item_attrs`
+ trait.add_function( ::std::move(name), /*mv$(item_attrs),*/ ::std::move(fcn) );
+ break; }
+ default:
+ throw ParseError::Unexpected(lex, tok);
+ }
+ }
+
+ return trait;
+}
+
+AST::Enum Parse_EnumDef(TokenStream& lex, const AST::MetaItems& meta_items)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+
+ tok = lex.getToken();
+ // Type params supporting "where"
+ AST::GenericParams params;
+ if( tok.type() == TOK_LT )
+ {
+ params = Parse_GenericParams(lex);
+ GET_CHECK_TOK(tok, lex, TOK_GT);
+ if(GET_TOK(tok, lex) == TOK_RWORD_WHERE)
+ {
+ Parse_WhereClause(lex, params);
+ tok = lex.getToken();
+ }
+ }
+
+ // Body
+ CHECK_TOK(tok, TOK_BRACE_OPEN);
+ ::std::vector<AST::EnumVariant> variants;
+ while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
+ {
+ auto sp = lex.start_span();
+
+ AST::MetaItems item_attrs;
+ while( tok.type() == TOK_ATTR_OPEN )
+ {
+ item_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ GET_TOK(tok, lex);
+ }
+ SET_ATTRS(lex, item_attrs);
+
+ CHECK_TOK(tok, TOK_IDENT);
+ ::std::string name = mv$(tok.str());
+ if( GET_TOK(tok, lex) == TOK_PAREN_OPEN )
+ {
+ ::std::vector<TypeRef> types;
+ // Get type list
+ do
+ {
+ if(LOOK_AHEAD(lex) == TOK_PAREN_CLOSE)
+ {
+ GET_TOK(tok, lex);
+ break;
+ }
+
+ AST::MetaItems field_attrs;
+ while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
+ {
+ GET_TOK(tok, lex);
+ field_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+
+ types.push_back( Parse_Type(lex) );
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ CHECK_TOK(tok, TOK_PAREN_CLOSE);
+ 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
+ {
+ if(LOOK_AHEAD(lex) == TOK_BRACE_CLOSE)
+ {
+ GET_TOK(tok, lex);
+ break;
+ }
+
+ AST::MetaItems field_attrs;
+ while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
+ {
+ GET_TOK(tok, lex);
+ field_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+
+ 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::StructItem(mv$(field_attrs), true, mv$(name), mv$(ty)) );
+ } 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 )
+ {
+ auto node = Parse_Expr(lex);
+ variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), mv$(node)) );
+ GET_TOK(tok, lex);
+ }
+ else
+ {
+ variants.push_back( AST::EnumVariant(mv$(item_attrs), mv$(name), ::AST::Expr()) );
+ }
+
+ if( tok.type() != TOK_COMMA )
+ break;
+ }
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+
+
+ return AST::Enum( mv$(params), mv$(variants) );
+}
+
+::AST::Union Parse_Union(TokenStream& lex, AST::MetaItems& meta_items)
+{
+ Token tok;
+
+ TRACE_FUNCTION;
+
+ AST::GenericParams params;
+ if( GET_TOK(tok, lex) == TOK_LT )
+ {
+ params = Parse_GenericParams(lex);
+ GET_CHECK_TOK(tok, lex, TOK_GT);
+ if(GET_TOK(tok, lex) == TOK_RWORD_WHERE)
+ {
+ Parse_WhereClause(lex, params);
+ tok = lex.getToken();
+ }
+ }
+
+ ::std::vector< ::AST::StructItem> variants;
+
+ CHECK_TOK(tok, TOK_BRACE_OPEN);
+ do {
+ if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) {
+ GET_TOK(tok, lex);
+ break ;
+ }
+
+ AST::MetaItems item_attrs;
+ while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN )
+ {
+ GET_TOK(tok, lex);
+ item_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+ SET_ATTRS(lex, item_attrs);
+
+ bool is_pub = false;
+ if( LOOK_AHEAD(lex) == TOK_RWORD_PUB ) {
+ is_pub = true;
+ GET_TOK(tok, lex);
+ }
+
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = mv$(tok.str());
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+
+ auto ty = Parse_Type(lex);
+
+ variants.push_back( ::AST::StructItem( mv$(item_attrs), is_pub, mv$(name), mv$(ty) ) );
+
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+
+ return ::AST::Union( mv$(params), mv$(variants) );
+}
+
+/// Parse a meta-item declaration (either #![ or #[)
+AST::MetaItem Parse_MetaItem(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+ Token tok;
+ GET_TOK(tok, lex);
+
+ if( tok.type() == TOK_INTERPOLATED_META ) {
+ return mv$(tok.frag_meta());
+ }
+
+ CHECK_TOK(tok, TOK_IDENT);
+ ::std::string name = mv$(tok.str());
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_EQUAL:
+ GET_CHECK_TOK(tok, lex, TOK_STRING);
+ return AST::MetaItem(name, tok.str());
+ case TOK_PAREN_OPEN: {
+ ::std::vector<AST::MetaItem> items;
+ do {
+ if(LOOK_AHEAD(lex) == TOK_PAREN_CLOSE) {
+ GET_TOK(tok, lex);
+ break;
+ }
+ items.push_back(Parse_MetaItem(lex));
+ } while(GET_TOK(tok, lex) == TOK_COMMA);
+ CHECK_TOK(tok, TOK_PAREN_CLOSE);
+ return AST::MetaItem(name, mv$(items)); }
+ default:
+ PUTBACK(tok, lex);
+ return AST::MetaItem(name);
+ }
+}
+
+::AST::Item Parse_Impl(TokenStream& lex, AST::MetaItems attrs, bool is_unsafe=false)
+{
+ TRACE_FUNCTION;
+ Token tok;
+ auto ps = lex.start_span();
+
+ AST::GenericParams params;
+ // 1. (optional) type parameters
+ if( GET_TOK(tok, lex) == TOK_LT )
+ {
+ params = Parse_GenericParams(lex);
+ GET_CHECK_TOK(tok, lex, TOK_GT);
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+ // 2. Either a trait name (with type params), or the type to impl
+
+ Spanned<AST::Path> trait_path;
+
+ // - Handle negative impls specially, which must be a trait
+ // "impl !Trait for Type {}"
+ if( GET_TOK(tok, lex) == TOK_EXCLAM )
+ {
+ trait_path = GET_SPANNED(::AST::Path, lex, Parse_Path(lex, PATH_GENERIC_TYPE));
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_FOR);
+ auto impl_type = Parse_Type(lex, true);
+
+ if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
+ {
+ Parse_WhereClause(lex, params);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_BRACE_OPEN);
+ // negative impls can't have any content
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
+
+ return ::AST::Item::make_NegImpl( AST::ImplDef(lex.end_span(ps), mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ) );
+ }
+
+ // - Don't care which at this stage
+ PUTBACK(tok, lex);
+
+ auto impl_type = Parse_Type(lex, true);
+
+ if( GET_TOK(tok, lex) == TOK_RWORD_FOR )
+ {
+ // Trickery! All traits parse as valid types, so this works.
+ if( !impl_type.is_path() )
+ throw ParseError::Generic(lex, "Trait was not a path");
+ trait_path = Spanned< AST::Path> {
+ impl_type.span(),
+ mv$(impl_type.path())
+ };
+ // Implementing a trait for another type, get the target type
+ if( GET_TOK(tok, lex) == TOK_DOUBLE_DOT )
+ {
+ // Default impl
+ impl_type = TypeRef(TypeRef::TagInvalid(), lex.getPosition());
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ impl_type = Parse_Type(lex, true);
+ }
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+
+ // Where clause
+ if( GET_TOK(tok, lex) == TOK_RWORD_WHERE )
+ {
+ Parse_WhereClause(lex, params);
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
+
+ while( LOOK_AHEAD(lex) == TOK_CATTR_OPEN )
+ {
+ GET_TOK(tok, lex);
+ attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+
+ AST::Impl impl( AST::ImplDef( lex.end_span(ps), mv$(attrs), mv$(params), mv$(trait_path), mv$(impl_type) ) );
+
+ // A sequence of method implementations
+ while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
+ {
+ auto ps = lex.start_span();
+ if( tok.type() == TOK_MACRO )
+ {
+ impl.add_macro_invocation( Parse_MacroInvocation( ps, mv$(tok.str()), lex ) );
+ // - Silently consume ';' after the macro
+ if( GET_TOK(tok, lex) != TOK_SEMICOLON )
+ PUTBACK(tok, lex);
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ Parse_Impl_Item(lex, impl);
+ }
+ }
+
+ return ::AST::Item::make_Impl( mv$(impl) );
+}
+
+void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ GET_TOK(tok, lex);
+
+ AST::MetaItems item_attrs;
+ while( tok.type() == TOK_ATTR_OPEN )
+ {
+ item_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ GET_TOK(tok, lex);
+ }
+ SET_ATTRS(lex, item_attrs);
+
+ auto ps = lex.start_span();
+
+ bool is_public = false;
+ if(tok.type() == TOK_RWORD_PUB) {
+ is_public = true;
+ GET_TOK(tok, lex);
+ }
+
+ bool is_specialisable = false;
+ if( tok.type() == TOK_IDENT && tok.str() == "default" ) {
+ is_specialisable = true;
+ GET_TOK(tok, lex);
+ }
+
+ ::std::string abi = ABI_RUST;
+ bool fn_is_unsafe = false;
+ bool fn_is_const = false;
+ switch(tok.type())
+ {
+ case TOK_RWORD_TYPE: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = mv$(tok.str());
+ GET_CHECK_TOK(tok, lex, TOK_EQUAL);
+ impl.add_type(is_public, is_specialisable, name, Parse_Type(lex));
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ break; }
+ case TOK_RWORD_UNSAFE:
+ fn_is_unsafe = true;
+ GET_TOK(tok, lex);
+ if( tok.type() == TOK_RWORD_CONST )
+ case TOK_RWORD_CONST:
+ {
+ GET_TOK(tok, lex);
+ if( tok.type() != TOK_RWORD_FN && tok.type() != TOK_RWORD_UNSAFE && !fn_is_unsafe )
+ {
+ 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);
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+
+ auto i = ::AST::Static(AST::Static::CONST, mv$(ty), mv$(val));
+ // TODO: Attributes on associated constants
+ impl.add_static( is_public, is_specialisable, mv$(name), mv$(i) /*, mv$(item_attrs)*/ );
+ break ;
+ }
+ else if( tok.type() == TOK_RWORD_UNSAFE )
+ {
+ fn_is_unsafe = true;
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
+ }
+ fn_is_const = true;
+ }
+ if( tok.type() == TOK_RWORD_EXTERN )
+ // FALL
+ case TOK_RWORD_EXTERN:
+ {
+ abi = "C";
+ if( GET_TOK(tok, lex) == TOK_STRING )
+ abi = tok.str();
+ else
+ PUTBACK(tok, lex);
+
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_RWORD_FN);
+ // FALL
+ case TOK_RWORD_FN: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ // TODO: Hygine on function names? - Not in impl blocks?
+ ::std::string name = mv$(tok.str());
+ DEBUG("Function " << name);
+ // - Self allowed, can't be prototype-form
+ auto fcn = Parse_FunctionDefWithCode(lex, abi, true, fn_is_unsafe, fn_is_const);
+ impl.add_function(is_public, is_specialisable, mv$(name), mv$(fcn));
+ break; }
+
+ default:
+ throw ParseError::Unexpected(lex, tok);
+ }
+
+ impl.items().back().data->span = lex.end_span(ps);
+ impl.items().back().data->attrs = mv$(item_attrs); // Empty for functions
+}
+
+AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::MetaItems& block_attrs)
+{
+ TRACE_FUNCTION;
+ Token tok;
+
+ while( GET_TOK(tok, lex) == TOK_CATTR_OPEN )
+ {
+ block_attrs.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+ PUTBACK(tok, lex);
+
+ AST::ExternBlock rv { abi };
+
+ while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
+ {
+ AST::MetaItems meta_items;
+ while( tok.type() == TOK_ATTR_OPEN )
+ {
+ meta_items.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ GET_TOK(tok, lex);
+ }
+ SET_ATTRS(lex, meta_items);
+
+ auto ps = lex.start_span();
+
+ bool is_public = false;
+ if( tok.type() == TOK_RWORD_PUB ) {
+ is_public = true;
+ GET_TOK(tok, lex);
+ }
+ switch(tok.type())
+ {
+ case TOK_RWORD_FN: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = mv$(tok.str());
+ // parse function as prototype
+ // - no self, is prototype, is unsafe and not const
+ auto i = ::AST::Item( Parse_FunctionDef(lex, abi, false, true, true,false) );
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+
+ i.attrs = mv$(meta_items);
+ i.span = lex.end_span(ps);
+
+ rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
+ break; }
+ case TOK_RWORD_STATIC: {
+ bool is_mut = false;
+ if( GET_TOK(tok, lex) == TOK_RWORD_MUT )
+ is_mut = true;
+ else
+ PUTBACK(tok, lex);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = mv$(tok.str());
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ auto type = Parse_Type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+
+ auto i = ::AST::Item(::AST::Static( (is_mut ? ::AST::Static::MUT : ::AST::Static::STATIC), mv$(type), ::AST::Expr() ));
+ i.attrs = mv$(meta_items);
+ i.span = lex.end_span(ps);
+ rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
+ break; }
+ default:
+ throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC});
+ }
+ }
+
+ return rv;
+}
+
+void Parse_Use_Wildcard(Span sp, AST::Path base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
+{
+ fcn( AST::UseStmt(mv$(sp), mv$(base_path)), "" ); // HACK! Empty path indicates wilcard import
+}
+void Parse_Use_Set(TokenStream& lex, const ProtoSpan& ps, const AST::Path& base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+ do {
+ AST::Path path;
+ ::std::string name;
+ if( GET_TOK(tok, lex) == TOK_RWORD_SELF ) {
+ path = ::AST::Path(base_path);
+ name = base_path[base_path.size()-1].name();
+ }
+ else if( tok.type() == TOK_BRACE_CLOSE ) {
+ break ;
+ }
+ else {
+ CHECK_TOK(tok, TOK_IDENT);
+ path = base_path + AST::PathNode(tok.str(), {});
+ name = mv$(tok.str());
+ }
+
+ if( GET_TOK(tok, lex) == TOK_RWORD_AS ) {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = mv$(tok.str());
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+ fcn(AST::UseStmt(lex.end_span(ps), mv$(path)), mv$(name));
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ PUTBACK(tok, lex);
+}
+
+void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+ AST::Path path = AST::Path("", {});
+ ::std::vector<AST::PathNode> nodes;
+ ProtoSpan span_start = lex.start_span();
+
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_RWORD_SELF:
+ path = AST::Path( AST::Path::TagSelf(), {} ); // relative path
+ break;
+ case TOK_RWORD_SUPER: {
+ unsigned int count = 1;
+ while( LOOK_AHEAD(lex) == TOK_DOUBLE_COLON && lex.lookahead(1) == TOK_RWORD_SUPER ) {
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_SUPER);
+ count += 1;
+ }
+ path = AST::Path( AST::Path::TagSuper(), count, {} );
+ break; }
+ case TOK_IDENT:
+ path.append( AST::PathNode(mv$(tok.str()), {}) );
+ break;
+ // Leading :: is allowed and ignored for the $crate feature
+ case TOK_DOUBLE_COLON:
+ // Absolute path
+ // HACK! mrustc emits $crate as `::"crate-name"`
+ if( LOOK_AHEAD(lex) == TOK_STRING )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_STRING);
+ path = ::AST::Path(tok.str(), {});
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+ break;
+ case TOK_BRACE_OPEN:
+ Parse_Use_Set(lex, span_start, path, fcn);
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
+ return;
+ default:
+ throw ParseError::Unexpected(lex, tok);
+ }
+ while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON )
+ {
+ if( GET_TOK(tok, lex) == TOK_IDENT )
+ {
+ path.append( AST::PathNode( mv$(tok.str()), {}) );
+ }
+ else
+ {
+ //path.set_span( lex.end_span(span_start) );
+ switch( tok.type() )
+ {
+ case TOK_BRACE_OPEN:
+ Parse_Use_Set(lex, span_start, mv$(path), fcn);
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
+ break ;
+ case TOK_STAR:
+ Parse_Use_Wildcard( lex.end_span(span_start), mv$(path), fcn );
+ break ;
+ default:
+ throw ParseError::Unexpected(lex, tok);
+ }
+ // early return - This branch is either the end of the use statement, or a syntax error
+ return ;
+ }
+ }
+ //path.set_span( lex.end_span(span_start) );
+
+ ::std::string name;
+ // This should only be allowed if the last token was an ident
+ // - Above checks ensure this
+ if( tok.type() == TOK_RWORD_AS )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = mv$(tok.str());
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ assert(path.nodes().size() > 0);
+ name = path.nodes().back().name();
+ }
+
+ fcn( AST::UseStmt(lex.end_span(span_start), mv$(path)), name);
+}
+
+
+::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, ::std::string name, TokenStream& lex)
+{
+ Token tok;
+ ::std::string ident;
+ if( GET_TOK(tok, lex) == TOK_IDENT ) {
+ ident = mv$(tok.str());
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+ DEBUG("name=" << name << ", ident=" << ident);
+ TokenTree tt = Parse_TT(lex, true);
+ return ::AST::MacroInvocation( lex.end_span(span_start), mv$(name), mv$(ident), mv$(tt));
+}
+
+::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::MetaItems meta_items)
+{
+ TRACE_FUNCTION_F("mod_path="<<mod_path<<", meta_items="<<meta_items);
+ Token tok;
+
+ while( LOOK_AHEAD(lex) == TOK_ATTR_OPEN /* || LOOKAHEAD2(lex, TOK_HASH, TOK_SQUARE_OPEN) */ )
+ {
+ // Attributes!
+ GET_CHECK_TOK(tok, lex, TOK_ATTR_OPEN);
+ meta_items.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+
+ if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_ITEM ) {
+ GET_TOK(tok, lex);
+ auto rv = tok.take_frag_item();
+ // Transfer new attributes onto the item
+ for(auto& mi : meta_items.m_items)
+ rv.data.attrs.m_items.push_back( mv$(mi) );
+ return rv;
+ }
+
+ auto ps = lex.start_span();
+
+ ::std::string item_name;
+ ::AST::Item item_data;
+
+ if( LOOK_AHEAD(lex) == TOK_MACRO ) {
+ GET_TOK(tok, lex);
+
+ ::std::string name = mv$(tok.str());
+ bool is_braced = (LOOK_AHEAD(lex) == TOK_BRACE_OPEN || LOOKAHEAD2(lex, TOK_IDENT, TOK_BRACE_OPEN));
+ item_data = ::AST::Item( Parse_MacroInvocation( ps, mv$(name), lex ) );
+
+ if( !is_braced ) {
+ // - Consume the ';' after the macro
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ }
+
+ item_data.attrs = mv$(meta_items);
+ item_data.span = lex.end_span(ps);
+
+ return ::AST::Named< ::AST::Item> { "", mv$(item_data), false };
+ }
+
+ bool is_public = false;
+ if( GET_TOK(tok, lex) == TOK_RWORD_PUB ) {
+ is_public = true;
+ }
+ else {
+ PUTBACK(tok, lex);
+ }
+
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_RWORD_USE:
+ // NOTE: The only problem here is with things like `use foo::{a, b, c}` - all others are a single statement.
+ // - These are caught by the condition in the closure
+ Parse_Use(lex, [&](AST::UseStmt p, std::string s) {
+ DEBUG(mod_path << " - use " << p << " as '" << s << "'");
+ if( !item_data.is_None() )
+ TODO(lex.getPosition(), "Encode multi-item use statements as a single Item");
+ item_data = ::AST::Item(mv$(p));
+ item_name = mv$(s);
+ });
+ assert( !item_data.is_None() );
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ break;
+
+ case TOK_RWORD_EXTERN:
+ switch( GET_TOK(tok, lex) )
+ {
+ // `extern "<ABI>" fn ...`
+ // `extern "<ABI>" { ...`
+ case TOK_STRING: {
+ ::std::string abi = tok.str();
+ switch(GET_TOK(tok, lex))
+ {
+ // `extern "<ABI>" fn ...`
+ case TOK_RWORD_FN: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, false,false) );
+ break; }
+ // `extern "ABI" {`
+ case TOK_BRACE_OPEN:
+ item_name = "";
+ item_data = ::AST::Item( Parse_ExternBlock(lex, mv$(abi), meta_items) );
+ break;
+ default:
+ throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_BRACE_OPEN});
+ }
+ break; }
+ // `extern fn ...`
+ case TOK_RWORD_FN:
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, "C", false, false,false) );
+ break;
+
+ // NOTE: `extern { ...` is handled in caller
+ case TOK_BRACE_OPEN:
+ item_name = "";
+ item_data = ::AST::Item( Parse_ExternBlock(lex, "C", meta_items) );
+ break;
+
+ // `extern crate "crate-name" as crate_name;`
+ // `extern crate crate_name;`
+ // `extern crate crate_name as other_name;`
+ case TOK_RWORD_CRATE:
+ switch( GET_TOK(tok, lex) )
+ {
+ // `extern crate "crate-name" as crate_name;`
+ // NOTE: rustc doesn't allow this, keep in mrustc for for reparse support
+ case TOK_STRING:
+ item_data = ::AST::Item::make_Crate({ tok.str() });
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_AS);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ break;
+ // `extern crate crate_name;`
+ // `extern crate crate_name as other_name;`
+ case TOK_IDENT:
+ item_name = mv$(tok.str());
+ if(GET_TOK(tok, lex) == TOK_RWORD_AS) {
+ item_data = ::AST::Item::make_Crate({ mv$(item_name) });
+
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ }
+ else {
+ PUTBACK(tok, lex);
+ item_data = ::AST::Item::make_Crate({ item_name });
+ }
+ break;
+ default:
+ throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_IDENT});
+ }
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ break;
+ default:
+ throw ParseError::Unexpected(lex, tok, {TOK_STRING, TOK_RWORD_FN, TOK_BRACE_OPEN, TOK_RWORD_CRATE});
+ }
+ break;
+
+ // `const NAME`
+ // `const [unsafe] fn`
+ case TOK_RWORD_CONST:
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_IDENT: {
+ item_name = mv$(tok.str());
+
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ TypeRef type = Parse_Type(lex);
+ GET_CHECK_TOK(tok, lex, TOK_EQUAL);
+ AST::Expr val = Parse_Expr(lex);
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ item_data = ::AST::Item( ::AST::Static(AST::Static::CONST, mv$(type), mv$(val)) );
+ break; }
+ case TOK_RWORD_UNSAFE:
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,true/*unsafe,const*/) );
+ break;
+ case TOK_RWORD_FN:
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ // - self not allowed, not prototype
+ item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,true/*unsafe,const*/) );
+ break;
+ default:
+ throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_RWORD_FN});
+ }
+ break;
+ // `static NAME`
+ // `static mut NAME`
+ case TOK_RWORD_STATIC: {
+ bool is_mut = false;
+ if(GET_TOK(tok, lex) == TOK_RWORD_MUT) {
+ is_mut = true;
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_IDENT);
+ item_name = mv$(tok.str());
+
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ TypeRef type = Parse_Type(lex);
+
+ GET_CHECK_TOK(tok, lex, TOK_EQUAL);
+
+ AST::Expr val = Parse_Expr(lex);
+
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ item_data = ::AST::Item( ::AST::Static( (is_mut ? AST::Static::MUT : AST::Static::STATIC), mv$(type), mv$(val)) );
+ break; }
+
+ // `unsafe fn`
+ // `unsafe trait`
+ // `unsafe impl`
+ case TOK_RWORD_UNSAFE:
+ 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 {
+ PUTBACK(tok, lex);
+ }
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, true,false/*unsafe,const*/) );
+ break; }
+ // `unsafe fn`
+ case TOK_RWORD_FN:
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ // - self not allowed, not prototype
+ item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, true,false/*unsafe,const*/) );
+ break;
+ // `unsafe trait`
+ case TOK_RWORD_TRAIT:
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ // TODO: Mark as unsafe
+ meta_items.push_back( AST::MetaItem("#UNSAFE") );
+ item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) );
+ break;
+ // `unsafe impl`
+ case TOK_RWORD_IMPL:
+ return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items), true), false };
+ default:
+ throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_TRAIT, TOK_RWORD_IMPL});
+ }
+ break;
+ // `fn`
+ case TOK_RWORD_FN:
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ // - self not allowed, not prototype
+ item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,false/*unsafe,const*/) );
+ break;
+ // `type`
+ case TOK_RWORD_TYPE:
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ item_data = ::AST::Item( Parse_TypeAlias(lex) );
+ break;
+ // `struct`
+ case TOK_RWORD_STRUCT:
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ item_data = ::AST::Item( Parse_Struct(lex, meta_items) );
+ break;
+ // `enum`
+ case TOK_RWORD_ENUM:
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ item_data = ::AST::Item( Parse_EnumDef(lex, meta_items) );
+ break;
+ // Contextual keywords
+ case TOK_IDENT:
+ if( tok.str() == "union" ) {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ item_data = ::AST::Item( Parse_Union(lex, meta_items) );
+ }
+ else {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ break;
+ // `impl`
+ case TOK_RWORD_IMPL:
+ return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items)), false };
+ // `trait`
+ case TOK_RWORD_TRAIT:
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = mv$(tok.str());
+ item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) );
+ break;
+
+ case TOK_RWORD_MOD: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = mv$(tok.str());
+ DEBUG("Sub module '" << name << "'");
+ AST::Module submod( mod_path + name );
+
+ // Rules for external files (/ path handling):
+ // - IF using stdin (path='-') - Disallow and propagate '-' as path
+ // - IF a #[path] attribute was passed, allow
+ // - IF in crate root or mod.rs, allow (input flag)
+ // - else, disallow and set flag
+ ::std::string path_attr = (meta_items.has("path") ? meta_items.get("path")->string() : "");
+
+ //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON);
+
+ ::std::string sub_path;
+ bool sub_file_controls_dir = true;
+ if( mod_fileinfo.path == "-" ) {
+ if( path_attr.size() ) {
+ ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin");
+ }
+ sub_path = "-";
+ }
+ else if( path_attr.size() > 0 )
+ {
+ sub_path = dirname(mod_fileinfo.path) + path_attr;
+ }
+ else if( mod_fileinfo.controls_dir )
+ {
+ sub_path = dirname(mod_fileinfo.path) + name;
+ }
+ else
+ {
+ sub_path = mod_fileinfo.path;
+ sub_file_controls_dir = false;
+ }
+ DEBUG("Mod '" << name << "', sub_path = " << sub_path);
+
+ submod.m_file_info.path = sub_path;
+ submod.m_file_info.controls_dir = sub_file_controls_dir;
+
+ // Check #[cfg] and don't load if it fails
+ struct H {
+ static bool check_item_cfg(const ::AST::MetaItems& attrs)
+ {
+ for(const auto& at : attrs.m_items) {
+ if( at.name() == "cfg" && !check_cfg(attrs.m_span, at) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_BRACE_OPEN:
+ submod.m_file_info.path = sub_path + "/";
+ Parse_ModRoot(lex, submod, meta_items);
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
+ break;
+ case TOK_SEMICOLON:
+ if( sub_path == "-" ) {
+ ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin");
+ }
+ else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir )
+ {
+ ERROR(lex.getPosition(), E0000, "Can't load from files outside of mod.rs or crate root");
+ }
+ else if( !H::check_item_cfg(meta_items) ) {
+ // Ignore - emit Item::None
+ item_name = mv$(name);
+ item_data = ::AST::Item( );
+ break ;
+ }
+ else
+ {
+ ::std::string newpath_dir = sub_path + "/";
+ ::std::string newpath_file = path_attr.size() > 0 ? sub_path : sub_path + ".rs";
+ DEBUG("newpath_dir = '" << newpath_dir << "', newpath_file = '" << newpath_file << "'");
+ ::std::ifstream ifs_dir (newpath_dir + "mod.rs");
+ ::std::ifstream ifs_file(newpath_file);
+ if( ifs_dir.is_open() && ifs_file.is_open() )
+ {
+ // Collision
+ ERROR(lex.getPosition(), E0000, "Both modname.rs and modname/mod.rs exist");
+ }
+ else if( ifs_dir.is_open() )
+ {
+ // Load from dir
+ submod.m_file_info.path = newpath_dir + "mod.rs";
+ }
+ else if( ifs_file.is_open() )
+ {
+ submod.m_file_info.path = newpath_file;
+ }
+ else
+ {
+ // Can't find file
+ ERROR(lex.getPosition(), E0000, "Can't find file for '" << name << "' in '" << mod_fileinfo.path << "'");
+ }
+ DEBUG("- path = " << submod.m_file_info.path);
+ Lexer sub_lex(submod.m_file_info.path);
+ Parse_ModRoot(sub_lex, submod, meta_items);
+ GET_CHECK_TOK(tok, sub_lex, TOK_EOF);
+ }
+ break;
+ default:
+ throw ParseError::Generic("Expected { or ; after module name");
+ }
+ item_name = mv$(name);
+ item_data = ::AST::Item( mv$(submod) );
+ break; }
+
+ default:
+ throw ParseError::Unexpected(lex, tok);
+ }
+
+ item_data.attrs = mv$(meta_items);
+ item_data.span = lex.end_span(ps);
+
+ return ::AST::Named< ::AST::Item> { mv$(item_name), mv$(item_data), is_public };
+}
+
+void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::MetaItems meta_items)
+{
+ SET_MODULE(lex, mod);
+ lex.parse_state().parent_attrs = &meta_items;
+
+ //TRACE_FUNCTION;
+ Token tok;
+
+ // `use ...`
+ if( LOOK_AHEAD(lex) == TOK_RWORD_USE || (lex.lookahead(0) == TOK_RWORD_PUB && lex.lookahead(1) == TOK_RWORD_USE) )
+ {
+ bool is_public = false;
+ if( GET_TOK(tok, lex) == TOK_RWORD_PUB ) {
+ is_public = true;
+ GET_TOK(tok, lex);
+ }
+
+ Parse_Use(lex, [&mod,is_public,&meta_items](AST::UseStmt p, std::string s) {
+ DEBUG(mod.path() << " - use " << p << " as '" << s << "'");
+ mod.add_alias(is_public, mv$(p), s, meta_items.clone());
+ });
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ }
+ else
+ {
+ mod.add_item( Parse_Mod_Item_S(lex, mod.m_file_info, mod.path(), mv$(meta_items)) );
+ }
+}
+
+void Parse_ModRoot_Items(TokenStream& lex, AST::Module& mod)
+{
+ Token tok;
+
+ for(;;)
+ {
+ // Check 1 - End of module (either via a closing brace, or EOF)
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_BRACE_CLOSE:
+ case TOK_EOF:
+ PUTBACK(tok, lex);
+ return;
+ default:
+ PUTBACK(tok, lex);
+ break;
+ }
+
+ // Attributes on the following item
+ AST::MetaItems meta_items;
+ while( GET_TOK(tok, lex) == TOK_ATTR_OPEN )
+ {
+ meta_items.push_back( Parse_MetaItem(lex) );
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+ }
+ PUTBACK(tok, lex);
+ DEBUG("meta_items = " << meta_items);
+
+ Parse_Mod_Item(lex, mod, mv$(meta_items));
+ }
+}
+
+void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::MetaItems& mod_attrs)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+
+ // Attributes on module/crate (will continue loop)
+ while( GET_TOK(tok, lex) == TOK_CATTR_OPEN )
+ {
+ AST::MetaItem item = Parse_MetaItem(lex);
+ GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE);
+
+ mod_attrs.push_back( mv$(item) );
+ }
+ PUTBACK(tok, lex);
+
+ Parse_ModRoot_Items(lex, mod);
+}
+
+AST::Crate Parse_Crate(::std::string mainfile)
+{
+ Token tok;
+
+ Lexer lex(mainfile);
+
+ size_t p = mainfile.find_last_of('/');
+ ::std::string mainpath = (p != ::std::string::npos ? ::std::string(mainfile.begin(), mainfile.begin()+p+1) : "./");
+
+ AST::Crate crate;
+
+ crate.root_module().m_file_info.path = mainpath;
+ crate.root_module().m_file_info.controls_dir = true;
+
+ Parse_ModRoot(lex, crate.root_module(), crate.m_attrs);
+
+ return crate;
+}
diff --git a/src/parse/token.cpp b/src/parse/token.cpp
index 95adf594..13af2043 100644
--- a/src/parse/token.cpp
+++ b/src/parse/token.cpp
@@ -38,7 +38,7 @@ Token::~Token()
default:
break;
}
-
+
}
Token::Token():
@@ -87,7 +87,7 @@ Token::Token(const InterpolatedFragment& frag)
m_type = TOK_INTERPOLATED_STMT; if(0)
case InterpolatedFragment::BLOCK:
m_type = TOK_INTERPOLATED_BLOCK;
-
+
m_data = reinterpret_cast<const AST::ExprNode*>(frag.m_ptr)->clone().release();
break;
case InterpolatedFragment::META:
@@ -125,7 +125,7 @@ Token::Token(TagTakeIP, InterpolatedFragment frag)
m_type = TOK_INTERPOLATED_STMT; if(0)
case InterpolatedFragment::BLOCK:
m_type = TOK_INTERPOLATED_BLOCK;
-
+
m_data = reinterpret_cast<AST::ExprNode*>(frag.m_ptr);
frag.m_ptr = nullptr;
break;
@@ -160,7 +160,7 @@ Token Token::clone() const
{
Token rv(m_type);
rv.m_pos = m_pos;
-
+
assert( m_data.tag() != Data::TAGDEAD );
TU_MATCH(Data, (m_data), (e),
(None,
@@ -254,7 +254,7 @@ enum eTokenType Token::typefromstr(const ::std::string& s)
struct EscapedString {
const ::std::string& s;
EscapedString(const ::std::string& s): s(s) {}
-
+
friend ::std::ostream& operator<<(::std::ostream& os, const EscapedString& x) {
for(auto b : x.s) {
switch(b)
@@ -284,7 +284,7 @@ struct EscapedString {
{
switch(m_type)
{
- case TOK_NULL: return "/*null*/";
+ case TOK_NULL: return "/*null*/";
case TOK_EOF: return "/*eof*/";
case TOK_NEWLINE: return "\n";
diff --git a/src/parse/token.hpp b/src/parse/token.hpp
index 3e7f7c24..0fcf0ed7 100644
--- a/src/parse/token.hpp
+++ b/src/parse/token.hpp
@@ -26,7 +26,7 @@ public:
RcString filename;
unsigned int line;
unsigned int ofs;
-
+
Position():
filename(""),
line(0),
@@ -71,11 +71,11 @@ class Token:
}),
(Fragment, void*)
);
-
+
enum eTokenType m_type;
Data m_data;
Position m_pos;
-
+
public:
virtual ~Token();
Token();
@@ -95,7 +95,7 @@ public:
}
Token(const Token& t);
Token clone() const;
-
+
Token(enum eTokenType type);
Token(enum eTokenType type, ::std::string str);
Token(uint64_t val, enum eCoreType datatype);
@@ -110,14 +110,14 @@ public:
enum eCoreType datatype() const { TU_MATCH_DEF(Data, (m_data), (e), (assert(!"Getting datatype of invalid token type");), (Integer, return e.m_datatype;), (Float, return e.m_datatype;)) }
uint64_t intval() const { return m_data.as_Integer().m_intval; }
double floatval() const { return m_data.as_Float().m_floatval; }
-
+
TypeRef& frag_type() { assert(m_type == TOK_INTERPOLATED_TYPE); return *reinterpret_cast<TypeRef*>( m_data.as_Fragment() ); }
AST::Path& frag_path() { assert(m_type == TOK_INTERPOLATED_PATH); return *reinterpret_cast<AST::Path*>( m_data.as_Fragment() ); }
AST::Pattern& frag_pattern() { assert(m_type == TOK_INTERPOLATED_PATTERN); return *reinterpret_cast<AST::Pattern*>( m_data.as_Fragment() ); }
AST::MetaItem& frag_meta() { assert(m_type == TOK_INTERPOLATED_META); return *reinterpret_cast<AST::MetaItem*>( m_data.as_Fragment() ); }
::std::unique_ptr<AST::ExprNode> take_frag_node();
::AST::Named<AST::Item> take_frag_item();
-
+
bool operator==(const Token& r) const {
if(type() != r.type())
return false;
@@ -133,13 +133,13 @@ public:
bool operator!=(const Token& r) const { return !(*this == r); }
::std::string to_str() const;
-
+
void set_pos(Position pos) { m_pos = pos; }
const Position& get_pos() const { return m_pos; }
-
+
static const char* typestr(enum eTokenType type);
static eTokenType typefromstr(const ::std::string& s);
-
+
SERIALISABLE_PROTOTYPES();
friend ::std::ostream& operator<<(::std::ostream& os, const Token& tok);
diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp
index 0182e548..9a961a04 100644
--- a/src/parse/tokenstream.cpp
+++ b/src/parse/tokenstream.cpp
@@ -73,17 +73,17 @@ void TokenStream::putback(Token tok)
eTokenType TokenStream::lookahead(unsigned int i)
{
const unsigned int MAX_LOOKAHEAD = 3;
-
+
if( m_cache_valid )
{
if( i == 0 )
return m_cache.type();
i --;
}
-
+
if( i >= MAX_LOOKAHEAD )
throw ParseError::BugCheck("Excessive lookahead");
-
+
while( i >= m_lookahead.size() )
{
DEBUG("lookahead - read #" << m_lookahead.size());
@@ -91,7 +91,7 @@ eTokenType TokenStream::lookahead(unsigned int i)
auto hygiene = this->realGetHygiene();
m_lookahead.push_back( ::std::make_pair(mv$(tok), mv$(hygiene)) );
}
-
+
DEBUG("lookahead(" << i << ") = " << m_lookahead[i]);
return m_lookahead[i].first.type();
}
diff --git a/src/parse/tokenstream.hpp b/src/parse/tokenstream.hpp
index ae737d0d..85fc62e2 100644
--- a/src/parse/tokenstream.hpp
+++ b/src/parse/tokenstream.hpp
@@ -26,15 +26,15 @@ struct ParseState
bool disallow_struct_literal = false;
// A debugging hook that disables expansion of macros
bool no_expand_macros = false;
-
+
::AST::Module* module = nullptr;
::AST::MetaItems* parent_attrs = nullptr;
-
+
::AST::Module& get_current_mod() {
assert(this->module);
return *this->module;
}
-
+
friend ::std::ostream& operator<<(::std::ostream& os, const ParseState& ps) {
os << "ParseState {";
if(ps.disallow_struct_literal) os << " disallow_struct_literal";
@@ -47,7 +47,7 @@ struct ParseState
class TokenStream
{
friend class TTLexer; // needs access to internals to know what was consumed
-
+
bool m_cache_valid;
Token m_cache;
Ident::Hygiene m_hygiene;
@@ -59,17 +59,17 @@ public:
Token getToken();
void putback(Token tok);
eTokenType lookahead(unsigned int count);
-
+
virtual Position getPosition() const = 0;
Ident::Hygiene getHygiene() const;
-
+
ParseState& parse_state() { return m_parse_state; }
-
+
ProtoSpan start_span() const;
Span end_span(ProtoSpan ps) const;
-
+
Ident get_ident(Token tok) const;
-
+
protected:
virtual Token realGetToken() = 0;
virtual Ident::Hygiene realGetHygiene() const = 0;
diff --git a/src/parse/tokentree.hpp b/src/parse/tokentree.hpp
index 8472ec7f..26e23876 100644
--- a/src/parse/tokentree.hpp
+++ b/src/parse/tokentree.hpp
@@ -1,61 +1,61 @@
-/*
- * MRustC - Rust Compiler
- * - By John Hodge (Mutabah/thePowersGang)
- *
- * parse/tokentree.hpp
- * - Token Trees (groups of tokens
- */
-#ifndef TOKENTREE_HPP_INCLUDED
-#define TOKENTREE_HPP_INCLUDED
-
-#include "token.hpp"
-#include <ident.hpp>
-#include <vector>
-
-class TokenTree
-{
- Ident::Hygiene m_hygiene;
- Token m_tok;
- ::std::vector<TokenTree> m_subtrees;
-public:
- virtual ~TokenTree() {}
- TokenTree() {}
- TokenTree(TokenTree&&) = default;
- TokenTree& operator=(TokenTree&&) = default;
- TokenTree(enum eTokenType ty):
- m_tok( Token(ty) )
- {
- }
- TokenTree(Token tok):
- m_tok( ::std::move(tok) )
- {
- }
- TokenTree(Ident::Hygiene hygiene, Token tok):
- m_hygiene( ::std::move(hygiene) ),
- m_tok( ::std::move(tok) )
- {
- }
- TokenTree(Ident::Hygiene hygiene, ::std::vector<TokenTree> subtrees):
- m_hygiene( ::std::move(hygiene) ),
- m_subtrees( ::std::move(subtrees) )
- {
- }
-
- TokenTree clone() const;
-
- bool is_token() const {
- return m_tok.type() != TOK_NULL;
- }
- unsigned int size() const {
- return m_subtrees.size();
- }
- const TokenTree& operator[](unsigned int idx) const { return m_subtrees[idx]; }
- TokenTree& operator[](unsigned int idx) { return m_subtrees[idx]; }
- const Token& tok() const { return m_tok; }
- Token& tok() { return m_tok; }
- const Ident::Hygiene& hygiene() const { return m_hygiene; }
-
- friend ::std::ostream& operator<<(::std::ostream& os, const TokenTree& tt);
-};
-
-#endif // TOKENTREE_HPP_INCLUDED
+/*
+ * MRustC - Rust Compiler
+ * - By John Hodge (Mutabah/thePowersGang)
+ *
+ * parse/tokentree.hpp
+ * - Token Trees (groups of tokens
+ */
+#ifndef TOKENTREE_HPP_INCLUDED
+#define TOKENTREE_HPP_INCLUDED
+
+#include "token.hpp"
+#include <ident.hpp>
+#include <vector>
+
+class TokenTree
+{
+ Ident::Hygiene m_hygiene;
+ Token m_tok;
+ ::std::vector<TokenTree> m_subtrees;
+public:
+ virtual ~TokenTree() {}
+ TokenTree() {}
+ TokenTree(TokenTree&&) = default;
+ TokenTree& operator=(TokenTree&&) = default;
+ TokenTree(enum eTokenType ty):
+ m_tok( Token(ty) )
+ {
+ }
+ TokenTree(Token tok):
+ m_tok( ::std::move(tok) )
+ {
+ }
+ TokenTree(Ident::Hygiene hygiene, Token tok):
+ m_hygiene( ::std::move(hygiene) ),
+ m_tok( ::std::move(tok) )
+ {
+ }
+ TokenTree(Ident::Hygiene hygiene, ::std::vector<TokenTree> subtrees):
+ m_hygiene( ::std::move(hygiene) ),
+ m_subtrees( ::std::move(subtrees) )
+ {
+ }
+
+ TokenTree clone() const;
+
+ bool is_token() const {
+ return m_tok.type() != TOK_NULL;
+ }
+ unsigned int size() const {
+ return m_subtrees.size();
+ }
+ const TokenTree& operator[](unsigned int idx) const { return m_subtrees[idx]; }
+ TokenTree& operator[](unsigned int idx) { return m_subtrees[idx]; }
+ const Token& tok() const { return m_tok; }
+ Token& tok() { return m_tok; }
+ const Ident::Hygiene& hygiene() const { return m_hygiene; }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const TokenTree& tt);
+};
+
+#endif // TOKENTREE_HPP_INCLUDED
diff --git a/src/parse/ttstream.hpp b/src/parse/ttstream.hpp
index 575178ac..946cca5f 100644
--- a/src/parse/ttstream.hpp
+++ b/src/parse/ttstream.hpp
@@ -21,7 +21,7 @@ public:
~TTStream();
TTStream& operator=(const TTStream& x) { m_stack = x.m_stack; return *this; }
-
+
Position getPosition() const override;
protected:
@@ -44,7 +44,7 @@ public:
TTStreamO& operator=(const TTStreamO& x) { m_stack = x.m_stack; return *this; }
TTStreamO& operator=(TTStreamO&& x) = default;
-
+
Position getPosition() const override;
protected:
diff --git a/src/parse/types.cpp b/src/parse/types.cpp
index 4cd9d755..cb664f79 100644
--- a/src/parse/types.cpp
+++ b/src/parse/types.cpp
@@ -32,7 +32,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
auto ps = lex.start_span();
Token tok;
-
+
switch( GET_TOK(tok, lex) )
{
case TOK_INTERPOLATED_TYPE:
@@ -45,7 +45,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
// '_' = Wildcard (type inferrence variable)
case TOK_UNDERSCORE:
return TypeRef(Span(tok.get_pos()));
-
+
// 'unsafe' - An unsafe function type
case TOK_RWORD_UNSAFE:
// 'extern' - A function type with an ABI
@@ -54,10 +54,10 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
case TOK_RWORD_FN:
PUTBACK(tok, lex);
return Parse_Type_Fn(lex);
-
+
case TOK_RWORD_IMPL:
return Parse_Type_ErasedType(lex, allow_trait_list);
-
+
// '<' - An associated type cast
case TOK_LT:
case TOK_DOUBLE_LT: {
@@ -65,7 +65,7 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
auto path = Parse_Path(lex, PATH_GENERIC_TYPE);
return TypeRef(TypeRef::TagPath(), lex.end_span(ps), mv$(path));
}
- //
+ //
case TOK_RWORD_FOR: {
auto hrls = Parse_HRB(lex);
switch(LOOK_AHEAD(lex))
@@ -156,14 +156,14 @@ TypeRef Parse_Type_Int(TokenStream& lex, bool allow_trait_list)
throw ParseError::Unexpected(lex, tok/*, "; or ]"*/);
}
}
-
+
// '(' - Tuple (or lifetime bounded trait)
case TOK_PAREN_OPEN: {
DEBUG("Tuple");
if( GET_TOK(tok, lex) == TOK_PAREN_CLOSE )
return TypeRef(TypeRef::TagTuple(), lex.end_span(ps), {});
PUTBACK(tok, lex);
-
+
TypeRef inner = Parse_Type(lex, true);
if( LOOK_AHEAD(lex) == TOK_PAREN_CLOSE )
{
@@ -198,12 +198,12 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls)
// TODO: HRLs
TRACE_FUNCTION;
Token tok;
-
+
::std::string abi = "";
bool is_unsafe = false;
-
+
GET_TOK(tok, lex);
-
+
if( tok.type() == TOK_RWORD_UNSAFE )
{
is_unsafe = true;
@@ -231,7 +231,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls)
if( LOOK_AHEAD(lex) == TOK_TRIPLE_DOT ) {
GET_TOK(tok, lex);
is_variadic = true;
- break;
+ break;
}
// Handle `ident: `
if( lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_COLON ) {
@@ -245,7 +245,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls)
}
}
GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE);
-
+
TypeRef ret_type = TypeRef(TypeRef::TagUnit(), Span(tok.get_pos()));
if( GET_TOK(tok, lex) == TOK_THINARROW )
{
@@ -254,7 +254,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls)
else {
PUTBACK(tok, lex);
}
-
+
return TypeRef(TypeRef::TagFunction(), lex.end_span(ps), is_unsafe, mv$(abi), mv$(args), is_variadic, mv$(ret_type));
}
@@ -263,7 +263,7 @@ TypeRef Parse_Type_Path(TokenStream& lex, ::std::vector<::std::string> hrls, boo
Token tok;
auto ps = lex.start_span();
-
+
if( ! allow_trait_list )
{
return TypeRef(TypeRef::TagPath(), lex.end_span(ps), Parse_Path(lex, PATH_GENERIC_TYPE));
@@ -307,7 +307,7 @@ TypeRef Parse_Type_ErasedType(TokenStream& lex, bool allow_trait_list)
traits.push_back( Parse_Path(lex, PATH_GENERIC_TYPE) );
} while( GET_TOK(tok, lex) == TOK_PLUS );
PUTBACK(tok, lex);
-
+
if( lifetimes.size() )
DEBUG("TODO: Lifetime bounds on erased types");
return TypeRef(lex.end_span(ps), TypeData::make_ErasedType({ {}, mv$(traits) }));