summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile3
-rw-r--r--src/ast/ast.hpp5
-rw-r--r--src/ast/expr.hpp5
-rw-r--r--src/ast/path.hpp5
-rw-r--r--src/convert/decorators.cpp69
-rw-r--r--src/include/main_bindings.hpp11
-rw-r--r--src/include/synext.hpp33
-rw-r--r--src/main.cpp1
-rw-r--r--src/parse/expr.cpp4
-rw-r--r--src/parse/lex.hpp2
-rw-r--r--src/synexts/derive.cpp151
11 files changed, 283 insertions, 6 deletions
diff --git a/Makefile b/Makefile
index 9bea4a43..cfd5562e 100644
--- a/Makefile
+++ b/Makefile
@@ -21,8 +21,11 @@ OBJ += parse/parseerror.o parse/lex.o
OBJ += parse/root.o parse/paths.o parse/types.o parse/expr.o parse/pattern.o
OBJ += dump_as_rust.o
OBJ += convert/ast_iterate.o
+OBJ += convert/decorators.o
OBJ += convert/resolve.o convert/typecheck_bounds.o convert/typecheck_params.o convert/typecheck_expr.o
OBJ += convert/flatten.o convert/render.o
+OBJ += synexts/derive.o
+
OBJ := $(addprefix $(OBJDIR),$(OBJ))
diff --git a/src/ast/ast.hpp b/src/ast/ast.hpp
index 5cf1dee2..1cfae202 100644
--- a/src/ast/ast.hpp
+++ b/src/ast/ast.hpp
@@ -170,6 +170,7 @@ public:
const ::std::string& name() const { return m_name; }
const ::std::string& string() const { return m_str_val; }
bool has_sub_items() const { return m_sub_items.m_items.size() > 0; }
+ const MetaItems& items() const { return m_sub_items; }
MetaItems& items() { return m_sub_items; }
friend ::std::ostream& operator<<(::std::ostream& os, const MetaItem& x) {
@@ -454,9 +455,11 @@ public:
m_fields( move(fields) )
{}
- const TypeParams& params() const { return m_params; }
+ const MetaItems& attrs() const { return m_attrs; }
+ const TypeParams& params() const { return m_params; }
const ::std::vector<StructItem>& fields() const { return m_fields; }
+ MetaItems& attrs() { return m_attrs; }
TypeParams& params() { return m_params; }
::std::vector<StructItem>& fields() { return m_fields; }
diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp
index 663beae0..45f6e3c9 100644
--- a/src/ast/expr.hpp
+++ b/src/ast/expr.hpp
@@ -208,7 +208,7 @@ struct ExprNode_CallMethod:
::std::vector<unique_ptr<ExprNode>> m_args;
ExprNode_CallMethod() {}
- ExprNode_CallMethod(unique_ptr<ExprNode>&& obj, PathNode&& method, ::std::vector<unique_ptr<ExprNode>>&& args):
+ ExprNode_CallMethod(unique_ptr<ExprNode> obj, PathNode method, ::std::vector<unique_ptr<ExprNode>> args):
m_val( move(obj) ),
m_method( move(method) ),
m_args( move(args) )
@@ -479,7 +479,7 @@ struct ExprNode_Field:
::std::string m_name;
ExprNode_Field() {}
- ExprNode_Field(::std::unique_ptr<ExprNode>&& obj, ::std::string&& name):
+ ExprNode_Field(::std::unique_ptr<ExprNode>&& obj, ::std::string name):
m_obj( ::std::move(obj) ),
m_name( ::std::move(name) )
{
@@ -723,6 +723,7 @@ public:
SERIALISABLE_PROTOTYPES();
};
+typedef ::std::unique_ptr<AST::ExprNode> ExprNodeP;
}
#endif
diff --git a/src/ast/path.hpp b/src/ast/path.hpp
index a2ca316b..390271fe 100644
--- a/src/ast/path.hpp
+++ b/src/ast/path.hpp
@@ -180,7 +180,10 @@ public:
struct TagLocal {};
Path(TagLocal, ::std::string name):
m_class(LOCAL),
- m_nodes({PathNode(name, {})})
+ m_nodes({PathNode( ::std::move(name), {} )})
+ {}
+ Path(::std::string name):
+ Path(TagLocal(), ::std::move(name))
{}
struct TagSuper {};
Path(TagSuper):
diff --git a/src/convert/decorators.cpp b/src/convert/decorators.cpp
new file mode 100644
index 00000000..0ccb16d4
--- /dev/null
+++ b/src/convert/decorators.cpp
@@ -0,0 +1,69 @@
+/*
+ */
+#include "ast_iterate.hpp"
+#include "../ast/ast.hpp"
+#include <main_bindings.hpp>
+#include <unordered_map> // C++11, hashmap
+#include <synext.hpp>
+
+::std::unordered_map< ::std::string, ::std::unique_ptr<CDecoratorHandler> > g_decorators;
+
+template<typename T>
+bool Decorator_Apply(AST::Module& mod, const AST::MetaItem& attr, const AST::Path& path, T& ent)
+{
+ auto it = g_decorators.find(attr.name());
+ if( it == g_decorators.end() )
+ {
+ return false;
+ }
+
+ const CDecoratorHandler& handler = *it->second;
+
+ handler.handle_item(mod, attr, path, ent);
+ return true;
+}
+
+class CProcessor:
+ public CASTIterator
+{
+ AST::Crate& m_crate;
+ ::std::vector<AST::Module*> m_modstack;
+public:
+ CProcessor(AST::Crate& crate):
+ m_crate(crate)
+ {}
+
+ void handle_module(AST::Path path, AST::Module& mod) override
+ {
+ m_modstack.push_back(&mod);
+ CASTIterator::handle_module(mv$(path), mod);
+ m_modstack.pop_back();
+ }
+
+ void handle_struct(AST::Path path, AST::Struct& str) override
+ {
+ // For all attributes on the struct, search for a handler and call handler
+ auto& attrs = str.attrs();
+ for( auto& attr : attrs.m_items )
+ {
+ Decorator_Apply(*m_modstack.back(), attr, path, str);
+ }
+ }
+};
+
+void Register_Synext_Decorator(::std::string name, ::std::unique_ptr<CDecoratorHandler> handler)
+{
+ auto res = g_decorators.insert( ::std::make_pair(name, mv$(handler)) );
+ if( res.second == false )
+ {
+ DEBUG("Duplicate definition of decorator '"<<name<<"'");
+ }
+}
+
+void Process_Decorators(AST::Crate& crate)
+{
+ CProcessor processor(crate);
+
+ processor.handle_module(AST::Path({}), crate.root_module());
+}
+
diff --git a/src/include/main_bindings.hpp b/src/include/main_bindings.hpp
index fef57184..91bac742 100644
--- a/src/include/main_bindings.hpp
+++ b/src/include/main_bindings.hpp
@@ -5,13 +5,24 @@
#include "../ast/ast.hpp"
+/// Parse a crate from the given file
extern AST::Crate Parse_Crate(::std::string mainfile);
+/// Process #[] decorators
+extern void Process_Decorators(AST::Crate& crate);
+/// Resolve all in-text paths to absolute variants
extern void ResolvePaths(AST::Crate& crate);
+/// Check that generic bounds are valid
extern void Typecheck_GenericBounds(AST::Crate& crate);
+/// Check that parameters for generics are valid
extern void Typecheck_GenericParams(AST::Crate& crate);
+/// Type resolution (and hence checking) for expressions
extern void Typecheck_Expr(AST::Crate& crate);
+
+/// Convert the AST to a flat tree
extern AST::Flat Convert_Flatten(const AST::Crate& crate);
+
+/// Dump the crate as annotated rust
extern void Dump_Rust(const char *Filename, const AST::Crate& crate);
#endif
diff --git a/src/include/synext.hpp b/src/include/synext.hpp
new file mode 100644
index 00000000..6688c1c7
--- /dev/null
+++ b/src/include/synext.hpp
@@ -0,0 +1,33 @@
+/*
+ */
+#ifndef _SYNEXT_HPP_
+#define _SYNEXT_HPP_
+
+#include "../common.hpp" // for mv$ and other things
+#include <string>
+#include <memory>
+
+namespace AST {
+ class MetaItem;
+ class Path;
+ class Module;
+ class Struct;
+}
+
+class CDecoratorHandler
+{
+public:
+ virtual void handle_item(AST::Module& mod, const AST::MetaItem& attr, const AST::Path& path, AST::Struct& str) const = 0;
+};
+
+#define STATIC_SYNEXT(_type, ident, _typename) \
+ struct register_##_typename##_c {\
+ register_##_typename##_c() {\
+ Register_Synext_##_type( ident, ::std::unique_ptr<C##_type##Handler>(new _typename()) ); \
+ } \
+ } s_register_##_typename;
+
+extern void Register_Synext_Decorator(::std::string name, ::std::unique_ptr<CDecoratorHandler> handler);
+
+#endif
+
diff --git a/src/main.cpp b/src/main.cpp
index d996167b..339fdb1e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -57,6 +57,7 @@ int main(int argc, char *argv[])
// Iterate all items in the AST, applying syntax extensions
g_cur_phase = "Syn Exts";
+ Process_Decorators(crate);
// TODO:
g_cur_phase = "PostParse";
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index 536860c6..e83d2dbe 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -17,10 +17,10 @@
#include <iostream>
#include "tokentree.hpp"
-typedef ::std::unique_ptr<AST::ExprNode> ExprNodeP;
+using AST::ExprNode;
+using AST::ExprNodeP;
static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){en->set_pos(lex.getPosition()); return ExprNodeP(en); }
#define NEWNODE(type, ...) mk_exprnodep(lex, new type(__VA_ARGS__))
-using AST::ExprNode;
ExprNodeP Parse_ExprBlockNode(TokenStream& lex);
ExprNodeP Parse_Stmt(TokenStream& lex);
diff --git a/src/parse/lex.hpp b/src/parse/lex.hpp
index 0dab9a24..522d2d31 100644
--- a/src/parse/lex.hpp
+++ b/src/parse/lex.hpp
@@ -105,7 +105,9 @@ extern ::std::ostream& operator<<(::std::ostream& os, const Token& tok);
/// State the parser needs to pass down via a second channel.
struct ParseState
{
+ // Used for "for/if/while" to handle ambiguity
bool disallow_struct_literal = false;
+ // A debugging hook that disables expansion of macros
bool no_expand_macros = false;
friend ::std::ostream& operator<<(::std::ostream& os, const ParseState& ps) {
diff --git a/src/synexts/derive.cpp b/src/synexts/derive.cpp
new file mode 100644
index 00000000..ccb4fb00
--- /dev/null
+++ b/src/synexts/derive.cpp
@@ -0,0 +1,151 @@
+
+#include <synext.hpp>
+#include "../common.hpp"
+#include "../ast/ast.hpp"
+#include "../ast/expr.hpp"
+
+template<typename T>
+static inline ::std::vector<T> vec$(T v1) {
+ ::std::vector<T> tmp;
+ tmp.push_back( mv$(v1) );
+ return mv$(tmp);
+}
+template<typename T>
+static inline ::std::vector<T> vec$(T v1, T v2) {
+ ::std::vector<T> tmp;
+ tmp.push_back( mv$(v1) );
+ tmp.push_back( mv$(v2) );
+ return mv$(tmp);
+}
+
+static inline AST::ExprNodeP mk_exprnodep(AST::ExprNode* en){ return AST::ExprNodeP(en); }
+#define NEWNODE(type, ...) mk_exprnodep(new type(__VA_ARGS__))
+
+/// Interface for derive handlers
+struct Deriver
+{
+ virtual AST::Impl handle_item(const AST::TypeParams& params, const TypeRef& type, const AST::Struct& str) const = 0;
+};
+
+/// 'Debug' derive handler
+class Deriver_Debug:
+ public Deriver
+{
+ //static AST::ExprNodeP _print_l(::std::string val)
+ //{
+ // return NEWNODE(AST::ExprNode_CallMethod,
+ // NEWNODE(AST::ExprNode_NamedValue, AST::Path("f")),
+ // AST::PathNode("write_str",{}),
+ // { NEWNODE(AST::ExprNode_String, mv$(val)) }
+ // );
+ //}
+ //static AST::ExprNodeP _try(AST::ExprNodeP expr)
+ //{
+ // throw CompileError::Todo("derive(Debug) - _try");
+ //}
+
+public:
+ AST::Impl handle_item(const AST::TypeParams& p, const TypeRef& type, const AST::Struct& str) const override
+ {
+ const AST::Path debug_trait("", { AST::PathNode("fmt", {}), AST::PathNode("Debug", {}) });
+ const TypeRef ret_type(AST::Path("", {AST::PathNode("fmt",{}), AST::PathNode("Result",{})}) );
+ const TypeRef f_type(TypeRef::TagReference(), true,
+ TypeRef(AST::Path("", {AST::PathNode("fmt",{}), AST::PathNode("Formatter", {})}))
+ );
+ const ::std::string& name = type.path().nodes().back().name();
+
+ // Generate code for Debug
+ AST::ExprNodeP node;
+ node = NEWNODE(AST::ExprNode_NamedValue, AST::Path("f"));
+ node = NEWNODE(AST::ExprNode_CallMethod,
+ mv$(node), AST::PathNode("debug_struct",{}),
+ vec$( NEWNODE(AST::ExprNode_String, name) )
+ );
+ for( const auto& fld : str.fields() )
+ {
+ node = NEWNODE(AST::ExprNode_CallMethod,
+ mv$(node), AST::PathNode("field",{}),
+ vec$(
+ NEWNODE(AST::ExprNode_String, fld.name),
+ NEWNODE(AST::ExprNode_UniOp, AST::ExprNode_UniOp::REF,
+ NEWNODE(AST::ExprNode_Field,
+ NEWNODE(AST::ExprNode_NamedValue, AST::Path("self")),
+ fld.name
+ )
+ )
+ )
+ );
+ }
+ node = NEWNODE(AST::ExprNode_CallMethod, mv$(node), AST::PathNode("finish",{}), {});
+
+ DEBUG("node = " << *node);
+
+ AST::Function fcn(
+ AST::MetaItems(), AST::TypeParams(), AST::Function::CLASS_REFMETHOD,
+ ret_type,
+ vec$( ::std::make_pair( AST::Pattern(AST::Pattern::TagBind(), "f"), f_type ) )
+ );
+ fcn.set_code( NEWNODE(AST::ExprNode_Block, vec$(mv$(node)), ::std::unique_ptr<AST::Module>()) );
+
+ AST::Impl rv( AST::MetaItems(), p, type, debug_trait );
+ rv.add_function(false, "fmt", mv$(fcn));
+ return mv$(rv);
+ }
+} g_derive_debug;
+
+
+// --------------------------------------------------------------------
+// Select and dispatch the correct derive() handler
+// --------------------------------------------------------------------
+static const Deriver* find_impl(const ::std::string& trait_name)
+{
+ if( trait_name == "Debug" )
+ return &g_derive_debug;
+ else
+ return nullptr;
+}
+
+template<typename T>
+static void derive_item(AST::Module& mod, const AST::MetaItem& attr, const AST::Path& path, const T& item)
+{
+ if( !attr.has_sub_items() )
+ throw CompileError::Generic("#[derive()] requires a list of known traits to derive");
+
+ DEBUG("path = " << path);
+ bool fail = false;
+
+ const auto& params = item.params();
+ TypeRef type(path);
+ for( const auto& param : params.ty_params() )
+ type.path().nodes().back().args().push_back( TypeRef(TypeRef::TagArg(), param.name()) );
+
+ for( const auto& trait : attr.items().m_items )
+ {
+ DEBUG("- " << trait.name());
+ auto dp = find_impl(trait.name());
+ if( !dp ) {
+ DEBUG("> No handler for " << trait.name());
+ fail = true;
+ continue ;
+ }
+
+ mod.add_impl( dp->handle_item(params, type, item) );
+ }
+
+ if( fail ) {
+ //throw CompileError::Generic("Failed to #[dervie]");
+ }
+}
+
+class Decorator_Derive:
+ public CDecoratorHandler
+{
+public:
+ void handle_item(AST::Module& mod, const AST::MetaItem& attr, const AST::Path& path, AST::Struct& str) const override
+ {
+ derive_item(mod, attr, path, str);
+ }
+};
+
+STATIC_SYNEXT(Decorator, "derive", Decorator_Derive)
+