summaryrefslogtreecommitdiff
path: root/src/parse/root.cpp
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2019-11-02 11:07:23 +0800
committerJohn Hodge <tpg@ucc.asn.au>2019-11-02 11:07:23 +0800
commit1d02810c3cf908bfba7c15ae50eb5314603b9d85 (patch)
tree79dd5e4ef4c3ff79db0912ba546f08e61a7a8c10 /src/parse/root.cpp
parent7111acba04d72fe4084b1a1f3209ff83efe8614d (diff)
parent8b53b38f40625ab0510f541d69db3f83332a830a (diff)
downloadmrust-1d02810c3cf908bfba7c15ae50eb5314603b9d85.tar.gz
Merge branch 'nightly-1.29' - #95 Working support for rustc 1.29
Diffstat (limited to 'src/parse/root.cpp')
-rw-r--r--src/parse/root.cpp920
1 files changed, 566 insertions, 354 deletions
diff --git a/src/parse/root.cpp b/src/parse/root.cpp
index bc001c99..e81055ec 100644
--- a/src/parse/root.cpp
+++ b/src/parse/root.cpp
@@ -18,14 +18,17 @@
#include <expand/cfg.hpp> // check_cfg - for `mod nonexistant;`
#include <fstream> // Used by directory path
#include "lex.hpp" // New file lexer
+#include <parse/interpolated_fragment.hpp>
#include <ast/expr.hpp>
+#include <macro_rules/macro_rules.hpp>
+#include <path.h>
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( mv$(ps) ),
+ lex.end_span(ps),
mv$(v)
};
}
@@ -34,7 +37,7 @@ Spanned<T> get_spanned(TokenStream& lex, ::std::function<T()> f) {
// Check the next two tokens
#define LOOKAHEAD2(lex, tok1, tok2) ((lex).lookahead(0) == (tok1) && (lex).lookahead(1) == (tok2))
-::std::string dirname(::std::string input) {
+::helpers::path dirname(::std::string input) {
while( input.size() > 0 && input.back() != '/' && input.back() != '\\' ) {
input.pop_back();
}
@@ -47,10 +50,20 @@ AST::Attribute Parse_MetaItem(TokenStream& lex);
void Parse_ModRoot(TokenStream& lex, AST::Module& mod, AST::AttributeList& mod_attrs);
bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv);
-//::AST::Path Parse_Publicity(TokenStream& lex)
-bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true)
+::AST::Visibility Parse_Publicity(TokenStream& lex, bool allow_restricted/*=true*/)
{
Token tok;
+ if( LOOK_AHEAD(lex) == TOK_INTERPOLATED_VIS )
+ {
+ GET_TOK(tok, lex);
+ return tok.take_frag_vis();
+ }
+ if( LOOK_AHEAD(lex) == TOK_RWORD_CRATE )
+ {
+ // TODO: Return a path that indicates the entire current crate
+ GET_TOK(tok, lex);
+ return true;
+ }
if( LOOK_AHEAD(lex) == TOK_RWORD_PUB )
{
GET_TOK(tok, lex);
@@ -98,12 +111,12 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true)
GET_CHECK_TOK(tok, lex, TOK_IDENT);
case TOK_RWORD_IN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- path.nodes().push_back( AST::PathNode(tok.str()) );
+ path.nodes().push_back( AST::PathNode(tok.istr()) );
while( LOOK_AHEAD(lex) == TOK_DOUBLE_COLON )
{
GET_TOK(tok, lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- path.nodes().push_back( AST::PathNode(tok.str()) );
+ path.nodes().push_back( AST::PathNode(tok.istr()) );
}
break;
default:
@@ -137,7 +150,7 @@ bool Parse_Publicity(TokenStream& lex, bool allow_restricted=true)
switch(GET_TOK(tok, lex))
{
case TOK_LIFETIME:
- rv.m_lifetimes.push_back(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), Ident(lex.getHygiene(), tok.str())));
+ rv.m_lifetimes.push_back(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), lex.get_ident(mv$(tok))));
break;
default:
throw ParseError::Unexpected(lex, tok, Token(TOK_LIFETIME));
@@ -163,7 +176,7 @@ namespace {
AST::LifetimeRef get_LifetimeRef(TokenStream& lex, Token tok)
{
CHECK_TOK(tok, TOK_LIFETIME);
- return AST::LifetimeRef(/*lex.point_span(), */Ident(lex.getHygiene(), mv$(tok.str())));
+ return AST::LifetimeRef(/*lex.point_span(), */lex.get_ident(mv$(tok)));
}
}
/// Parse type parameters in a definition
@@ -230,7 +243,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex)
GET_TOK(tok, lex);
if( tok.type() == TOK_IDENT )
{
- ::std::string param_name = mv$(tok.str());
+ auto param_name = tok.istr();
ret.add_ty_param( AST::TypeParam( lex.point_span(), ::std::move(attrs), param_name ) );
auto param_ty = TypeRef(lex.point_span(), param_name);
@@ -248,7 +261,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex)
}
else if( tok.type() == TOK_LIFETIME )
{
- auto param_name = tok.str();
+ auto param_name = tok.istr();
auto ref = get_LifetimeRef(lex, mv$(tok));
ret.add_lft_param(::AST::LifetimeParam(lex.point_span(), ::std::move(attrs), Ident(lex.getHygiene(), param_name) ));
if( GET_TOK(tok, lex) == TOK_COLON )
@@ -499,7 +512,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_
PUTBACK(tok, lex);
}
- return AST::Function(lex.end_span( mv$(ps) ), mv$(params), mv$(abi), is_unsafe, is_const, is_variadic, mv$(ret_type), mv$(args));
+ 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)
@@ -609,7 +622,7 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::AttributeList& meta_items)
bool is_pub = Parse_Publicity(lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
TypeRef type = Parse_Type(lex);
@@ -628,6 +641,140 @@ AST::Struct Parse_Struct(TokenStream& lex, const AST::AttributeList& meta_items)
}
}
+AST::Named<AST::Item> Parse_Trait_Item(TokenStream& lex)
+{
+ Token tok;
+
+ auto item_attrs = Parse_ItemAttrs(lex);
+ SET_ATTRS(lex, item_attrs);
+
+ auto ps = lex.start_span();
+ {
+ ::AST::MacroInvocation inv;
+ if( Parse_MacroInvocation_Opt(lex, inv) )
+ {
+ return AST::Named<AST::Item>( lex.end_span(ps), mv$(item_attrs), false, "", AST::Item(mv$(inv)) );
+ }
+ }
+
+ GET_TOK(tok, lex);
+ bool is_specialisable = false;
+ if( tok.type() == TOK_IDENT && tok.istr() == "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;
+
+ RcString name;
+ ::AST::Item rv;
+ switch(tok.type())
+ {
+ case TOK_RWORD_STATIC: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ 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);
+
+ rv = ::AST::Static(::AST::Static::STATIC, mv$(ty), val);
+ break; }
+ case TOK_RWORD_CONST: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ 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);
+
+ rv = ::AST::Static(AST::Static::CONST, mv$(ty), val);
+ break; }
+ // Associated type
+ case TOK_RWORD_TYPE: {
+ auto atype_params = ::AST::GenericParams { };
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ if( GET_TOK(tok, lex) == TOK_COLON )
+ {
+ // Bounded associated type
+ Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "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.point_span() );
+ if( tok.type() == TOK_EQUAL ) {
+ default_type = Parse_Type(lex);
+ GET_TOK(tok, lex);
+ }
+
+ CHECK_TOK(tok, TOK_SEMICOLON);
+ rv = ::AST::TypeAlias( mv$(atype_params), mv$(default_type) );
+ break; }
+
+ // Functions (possibly unsafe)
+ 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);
+ name = tok.istr();
+ // 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);
+ // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?)
+ lex.push_hygine();
+ fcn.set_code( Parse_ExprBlock(lex) );
+ lex.pop_hygine();
+ }
+ else if( tok.type() == TOK_SEMICOLON )
+ {
+ // Accept it
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ rv = ::std::move(fcn);
+ break; }
+ default:
+ throw ParseError::Unexpected(lex, tok);
+ }
+
+ return ::AST::Named<::AST::Item>( lex.end_span(ps), mv$(item_attrs), true, mv$(name), mv$(rv) );
+}
+
AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items)
{
TRACE_FUNCTION;
@@ -649,9 +796,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items
// TODO: Just add these as `where Self: <foo>` (would that break typecheck?)
do {
if( GET_TOK(tok, lex) == TOK_LIFETIME ) {
- // TODO: Need a better way of indiciating 'static than just an invalid path
- ASSERT_BUG(lex.point_span(), tok.str() == "static", "TODO: Support lifetimes other than 'static in trait bounds");
- supertraits.push_back( make_spanned( Span(tok.get_pos()), Type_TraitPath{ {}, AST::Path() } ) );
+ params.add_bound(::AST::GenericBound::make_TypeLifetime({ TypeRef(lex.point_span(), "Self"), ::AST::LifetimeRef(lex.get_ident(tok)) }));
}
else if( tok.type() == TOK_BRACE_OPEN ) {
break;
@@ -680,131 +825,7 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::AttributeList& meta_items
{
PUTBACK(tok, lex);
- auto item_attrs = Parse_ItemAttrs(lex);
- SET_ATTRS(lex, item_attrs);
-
- auto ps = lex.start_span();
- {
- ::AST::MacroInvocation inv;
- if( Parse_MacroInvocation_Opt(lex, inv) )
- {
- trait.items().push_back( AST::Named<AST::Item>("", AST::Item(mv$(inv)), false) );
- continue ;
- }
- GET_TOK(tok, lex);
- }
-
- 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);
-
- trait.add_static( mv$(name), mv$(item_attrs), ::AST::Static(AST::Static::STATIC, mv$(ty), val) );
- break; }
- case TOK_RWORD_CONST: {
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
- GET_CHECK_TOK(tok, lex, TOK_COLON);
- auto ty = Parse_Type(lex);
-
- ::AST::Expr val;
- if(GET_TOK(tok, lex) == TOK_EQUAL) {
- val = Parse_Expr(lex);
- GET_TOK(tok, lex);
- }
- CHECK_TOK(tok, TOK_SEMICOLON);
-
- trait.add_static( mv$(name), mv$(item_attrs), ::AST::Static(AST::Static::CONST, mv$(ty), val) );
- 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.point_span(), "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.point_span() );
- 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), mv$(item_attrs), ::std::move(default_type) );
- trait.items().back().data.as_Type().params() = mv$(atype_params);
- break; }
-
- // Functions (possibly unsafe)
- 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);
- // Enter a new hygine scope for the function body. (TODO: Should this be in Parse_ExprBlock?)
- lex.push_hygine();
- fcn.set_code( Parse_ExprBlock(lex) );
- lex.pop_hygine();
- }
- else if( tok.type() == TOK_SEMICOLON )
- {
- // Accept it
- }
- else
- {
- throw ParseError::Unexpected(lex, tok);
- }
- trait.add_function( ::std::move(name), mv$(item_attrs), ::std::move(fcn) );
- break; }
- default:
- throw ParseError::Unexpected(lex, tok);
- }
+ trait.items().push_back( Parse_Trait_Item(lex) );
}
return trait;
@@ -842,7 +863,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items)
SET_ATTRS(lex, item_attrs);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- ::std::string name = mv$(tok.str());
+ auto name = tok.istr();
// Tuple-like variants
if( GET_TOK(tok, lex) == TOK_PAREN_OPEN )
{
@@ -880,7 +901,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items)
auto field_attrs = Parse_ItemAttrs(lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
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)) );
@@ -945,7 +966,7 @@ AST::Enum Parse_EnumDef(TokenStream& lex, const AST::AttributeList& meta_items)
bool is_pub = Parse_Publicity(lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto ty = Parse_Type(lex);
@@ -988,34 +1009,56 @@ AST::Attribute Parse_MetaItem(TokenStream& lex)
{
TRACE_FUNCTION;
Token tok;
- GET_TOK(tok, lex);
- if( tok.type() == TOK_INTERPOLATED_META ) {
+ if( lex.lookahead(0) == TOK_INTERPOLATED_META ) {
+ GET_TOK(tok, lex);
return mv$(tok.frag_meta());
}
auto ps = lex.start_span();
- CHECK_TOK(tok, TOK_IDENT);
- ::std::string name = mv$(tok.str());
+ GET_TOK(tok, lex);
+
+ switch(tok.type())
+ {
+ case TOK_IDENT:
+ break;
+ case TOK_INTEGER:
+ if( TARGETVER_1_29 )
+ return AST::Attribute(lex.end_span(ps), "", tok.to_str());
+ default:
+ throw ParseError::Unexpected(lex, tok, {TOK_IDENT, TOK_INTEGER});
+ }
+
+ auto name = tok.istr();
switch(GET_TOK(tok, lex))
{
case TOK_EQUAL:
switch(GET_TOK(tok, lex))
{
case TOK_STRING:
- return AST::Attribute(lex.end_span(mv$(ps)), name, tok.str());
+ return AST::Attribute(lex.end_span(ps), name, tok.str());
case TOK_INTERPOLATED_EXPR: {
auto n = tok.take_frag_node();
+ void Expand_BareExpr(const AST::Crate& , const AST::Module&, ::std::unique_ptr<AST::ExprNode>& n);
+ assert( lex.parse_state().crate );
+ assert( lex.parse_state().module );
+ Expand_BareExpr(*lex.parse_state().crate, *lex.parse_state().module, n);
if( auto* v = dynamic_cast<::AST::ExprNode_String*>(&*n) )
{
- return AST::Attribute(lex.end_span(mv$(ps)), name, mv$(v->m_value));
+ return AST::Attribute(lex.end_span(ps), name, mv$(v->m_value));
}
else
{
// - Force an error.
- CHECK_TOK(tok, TOK_STRING);
+ throw ParseError::Unexpected(lex, Token(InterpolatedFragment(InterpolatedFragment::EXPR, n.release())), TOK_STRING);
}
break; }
+ case TOK_INTEGER:
+ if( TARGETVER_1_29 )
+ return AST::Attribute(lex.end_span(ps), name, tok.to_str());
+ case TOK_IDENT:
+ if( TARGETVER_1_29 )
+ return AST::Attribute(lex.end_span(ps), name, tok.to_str());
default:
// - Force an error.
CHECK_TOK(tok, TOK_STRING);
@@ -1031,10 +1074,10 @@ AST::Attribute Parse_MetaItem(TokenStream& lex)
items.push_back(Parse_MetaItem(lex));
} while(GET_TOK(tok, lex) == TOK_COMMA);
CHECK_TOK(tok, TOK_PAREN_CLOSE);
- return AST::Attribute(lex.end_span(mv$(ps)), name, mv$(items)); }
+ return AST::Attribute(lex.end_span(ps), name, mv$(items)); }
default:
PUTBACK(tok, lex);
- return AST::Attribute(lex.end_span(mv$(ps)), name);
+ return AST::Attribute(lex.end_span(ps), name);
}
}
@@ -1145,7 +1188,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
if( Parse_MacroInvocation_Opt(lex, inv) )
{
impl.add_macro_invocation( mv$(inv) );
- impl.items().back().data->attrs = mv$(item_attrs);
+ impl.items().back().attrs = mv$(item_attrs);
return ;
}
}
@@ -1156,7 +1199,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
GET_TOK(tok, lex);
bool is_specialisable = false;
- if( tok.type() == TOK_IDENT && tok.str() == "default" ) {
+ if( tok.type() == TOK_IDENT && tok.istr() == "default" ) {
is_specialisable = true;
GET_TOK(tok, lex);
}
@@ -1168,10 +1211,11 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
{
case TOK_RWORD_TYPE: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
- impl.add_type(is_public, is_specialisable, name, Parse_Type(lex));
+ auto ty = Parse_Type(lex);
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ impl.add_type(lex.end_span(ps), mv$(item_attrs), is_public, is_specialisable, name, mv$(ty));
break; }
case TOK_RWORD_UNSAFE:
fn_is_unsafe = true;
@@ -1183,7 +1227,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
if( tok.type() != TOK_RWORD_FN && tok.type() != TOK_RWORD_UNSAFE && !fn_is_unsafe )
{
CHECK_TOK(tok, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
auto ty = Parse_Type(lex);
GET_CHECK_TOK(tok, lex, TOK_EQUAL);
@@ -1191,7 +1235,7 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
auto i = ::AST::Static(AST::Static::CONST, mv$(ty), mv$(val));
- impl.add_static( is_public, is_specialisable, mv$(name), mv$(i) );
+ impl.add_static( lex.end_span(ps), mv$(item_attrs), is_public, is_specialisable, mv$(name), mv$(i) );
break ;
}
else if( tok.type() == TOK_RWORD_UNSAFE )
@@ -1218,19 +1262,16 @@ void Parse_Impl_Item(TokenStream& lex, AST::Impl& impl)
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());
+ auto name = tok.istr();
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));
+ impl.add_function(lex.end_span(ps), mv$(item_attrs), is_public, is_specialisable, mv$(name), mv$(fcn));
break; }
default:
throw ParseError::Unexpected(lex, tok);
}
-
- impl.items().back().data->span = lex.end_span(mv$(ps));
- impl.items().back().data->attrs = mv$(item_attrs); // Empty for functions
}
AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::AttributeList& block_attrs)
@@ -1255,16 +1296,13 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A
{
case TOK_RWORD_FN: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
// 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(mv$(ps));
-
- rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
+ rv.add_item( AST::Named<AST::Item> { lex.end_span(ps), mv$(meta_items), is_public, mv$(name), mv$(i) } );
break; }
case TOK_RWORD_STATIC: {
bool is_mut = false;
@@ -1273,62 +1311,104 @@ AST::ExternBlock Parse_ExternBlock(TokenStream& lex, ::std::string abi, ::AST::A
else
PUTBACK(tok, lex);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
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(mv$(ps));
- rv.add_item( AST::Named<AST::Item> { mv$(name), mv$(i), is_public } );
+ rv.add_item( AST::Named<AST::Item> { lex.end_span(ps), mv$(meta_items), is_public, mv$(name), mv$(i) } );
+ break; }
+ case TOK_RWORD_TYPE: {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = tok.istr();
+ GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
+ auto sp = lex.end_span(ps);
+ //TODO(sp, "Extern type");
+ auto i = ::AST::Item(::AST::TypeAlias( ::AST::GenericParams(), ::TypeRef(sp) ));
+ rv.add_item( AST::Named<AST::Item> { mv$(sp), mv$(meta_items), is_public, mv$(name), mv$(i) } );
break; }
default:
- throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC});
+ throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_STATIC, TOK_RWORD_TYPE});
}
}
return rv;
}
-void Parse_Use_Wildcard(Span sp, AST::Path base_path, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
+/// Parse multiple items from a use "statement"
+void Parse_Use_Inner(TokenStream& lex, ::std::vector<AST::UseItem::Ent>& entries, AST::Path& path)
{
- 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);
+ do
+ {
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_IDENT:
+ path.append( AST::PathNode( tok.istr(), {}) );
+ break;
+ case TOK_BRACE_OPEN:
+ // Can't be an empty list
+ if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ // Keep looping until a comma
+ do {
+ if( LOOK_AHEAD(lex) == TOK_BRACE_CLOSE ) {
+ // Trailing comma
+ GET_TOK(tok, lex);
+ break;
+ }
+ // - Handle `self` in braces differently
+ else if( LOOK_AHEAD(lex) == TOK_RWORD_SELF ) {
+ GET_TOK(tok, lex);
+ auto name = path.nodes().back().name();
+ if( LOOK_AHEAD(lex) == TOK_RWORD_AS ) {
+ GET_TOK(tok, lex);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ }
+ entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) });
+ }
+ else {
+ size_t l = path.nodes().size();
+
+ Parse_Use_Inner(lex, entries, path);
+
+ assert(l <= path.nodes().size());
+ path.nodes().resize( l );
+ }
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+ return;
+ case TOK_STAR:
+ entries.push_back({ lex.point_span(), AST::Path(path), "" });
+ return ;
+ default:
+ throw ParseError::Unexpected(lex, tok);
}
- fcn(AST::UseStmt(lex.end_span(ps), mv$(path)), mv$(name));
- } while( GET_TOK(tok, lex) == TOK_COMMA );
- PUTBACK(tok, lex);
-}
+ } while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON );
+
+ RcString name;
-void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::string)> fcn)
+ // NOTE: The above loop has to run once, so the last token HAS to have been an ident
+ if( tok.type() == TOK_RWORD_AS )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ name = tok.istr();
+ }
+ else
+ {
+ PUTBACK(tok, lex);
+ ASSERT_BUG(lex.point_span(), path.nodes().size() > 0, "`use` with no path");
+ name = path.nodes().back().name();
+ }
+
+ // TODO: Get a span covering the final node.
+ entries.push_back({ lex.point_span(), AST::Path(path), ::std::move(name) });
+}
+::AST::UseItem Parse_Use(TokenStream& lex)
{
TRACE_FUNCTION;
@@ -1337,10 +1417,13 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::strin
::std::vector<AST::PathNode> nodes;
ProtoSpan span_start = lex.start_span();
+ ::std::vector<AST::UseItem::Ent> entries;
+
switch( GET_TOK(tok, lex) )
{
case TOK_RWORD_SELF:
path = AST::Path( AST::Path::TagSelf(), {} ); // relative path
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
case TOK_RWORD_SUPER: {
unsigned int count = 1;
@@ -1350,9 +1433,11 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::strin
count += 1;
}
path = AST::Path( AST::Path::TagSuper(), count, {} );
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break; }
- case TOK_IDENT:
- path.append( AST::PathNode(mv$(tok.str()), {}) );
+ case TOK_RWORD_CRATE:
+ // 1.29 absolute path
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
// Leading :: is allowed and ignored for the $crate feature
case TOK_DOUBLE_COLON:
@@ -1361,77 +1446,35 @@ void Parse_Use(TokenStream& lex, ::std::function<void(AST::UseStmt, ::std::strin
if( LOOK_AHEAD(lex) == TOK_STRING )
{
GET_CHECK_TOK(tok, lex, TOK_STRING);
- path = ::AST::Path(tok.str(), {});
+ path = ::AST::Path(RcString::new_interned(tok.str()), {});
}
- else {
+ else
+ {
PUTBACK(tok, lex);
}
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
- case TOK_BRACE_OPEN:
- Parse_Use_Set(lex, span_start, path, fcn);
- GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
- return;
- case TOK_STAR:
- Parse_Use_Wildcard( lex.end_span(span_start), mv$(path), fcn );
- return;
case TOK_INTERPOLATED_PATH:
path = mv$(tok.frag_path());
+ GET_CHECK_TOK(tok, lex, TOK_DOUBLE_COLON);
break;
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_BUG(lex.point_span(), path.nodes().size() > 0, "`use` with no path");
- name = path.nodes().back().name();
+ break;
}
- fcn( AST::UseStmt(lex.end_span(span_start), mv$(path)), name);
+ Parse_Use_Inner(lex, entries, path);
+
+ return AST::UseItem { lex.end_span(span_start), mv$(entries) };
}
-::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, ::std::string name, TokenStream& lex)
+::AST::MacroInvocation Parse_MacroInvocation(ProtoSpan span_start, RcString name, TokenStream& lex)
{
Token tok;
- ::std::string ident;
+ RcString ident;
if( GET_TOK(tok, lex) == TOK_IDENT ) {
- ident = mv$(tok.str());
+ ident = tok.istr();
}
else {
PUTBACK(tok, lex);
@@ -1448,14 +1491,19 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
{
// Good
}
+ else if( lex.lookahead(0) == TOK_INTERPOLATED_PATH && lex.lookahead(1) == TOK_EXCLAM )
+ {
+ // Also good.
+ }
else
{
return false;
}
auto ps = lex.start_span();
- GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = tok.str();
+ auto name_path = Parse_Path(lex, PATH_GENERIC_NONE);
+ ASSERT_BUG(lex.point_span(), name_path.nodes().size() == 1, "TODO: Support multi-component paths in macro invocations");
+ auto name = name_path.nodes()[0].name();
GET_CHECK_TOK(tok, lex, TOK_EXCLAM);
bool is_braced = (lex.lookahead(0) == TOK_BRACE_OPEN || (lex.lookahead(0) == TOK_IDENT && lex.lookahead(1) == TOK_BRACE_OPEN));
@@ -1469,6 +1517,102 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
return true;
}
+#if 0
+namespace {
+ ::AST::Module::FileInfo get_submod_file(
+ Span sp, const ::AST::Module::FileInfo& parent_fileinfo, const ::std::string& new_mod_name, const ::std::string& path_attr,
+ bool is_extern_file, bool is_cfg_disabled
+ )
+ {
+ ::AST::Module::FileInfo rv;
+ TRACE_FUNCTION_F(new_mod_name << ", " << path_attr << ", " << is_extern_file);
+ ::std::string sub_path;
+ bool sub_file_controls_dir = true;
+
+ // 1. Determine the base path for the module
+ if( parent_fileinfo.path == "-" ) {
+ if( path_attr.size() ) {
+ ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
+ }
+ sub_path = "-";
+ }
+ else if( path_attr.size() > 0 )
+ {
+ // #[path] present, add to the parent path
+ sub_path = dirname(parent_fileinfo.path) + path_attr;
+ }
+ else if( mod_fileinfo.controls_dir )
+ {
+ // The parent module is either the crate root, or a `mod.rs` (or otherwise a controller)
+ sub_path = parent_fileinfo.dir + name;
+ }
+ else
+ {
+ sub_path = parent_fileinfo.path;
+ sub_file_controls_dir = false;
+ }
+ DEBUG("Mod '" << name << "', sub_path = " << sub_path);
+
+ rv.path = sub_path;
+ rv.controls_dir = sub_file_controls_dir;
+
+ if( is_cfg_disabled || parent_fileinfo.force_no_load )
+ {
+ rv.force_no_load = true;
+ }
+ if( ! is_extern_file )
+ {
+ // If this is an inline module, set the path to just a directory
+ if( sub_path != "-" ) {
+ rv.path = sub_path + "/";
+ rv.dir = sub_path + "/";
+ }
+ else {
+ rv.path = "-";
+ }
+ }
+ else
+ {
+ if( sub_path == "-" )
+ {
+ ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
+ }
+ 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.point_span(), E0000, "Both modname.rs and modname/mod.rs exist");
+ }
+ else if( ifs_dir.is_open() )
+ {
+ // Load from dir
+ rv.path = newpath_dir + "mod.rs";
+ rv.dir = newpath_dir;
+ }
+ else if( ifs_file.is_open() )
+ {
+ rv.path = newpath_file;
+ rv.dir = newpath_dir;
+ rv.controls_dir = false;
+ }
+ else
+ {
+ // Can't find file
+ ERROR(sp, E0000, "Can't find file for '" << name << "' in '" << parent_fileinfo.dir << "'");
+ }
+ }
+ }
+ return rv;
+ }
+}
+#endif
+
::AST::Named<::AST::Item> Parse_Mod_Item_S(TokenStream& lex, const AST::Module::FileInfo& mod_fileinfo, const ::AST::Path& mod_path, AST::AttributeList meta_items)
{
TRACE_FUNCTION_F("mod_path="<<mod_path<<", meta_items="<<meta_items);
@@ -1489,24 +1633,20 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
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) );
+ rv.attrs.m_items.push_back( mv$(mi) );
return rv;
}
auto ps = lex.start_span();
- ::std::string item_name;
+ RcString item_name;
::AST::Item item_data;
{
::AST::MacroInvocation inv;
if( Parse_MacroInvocation_Opt(lex, inv) )
{
- item_data = ::AST::Item( mv$(inv) );
- item_data.attrs = mv$(meta_items);
- item_data.span = lex.end_span(mv$(ps));
-
- return ::AST::Named< ::AST::Item> { "", mv$(item_data), false };
+ return ::AST::Named< ::AST::Item> { lex.end_span(ps), mv$(meta_items), false, "", ::AST::Item( mv$(inv) ) };
}
}
@@ -1515,16 +1655,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
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.point_span(), "Encode multi-item use statements as a single Item");
- item_data = ::AST::Item(mv$(p));
- item_name = mv$(s);
- });
- assert( !item_data.is_None() );
+ item_data = Parse_Use(lex);
GET_CHECK_TOK(tok, lex, TOK_SEMICOLON);
break;
@@ -1540,7 +1671,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `extern "<ABI>" fn ...`
case TOK_RWORD_FN: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, abi, false, false,false) );
break; }
// `extern "ABI" {`
@@ -1555,7 +1686,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `extern fn ...`
case TOK_RWORD_FN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, "C", false, false,false) );
break;
@@ -1574,20 +1705,20 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `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() });
+ item_data = ::AST::Item::make_Crate({ RcString::new_interned(tok.str()) });
GET_CHECK_TOK(tok, lex, TOK_RWORD_AS);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
break;
// `extern crate crate_name;`
// `extern crate crate_name as other_name;`
case TOK_IDENT:
- item_name = mv$(tok.str());
+ item_name = tok.istr();
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());
+ item_name = tok.istr();
}
else {
PUTBACK(tok, lex);
@@ -1610,7 +1741,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
switch( GET_TOK(tok, lex) )
{
case TOK_IDENT: {
- item_name = mv$(tok.str());
+ item_name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
TypeRef type = Parse_Type(lex);
@@ -1622,12 +1753,12 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
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_name = tok.istr();
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());
+ item_name = tok.istr();
// - self not allowed, not prototype
item_data = ::AST::Item( Parse_FunctionDefWithCode(lex, ABI_RUST, false, false,true/*unsafe,const*/) );
break;
@@ -1644,7 +1775,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
GET_TOK(tok, lex);
}
CHECK_TOK(tok, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
GET_CHECK_TOK(tok, lex, TOK_COLON);
TypeRef type = Parse_Type(lex);
@@ -1674,20 +1805,20 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
}
GET_CHECK_TOK(tok, lex, TOK_RWORD_FN);
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
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());
+ item_name = tok.istr();
// - 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());
+ item_name = tok.istr();
auto tr = Parse_TraitDef(lex, meta_items);
tr.set_is_unsafe();
item_data = ::AST::Item( ::std::move(tr) );
@@ -1704,8 +1835,21 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
else {
BUG(lex.point_span(), "Parse_Impl returned a variant other than Impl or NegImpl");
}
- return ::AST::Named< ::AST::Item> { "", mv$(impl), false };
+ return ::AST::Named< ::AST::Item> { Span(), {}, false, "", mv$(impl) };
}
+ // `unsafe auto trait`
+ case TOK_IDENT:
+ if( TARGETVER_1_29 && tok.istr() == "auto" ) {
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = tok.istr();
+ auto tr = Parse_TraitDef(lex, meta_items);
+ tr.set_is_unsafe();
+ tr.set_is_marker();
+ item_data = ::AST::Item( ::std::move(tr) );
+ break;
+ }
+ //goto default;
default:
throw ParseError::Unexpected(lex, tok, {TOK_RWORD_FN, TOK_RWORD_TRAIT, TOK_RWORD_IMPL});
}
@@ -1713,65 +1857,142 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
// `fn`
case TOK_RWORD_FN:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
// - 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_name = tok.istr();
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_name = tok.istr();
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_name = tok.istr();
item_data = ::AST::Item( Parse_EnumDef(lex, meta_items) );
break;
// Contextual keywords
case TOK_IDENT:
- if( tok.str() == "union" ) {
+ if( tok.istr() == "union" ) {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_Union(lex, meta_items) );
}
+ // `auto trait`
+ else if( TARGETVER_1_29 && tok.istr() == "auto" ) {
+ GET_CHECK_TOK(tok, lex, TOK_RWORD_TRAIT);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ item_name = tok.istr();
+ auto tr = Parse_TraitDef(lex, meta_items);
+ tr.set_is_marker();
+ item_data = ::AST::Item( ::std::move(tr) );
+ }
else {
throw ParseError::Unexpected(lex, tok);
}
break;
// `impl`
case TOK_RWORD_IMPL:
- return ::AST::Named< ::AST::Item> { "", Parse_Impl(lex, mv$(meta_items)), false };
+ return ::AST::Named< ::AST::Item> { Span(), {}, false, "", Parse_Impl(lex, mv$(meta_items)) };
// `trait`
case TOK_RWORD_TRAIT:
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- item_name = mv$(tok.str());
+ item_name = tok.istr();
item_data = ::AST::Item( Parse_TraitDef(lex, meta_items) );
break;
+ case TOK_RWORD_MACRO:
+ if( TARGETVER_1_29 )
+ {
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ auto name = tok.istr();
+ if( lex.lookahead(0) != TOK_PAREN_OPEN )
+ {
+ GET_TOK(tok, lex);
+ throw ParseError::Unexpected(lex, tok);
+ }
+ DEBUG("name = " << name);
+
+ ::std::vector<RcString> names;
+ auto ps = lex.start_span();
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
+ auto arm_pat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names);
+ auto pat_span = lex.end_span(ps);
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
+ // TODO: Pass a flag that annotates all idents with the current module?
+ auto body = Parse_MacroRules_Cont(lex, TOK_BRACE_OPEN, TOK_BRACE_CLOSE, names);
+
+ auto mr = new MacroRules( );
+ mr->m_hygiene = lex.getHygiene();
+ {
+ Ident::ModPath mp;
+ for(const auto& node : mod_path.nodes())
+ {
+ mp.ents.push_back(node.name());
+ }
+ mr->m_hygiene.set_mod_path(::std::move(mp));
+ }
+ mr->m_rules.push_back(Parse_MacroRules_MakeArm(pat_span, ::std::move(arm_pat), ::std::move(body)));
+
+ item_name = name;
+ item_data = ::AST::Item( MacroRulesPtr(mr) );
+ }
+ else
+ {
+ throw ParseError::Unexpected(lex, tok);
+ }
+ break;
+
case TOK_RWORD_MOD: {
GET_CHECK_TOK(tok, lex, TOK_IDENT);
- auto name = mv$(tok.str());
+ auto name = tok.istr();
DEBUG("Sub module '" << name << "'");
AST::Module submod( mod_path + name );
+ // Check #[cfg] and don't load if it fails
+ struct H {
+ static bool check_item_cfg(const ::AST::AttributeList& attrs)
+ {
+ for(const auto& at : attrs.m_items) {
+ if( at.name() == "cfg" && !check_cfg(at.span(), at) ) {
+ return false;
+ }
+ }
+ return true;
+ }
+ };
+
// 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() : "");
+ ::std::string path_attr;
+ for(const auto& a : meta_items.m_items)
+ {
+ if( a.name() == "path" ) {
+ path_attr = a.string();
+ }
+ else if( a.name() == "cfg_attr" && a.items().at(1).name() == "path" ) {
+ if( check_cfg(a.span(), a.items().at(0)) ) {
+ path_attr = a.items().at(1).string();
+ }
+ }
+ else {
+ }
+ }
- //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON);
+ //submod.m_file_info = get_submod_file(lex.end_span(ps), mod_fileinfo, name, path_attr, LOOK_AHEAD(lex) == TOK_SEMICOLON, H::check_item_cfg(meta_items));
- ::std::string sub_path;
+ ::helpers::path sub_path;
bool sub_file_controls_dir = true;
if( mod_fileinfo.path == "-" ) {
if( path_attr.size() ) {
@@ -1781,15 +2002,16 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
}
else if( path_attr.size() > 0 )
{
- sub_path = dirname(mod_fileinfo.path) + path_attr;
+ sub_path = dirname(mod_fileinfo.path) / path_attr.c_str();
}
else if( mod_fileinfo.controls_dir )
{
- sub_path = dirname(mod_fileinfo.path) + name;
+ sub_path = dirname(mod_fileinfo.path) / name.c_str();
}
else
{
- sub_path = mod_fileinfo.path;
+ sub_path = dirname(mod_fileinfo.path) / mod_path.nodes().back().name().c_str() / name.c_str();
+ //sub_path = mod_fileinfo.path;
sub_file_controls_dir = false;
}
DEBUG("Mod '" << name << "', sub_path = " << sub_path);
@@ -1797,43 +2019,49 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
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::AttributeList& attrs)
- {
- for(const auto& at : attrs.m_items) {
- if( at.name() == "cfg" && !check_cfg(at.span(), at) ) {
- return false;
- }
- }
- return true;
- }
- };
-
switch( GET_TOK(tok, lex) )
{
case TOK_BRACE_OPEN:
- submod.m_file_info.path = sub_path + "/";
+ submod.m_file_info.path = sub_path.str() + "/";
+ // TODO: If cfg fails, just eat the TT until a matching #[cfg]?
+ // - Or, mark the file infor as not being valid (so child modules don't try to load)
Parse_ModRoot(lex, submod, meta_items);
GET_CHECK_TOK(tok, lex, TOK_BRACE_CLOSE);
break;
case TOK_SEMICOLON:
- if( sub_path == "-" ) {
+ if( sub_path.str() == "-" ) {
ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin");
}
- else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir )
- {
- ERROR(lex.point_span(), 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 if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir )
+ {
+ // TODO: Also search for curmod/submod.rs
+ //::std::string newpath_file = (mod_path.nodes().size() > 1 ? dirname(mod_fileinfo.path) + mod_path.nodes()[mod_path.nodes().size()-2].name() + "/" + name + ".rs" : "");
+ ::std::string newpath_file = (mod_path.nodes().size() >= 1 ? dirname(mod_fileinfo.path) / mod_path.nodes()[mod_path.nodes().size()-1].name().c_str() / name.c_str() + ".rs" : "");
+ DEBUG("newpath_file = '" << newpath_file << "' " << mod_fileinfo.path << " " << mod_path);
+ ::std::ifstream ifs_file(newpath_file);
+ if( ifs_file.is_open() )
+ {
+ submod.m_file_info.path = newpath_file;
+ submod.m_file_info.controls_dir = false;
+ 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);
+ }
+ else
+ {
+ ERROR(lex.point_span(), E0000, "Can't load from files outside of mod.rs or crate root");
+ }
+ }
else
{
- ::std::string newpath_dir = sub_path + "/";
+ ::std::string newpath_dir = sub_path.str() + "/";
::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");
@@ -1851,7 +2079,12 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
else if( ifs_file.is_open() )
{
submod.m_file_info.path = newpath_file;
+ if( path_attr == "" )
+ {
+ submod.m_file_info.controls_dir = false;
+ }
}
+ // TODO: If this is not a controlling file, look in `modname/` for the new module
else
{
// Can't find file
@@ -1874,10 +2107,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv)
throw ParseError::Unexpected(lex, tok);
}
- item_data.attrs = mv$(meta_items);
- item_data.span = lex.end_span(mv$(ps));
-
- return ::AST::Named< ::AST::Item> { mv$(item_name), mv$(item_data), is_public };
+ return ::AST::Named< ::AST::Item> { lex.end_span(ps), mv$(meta_items), is_public, mv$(item_name), mv$(item_data) };
}
void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_items)
@@ -1885,26 +2115,7 @@ void Parse_Mod_Item(TokenStream& lex, AST::Module& mod, AST::AttributeList meta_
SET_MODULE(lex, mod);
lex.parse_state().parent_attrs = &meta_items;
- //TRACE_FUNCTION;
- Token tok;
-
- // `use ...`
- // TODO: This doesn't spot `pub(path) use`.
- if( LOOK_AHEAD(lex) == TOK_RWORD_USE || (lex.lookahead(0) == TOK_RWORD_PUB && lex.lookahead(1) == TOK_RWORD_USE) )
- {
- bool is_public = Parse_Publicity(lex);
- GET_CHECK_TOK(tok, lex, TOK_RWORD_USE);
-
- 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)) );
- }
+ 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)
@@ -1959,6 +2170,7 @@ AST::Crate Parse_Crate(::std::string mainfile)
crate.root_module().m_file_info.path = mainpath;
crate.root_module().m_file_info.controls_dir = true;
+ lex.parse_state().crate = &crate;
Parse_ModRoot(lex, crate.root_module(), crate.m_attrs);
return crate;