From 5fae00d74e717a703d1bbc90536a003a205eae95 Mon Sep 17 00:00:00 2001 From: "John Hodge (sonata)" Date: Fri, 2 Jan 2015 19:10:22 +0800 Subject: Adding in support for std, parsing now broken due to TODO early in process --- src/ast/ast.cpp | 48 +++++++++++++++-- src/ast/ast.hpp | 80 +++++++++++++++++++++++---- src/ast/ast_expr.hpp | 14 +++++ src/ast/path.hpp | 27 +++++----- src/convert/resolve.cpp | 96 ++++++++++++++++++++++++++++++++- src/macros.hpp | 1 + src/parse/expr.cpp | 6 +-- src/parse/lex.cpp | 1 + src/parse/lex.hpp | 39 -------------- src/parse/root.cpp | 141 +++++++++++++++++++++++++++++++++++++++++++----- src/parse/tokentree.hpp | 39 ++++++++++++++ 11 files changed, 406 insertions(+), 86 deletions(-) (limited to 'src') diff --git a/src/ast/ast.cpp b/src/ast/ast.cpp index e1e6e877..7d151063 100644 --- a/src/ast/ast.cpp +++ b/src/ast/ast.cpp @@ -22,23 +22,49 @@ const ::std::vector& PathNode::args() const return m_params; } +Path& Path::operator+=(const Path& other) +{ + for(auto& node : other.m_nodes) + append(node); + return *this; +} +::std::ostream& operator<<(::std::ostream& os, const Path& path) +{ + switch(path.m_class) + { + case Path::RELATIVE: + os << "Path({" << path.m_nodes << "})"; + break; + case Path::ABSOLUTE: + os << "Path(TagAbsolute, {" << path.m_nodes << "})"; + break; + case Path::LOCAL: + os << "Path(TagLocal, " << path.m_nodes[0].name() << ")"; + break; + } + return os; +} + ::std::ostream& operator<<(::std::ostream& os, const Pattern& pat) { switch(pat.m_class) { + case Pattern::ANY: + os << "Pattern(TagWildcard, '" << pat.m_binding << "' @ _)"; + break; case Pattern::MAYBE_BIND: - os << "Pattern(TagMaybeBind, '" << pat.m_path[0].name() << "')"; + os << "Pattern(TagMaybeBind, '" << pat.m_binding << "')"; break; case Pattern::VALUE: //os << "Pattern(TagValue, " << *pat.m_node << ")"; - os << "Pattern(TagValue, TODO:ExprNode)"; + os << "Pattern(TagValue, '" << pat.m_binding << "' @ TODO:ExprNode)"; break; case Pattern::TUPLE: - os << "Pattern(TagTuple, " << pat.m_sub_patterns << ")"; + os << "Pattern(TagTuple, '" << pat.m_binding << "' @ [" << pat.m_sub_patterns << "])"; break; case Pattern::TUPLE_STRUCT: - os << "Pattern(TagEnumVariant, " << pat.m_path << ", " << pat.m_sub_patterns << ")"; + os << "Pattern(TagEnumVariant, '" << pat.m_binding << "' @ " << pat.m_path << ", [" << pat.m_sub_patterns << "])"; break; } return os; @@ -52,11 +78,25 @@ void Impl::add_function(bool is_public, Function fcn) { } +Crate::Crate(): + m_root_module(*this, ""), + m_load_std(true) +{ +} void Crate::iterate_functions(fcn_visitor_t* visitor) { m_root_module.iterate_functions(visitor, *this); } +void Module::add_ext_crate(::std::string ext_name, ::std::string int_name) +{ + DEBUG("add_ext_crate(\"" << ext_name << "\" as " << int_name << ")"); + if( ext_name == "std" ) + { + // HACK! Load std using a hackjob (included within the compiler) + } + throw ParseError::Todo("'extern crate'"); +} void Module::add_constant(bool is_public, ::std::string name, TypeRef type, Expr val) { ::std::cout << "add_constant()" << ::std::endl; diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp index 6c3e726c..0b124ad7 100644 --- a/src/ast/ast.hpp +++ b/src/ast/ast.hpp @@ -7,6 +7,7 @@ #include "../coretypes.hpp" #include +#include "../parse/tokentree.hpp" #include "../types.hpp" namespace AST { @@ -31,29 +32,43 @@ public: m_items(items) { } + + const ::std::string& name() const { return m_name; } }; class ExprNode; class Pattern { +public: enum BindType { MAYBE_BIND, + ANY, VALUE, TUPLE, TUPLE_STRUCT, }; +private: BindType m_class; + ::std::string m_binding; Path m_path; unique_ptr m_node; ::std::vector m_sub_patterns; public: - Pattern(); + Pattern(): + m_class(ANY) + {} + + struct TagBind {}; + Pattern(TagBind, ::std::string name): + m_class(ANY), + m_binding(name) + {} struct TagMaybeBind {}; Pattern(TagMaybeBind, ::std::string name): m_class(MAYBE_BIND), - m_path(Path::TagLocal(), name) + m_binding(name) {} struct TagValue {}; @@ -74,6 +89,21 @@ public: m_path( ::std::move(path) ), m_sub_patterns( ::std::move(sub_patterns) ) {} + + // Mutators + void set_bind(::std::string name) { + m_binding = name; + } + + // Accessors + const ::std::string& binding() const { return m_binding; } + BindType type() const { return m_class; } + ExprNode& node() { return *m_node; } + const ExprNode& node() const { return *m_node; } + Path& path() { return m_path; } + const Path& path() const { return m_path; } + ::std::vector& sub_patterns() { return m_sub_patterns; } + const ::std::vector& sub_patterns() const { return m_sub_patterns; } friend ::std::ostream& operator<<(::std::ostream& os, const Pattern& pat); }; @@ -152,33 +182,65 @@ public: }; +class Crate; class Module; typedef void fcn_visitor_t(const AST::Crate& crate, const AST::Module& mod, Function& fcn); class Module { - ::std::vector< ::std::pair > m_functions; + typedef ::std::vector< ::std::pair > itemlist_fcn_t; + typedef ::std::vector< ::std::pair > itemlist_mod_t; + typedef ::std::vector< ::std::tuple< ::std::string, Path, bool > > itemlist_use_t; + + const Crate& m_crate; + ::std::string m_name; + ::std::vector m_attrs; + itemlist_fcn_t m_functions; + itemlist_mod_t m_submods; + itemlist_use_t m_imports; public: - void add_alias(bool is_public, Path path) {} + Module(const Crate& crate, ::std::string name): + m_crate(crate), + m_name(name) + { + } + void add_ext_crate(::std::string ext_name, ::std::string imp_name); + void add_alias(bool is_public, Path path, ::std::string name) { + m_imports.push_back( ::std::make_tuple(name, path, is_public) ); + } void add_constant(bool is_public, ::std::string name, TypeRef type, Expr val); void add_global(bool is_public, bool is_mut, ::std::string name, TypeRef type, Expr val); void add_struct(bool is_public, ::std::string name, TypeParams params, ::std::vector items); void add_function(bool is_public, Function func); void add_impl(Impl impl); + void add_attr(MetaItem item) { + m_attrs.push_back(item); + } + void iterate_functions(fcn_visitor_t* visitor, const Crate& crate); + + const Crate& crate() const { return m_crate; } + + const ::std::string& name() const { return m_name; } + + const ::std::vector& attrs() const { return m_attrs; } + const itemlist_fcn_t& functions() const { return m_functions; } + const itemlist_mod_t& submods() const { return m_submods; } + const itemlist_use_t& imports() const { return m_imports; } }; class Crate { - Module m_root_module; public: - Crate(Module root_module): - m_root_module(root_module) - { - } + Module m_root_module; + bool m_load_std; + + Crate(); + Module& root_module() { return m_root_module; } + void iterate_functions( fcn_visitor_t* visitor ); }; diff --git a/src/ast/ast_expr.hpp b/src/ast/ast_expr.hpp index 223d7a4d..1b0a876d 100644 --- a/src/ast/ast_expr.hpp +++ b/src/ast/ast_expr.hpp @@ -28,6 +28,20 @@ struct ExprNode_Block: virtual void visit(NodeVisitor& nv) override; }; +struct ExprNode_Macro: + public ExprNode +{ + ::std::string m_name; + ::TokenTree m_tokens; + + ExprNode_Macro(::std::string name, ::TokenTree&& tokens): + m_name(name), + m_tokens( move(tokens) ) + {} + + virtual void visit(NodeVisitor& nv) override; +}; + // Return a value struct ExprNode_Return: public ExprNode diff --git a/src/ast/path.hpp b/src/ast/path.hpp index bc33c318..9887d192 100644 --- a/src/ast/path.hpp +++ b/src/ast/path.hpp @@ -66,6 +66,17 @@ public: m_class(LOCAL), m_nodes({PathNode(name, {})}) {} + + static Path add_tailing(const Path& a, const Path& b) { + Path ret(a); + for(const auto& ent : b.m_nodes) + ret.m_nodes.push_back(ent); + return ret; + } + Path operator+(const Path& x) const { + return Path(*this) += x; + } + Path& operator+=(const Path& x); void append(PathNode node) { m_nodes.push_back(node); @@ -79,21 +90,7 @@ public: PathNode& operator[](size_t idx) { return m_nodes[idx]; } const PathNode& operator[](size_t idx) const { return m_nodes[idx]; } - friend ::std::ostream& operator<<(::std::ostream& os, const Path& path) { - switch(path.m_class) - { - case RELATIVE: - os << "Path({" << path.m_nodes << "})"; - break; - case ABSOLUTE: - os << "Path(TagAbsolute, {" << path.m_nodes << "})"; - break; - case LOCAL: - os << "Path(TagLocal, " << path.m_nodes[0].name() << ")"; - break; - } - return os; - } + friend ::std::ostream& operator<<(::std::ostream& os, const Path& path); }; } // namespace AST diff --git a/src/convert/resolve.cpp b/src/convert/resolve.cpp index 504fec93..e1dea29f 100644 --- a/src/convert/resolve.cpp +++ b/src/convert/resolve.cpp @@ -1,4 +1,9 @@ /* + * "mrustc" Rust->C converter + * - By John Hodge (Mutabah / thePowersGang) + * + * convert/resolve.cpp + * - Resolve names into absolute format */ #include "../common.hpp" #include "../ast/ast.hpp" @@ -8,6 +13,7 @@ class CPathResolver { const AST::Crate& m_crate; const AST::Module& m_module; + const AST::Path m_module_path; ::std::vector< ::std::string > m_locals; // TODO: Maintain a stack of variable scopes @@ -47,12 +53,20 @@ public: { } + void visit(AST::ExprNode_Macro& node) { + throw ParseError::Todo("Resolve-time expanding of macros"); + + //MacroExpander expanded_macro = Macro_Invoke(node.m_name.c_str(), node.m_tokens); + // TODO: Requires being able to replace the node with a completely different type of node + //node.replace( Parse_Expr0(expanded_macro) ); + } + void visit(AST::ExprNode_NamedValue& node) { m_res.resolve_path(node.m_path, true); } - void visit(AST::ExprNode_Match& node) { - + void visit(AST::ExprNode_Match& node) + { AST::NodeVisitor::visit(node.m_val); for( auto& arm : node.m_arms ) @@ -110,6 +124,33 @@ void CPathResolver::resolve_path(AST::Path& path, bool allow_variables) const } } // Search relative to current module + // > Search local use definitions (function-level) + // - TODO: Local use statements (scoped) + // > Search module-level definitions + for( const auto& item_mod : m_module.submods() ) + { + if( item_mod.first.name() == path[0].name() ) { + // Check name down? + // Add current module path + path = m_module_path + path; + } + } + for( const auto& item_fcn : m_module.functions() ) + { + if( item_fcn.first.name() == path[0].name() ) { + path = m_module_path + path; + break; + } + } + for( const auto& import : m_module.imports() ) + { + const ::std::string& bind_name = ::std::get<0>(import); + const AST::Path& bind_path = ::std::get<1>(import); + if( bind_name == path[0].name() ) { + path = AST::Path::add_tailing(bind_path, path); + } + } + throw ParseError::Todo("CPathResolver::resolve_path()"); } } @@ -117,15 +158,66 @@ void CPathResolver::resolve_path(AST::Path& path, bool allow_variables) const void CPathResolver::resolve_type(TypeRef& type) const { // TODO: Convert type into absolute + DEBUG("type = " << type); throw ParseError::Todo("CPathResolver::resolve_type()"); } void CPathResolver::handle_pattern(AST::Pattern& pat) { DEBUG("pat = " << pat); + // Resolve names + switch(pat.type()) + { + case AST::Pattern::ANY: + // Wildcard, nothing to do + break; + case AST::Pattern::MAYBE_BIND: { + ::std::string name = pat.binding(); + // Locate a _constant_ within the current namespace which matches this name + // - Variables don't count + AST::Path newpath; + newpath.append( AST::PathNode(name, {}) ); + resolve_path(newpath, false); + if( newpath.is_relative() ) + { + // It's a name binding (desugar to 'name @ _') + pat = AST::Pattern(); + pat.set_bind(name); + } + else + { + // It's a constant (value) + + pat = AST::Pattern( + AST::Pattern::TagValue(), + ::std::unique_ptr( new AST::ExprNode_NamedValue( ::std::move(newpath) ) ) + ); + } + break; } + case AST::Pattern::VALUE: { + CResolvePaths_NodeVisitor nv(*this); + pat.node().visit(nv); + break; } + case AST::Pattern::TUPLE: + // Tuple is handled by subpattern code + break; + case AST::Pattern::TUPLE_STRUCT: + // Resolve the path! + // - TODO: Restrict to types and enum variants + resolve_path( pat.path(), false ); + break; + } + // Extract bindings and add to namespace + if( pat.binding().size() > 0 ) + m_locals.push_back( pat.binding() ); + for( auto& subpat : pat.sub_patterns() ) + handle_pattern(subpat); + + throw ParseError::Todo("CPathResolver::handle_pattern()"); } +/// Perform name resolution in a function void CPathResolver::handle_function(AST::Function& fcn) { CResolvePaths_NodeVisitor node_visitor(*this); diff --git a/src/macros.hpp b/src/macros.hpp index 2618825b..f5779d4d 100644 --- a/src/macros.hpp +++ b/src/macros.hpp @@ -2,6 +2,7 @@ #define MACROS_HPP_INCLUDED #include "parse/lex.hpp" +#include "parse/tokentree.hpp" #include #include #include diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index c56c529d..fd6f14b8 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -483,10 +483,10 @@ ExprNodeP Parse_ExprVal(TokenStream& lex) ExprNodeP rv = Parse_Expr0(lex); GET_CHECK_TOK(tok, lex, TOK_PAREN_CLOSE); return rv; } - case TOK_MACRO: { - // Need to create a token tree, pass to the macro, then pass the result of that to Parse_Expr0 + case TOK_MACRO: + //return NEWNODE( AST::ExprNode_Macro, tok.str(), Parse_TT(lex) ); + { MacroExpander expanded_macro = Macro_Invoke(tok.str().c_str(), Parse_TT(lex)); - return Parse_Expr0(expanded_macro); } default: diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp index 79db4603..f893f26c 100644 --- a/src/parse/lex.cpp +++ b/src/parse/lex.cpp @@ -6,6 +6,7 @@ * \brief Low-level lexer */ #include "lex.hpp" +#include "tokentree.hpp" #include "parseerror.hpp" #include #include diff --git a/src/parse/lex.hpp b/src/parse/lex.hpp index dbf365a0..6a798909 100644 --- a/src/parse/lex.hpp +++ b/src/parse/lex.hpp @@ -197,43 +197,4 @@ private: class EndOfFile {}; }; -class TokenTree -{ - Token m_tok; - ::std::vector m_subtrees; -public: - TokenTree() {} - TokenTree(Token tok): - m_tok(tok) - { - } - TokenTree(::std::vector subtrees): - m_subtrees(subtrees) - { - } - - const unsigned int size() const { - return m_subtrees.size(); - } - const TokenTree& operator[](unsigned int idx) const { - return m_subtrees[idx]; - } - const Token& tok() const { - return m_tok; - } -}; - -class TTStream: - public TokenStream -{ - const TokenTree& m_input_tt; - ::std::vector< ::std::pair > m_stack; -public: - TTStream(const TokenTree& input_tt); - ~TTStream(); - -protected: - virtual Token realGetToken(); -}; - #endif // LEX_HPP_INCLUDED diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 4f2a5084..e922b39f 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -481,11 +481,88 @@ AST::Impl Parse_Impl(TokenStream& lex) return impl; } -AST::Module Parse_ModRoot(const ::std::string& path, Preproc& lex) +void Parse_Use_Wildcard(const AST::Path& base_path, ::std::function fcn) +{ + throw ParseError::Todo("Wildcard imports"); +} + +void Parse_Use(Preproc& lex, ::std::function fcn) { Token tok; + AST::Path path = AST::Path( AST::Path::TagAbsolute() ); + + switch( GET_TOK(tok, lex) ) + { + case TOK_RWORD_SELF: + throw ParseError::Todo("Parse_Use - self"); + break; + case TOK_RWORD_SUPER: + throw ParseError::Todo("Parse_Use - super"); + break; + case TOK_IDENT: + path.append( AST::PathNode(tok.str(), {}) ); + break; + default: + throw ParseError::Unexpected(tok); + } + // TODO: Use from crate root + while( GET_TOK(tok, lex) == TOK_DOUBLE_COLON ) + { + if( GET_TOK(tok, lex) == TOK_IDENT ) + { + path.append( AST::PathNode(tok.str(), {}) ); + } + else + { + switch( tok.type() ) + { + case TOK_BRACE_OPEN: + throw ParseError::Todo("Parse_Use - multiples"); + break; + case TOK_STAR: + throw ParseError::Todo("Parse_Use - wildcard/glob"); + break; + default: + throw ParseError::Unexpected(tok); + } + GET_TOK(tok, lex); + break; + } + } + + ::std::string name; + // TODO: This should only be allowed if the last token was an ident + if( tok.type() == TOK_RWORD_AS ) + { + GET_CHECK_TOK(tok, lex, TOK_IDENT); + name = tok.str(); + } + else + { + lex.putback(tok); + name = path[path.size()-1].name(); + } + + fcn(path, name); +} - AST::Module mod; +void Parse_ModRoot(Preproc& lex, AST::Module& mod, const ::std::string& path) +{ + const bool nested_module = (path.size() == 0); // 'mod name { code }', as opposed to 'mod name;' + Token tok; + + if( mod.crate().m_load_std ) + { + // Import the prelude + AST::Path prelude_path = AST::Path(AST::Path::TagAbsolute()); + prelude_path.append( AST::PathNode("std", {}) ); + prelude_path.append( AST::PathNode("prelude", {}) ); + Parse_Use_Wildcard(prelude_path, + [&mod](AST::Path p, std::string s) { + mod.add_alias(false, p, s); + } + ); + } // Attributes on module/crate (will continue loop) while( GET_TOK(tok, lex) == TOK_CATTR_OPEN ) @@ -493,26 +570,25 @@ AST::Module Parse_ModRoot(const ::std::string& path, Preproc& lex) AST::MetaItem item = Parse_MetaItem(lex); GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); - throw ParseError::Todo("Parent attrs"); - //mod_attrs.push_back( item ); + mod.add_attr( item ); } lex.putback(tok); - // TODO: Handle known parent attribs if operating on crate root - + // TODO: Iterate attributes, and check for handlers on each + for(;;) { // Check 1 - End of module (either via a closing brace, or EOF) switch(GET_TOK(tok, lex)) { case TOK_BRACE_CLOSE: - if( path.size() > 0 ) + if( !nested_module ) throw ParseError::Unexpected(tok); - return mod; + return ; case TOK_EOF: - if( path.size() == 0 ) + if( nested_module ) throw ParseError::Unexpected(tok); - return mod; + return ; default: lex.putback(tok); break; @@ -542,8 +618,7 @@ AST::Module Parse_ModRoot(const ::std::string& path, Preproc& lex) switch( GET_TOK(tok, lex) ) { case TOK_RWORD_USE: - // TODO: Do manual path parsing here, as use has its own special set of quirks - mod.add_alias( is_public, Parse_Path(lex, true, PATH_GENERIC_NONE) ); + Parse_Use(lex, [&mod,is_public](AST::Path p, std::string s) { mod.add_alias(is_public, p, s); }); GET_CHECK_TOK(tok, lex, TOK_SEMICOLON); break; @@ -604,6 +679,44 @@ AST::Module Parse_ModRoot(const ::std::string& path, Preproc& lex) AST::Crate Parse_Crate(::std::string mainfile) { - Preproc lex(mainfile); - return AST::Crate( Parse_ModRoot(mainfile, lex) ); + Token tok; + + Preproc lex(mainfile); + AST::Crate crate; + AST::Module& rootmod = crate.root_module(); + + // Attributes on module/crate + while( GET_TOK(tok, lex) == TOK_CATTR_OPEN ) + { + AST::MetaItem item = Parse_MetaItem(lex); + GET_CHECK_TOK(tok, lex, TOK_SQUARE_CLOSE); + + rootmod.add_attr( item ); + } + lex.putback(tok); + + // Check for crate attributes + for( const auto& attr : rootmod.attrs() ) + { + if( attr.name() == "no_std" ) { + crate.m_load_std = false; + } + else { + // TODO: + } + } + + if( crate.m_load_std ) + { + // Load the standard library (add 'extern crate std;') + rootmod.add_ext_crate("std", "std"); + // Prelude imports are handled in Parse_ModRoot + } + + // Include the std if the 'no_std' attribute was absent + // - First need to load the std macros, then can import the prelude + + Parse_ModRoot(lex, rootmod, mainfile); + + return crate; } diff --git a/src/parse/tokentree.hpp b/src/parse/tokentree.hpp index 4105897d..b1b353ea 100644 --- a/src/parse/tokentree.hpp +++ b/src/parse/tokentree.hpp @@ -4,6 +4,45 @@ #include "lex.hpp" +class TokenTree +{ + Token m_tok; + ::std::vector m_subtrees; +public: + TokenTree() {} + TokenTree(Token tok): + m_tok(tok) + { + } + TokenTree(::std::vector subtrees): + m_subtrees(subtrees) + { + } + + const unsigned int size() const { + return m_subtrees.size(); + } + const TokenTree& operator[](unsigned int idx) const { + return m_subtrees[idx]; + } + const Token& tok() const { + return m_tok; + } +}; + +class TTStream: + public TokenStream +{ + const TokenTree& m_input_tt; + ::std::vector< ::std::pair > m_stack; +public: + TTStream(const TokenTree& input_tt); + ~TTStream(); + +protected: + virtual Token realGetToken(); +}; + extern TokenTree Parse_TT(TokenStream& lex); extern TokenTree Parse_TT_Expr(TokenStream& lex); extern TokenTree Parse_TT_Stmt(TokenStream& lex); -- cgit v1.2.3