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