summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast/pattern.hpp10
-rw-r--r--src/include/tagged_enum.hpp102
-rw-r--r--src/parse/expr.cpp46
3 files changed, 157 insertions, 1 deletions
diff --git a/src/ast/pattern.hpp b/src/ast/pattern.hpp
index a2f9a24b..a9a944fb 100644
--- a/src/ast/pattern.hpp
+++ b/src/ast/pattern.hpp
@@ -33,6 +33,16 @@ private:
unique_ptr<ExprNode> m_node;
unique_ptr<ExprNode> m_node2; // ONLY used for range values
::std::vector<Pattern> m_sub_patterns;
+
+ TAGGED_ENUM(Data, Any,
+ (Any, () ),
+ (Ref, (bool mut; unique_ptr<ExprNode> sub;) ),
+ (Value, (unique_ptr<ExprNode> start; unique_ptr<ExprNode> end;) ),
+ (Tuple, (::std::vector<Pattern> sub_patterns;) ),
+ (StructTuple, (Path path; ::std::vector<Pattern> sub_patterns;) ),
+ (Struct, (Path path; ::std::vector< ::std::pair< ::std::string,Pattern> > sub_patterns;) )
+ );
+
public:
Pattern(Pattern&& o) noexcept:
m_class(o.m_class),
diff --git a/src/include/tagged_enum.hpp b/src/include/tagged_enum.hpp
new file mode 100644
index 00000000..07bd5881
--- /dev/null
+++ b/src/include/tagged_enum.hpp
@@ -0,0 +1,102 @@
+
+#define TE_DATANAME(name) Data_##name
+#define ENUM_CONS(__tag, __type) \
+ static self_t make_##__tag(__type v) \
+ {\
+ self_t ret;\
+ ret.m_tag = __tag;\
+ new (ret.m_data) __type( ::std::move(v) ); \
+ return ::std::move(ret); \
+ }\
+ bool is_##__tag() const { return m_tag == __tag; } \
+ const __type& as_##__tag() const { return reinterpret_cast<const __type&>(m_data); } \
+ __type& as_##__tag() { return reinterpret_cast<__type&>(m_data); } \
+ __type unwrap_##__tag() { return ::std::move(reinterpret_cast<__type&>(m_data)); } \
+
+#define TE_CONS(name, _) ENUM_CONS(name, TE_DATANAME(name))
+#define TE_CONS2(a, b) TE_CONS a TE_CONS b
+#define TE_CONS3(a, ...) TE_CONS a TE_CONS2(__VA_ARGS__)
+#define TE_CONS4(a, ...) TE_CONS a TE_CONS3(__VA_ARGS__)
+#define TE_CONS5(a, ...) TE_CONS a TE_CONS4(__VA_ARGS__)
+#define TE_CONS6(a, ...) TE_CONS a TE_CONS5(__VA_ARGS__)
+
+// Sizes of structures
+#define TE_SO(name, _) sizeof(TE_DATANAME(name))
+#define MAX2(a, b) (a < b ? b : a)
+#define MAXS2(a, b) (TE_SO a < TE_SO b ? TE_SO b : TE_SO a)
+#define MAXS3(a, b, c) MAX2(MAXS2(a, b), TE_SO c)
+#define MAXS4(a, b, c, d) MAX2(MAXS2(a, b), MAXS2(c, d))
+#define MAXS5(a, b, c, d, e) MAX2(MAXS3(a, b, c), MAXS2(d, e))
+#define MAXS6(a, b, c, d, e, f) MAX2(MAXS3(a, b, c), MAXS3(d, e, f))
+
+// Type definitions
+#define TE_EXP(...) __VA_ARGS__
+#define TE_TYPEDEF(name, content) struct TE_DATANAME(name) { TE_EXP content };
+#define TE_TYPEDEF2(_1, _2) TE_TYPEDEF _1 TE_TYPEDEF _2
+#define TE_TYPEDEF3(_1, ...) TE_TYPEDEF _1 TE_TYPEDEF2(__VA_ARGS__)
+#define TE_TYPEDEF4(_1, ...) TE_TYPEDEF _1 TE_TYPEDEF3(__VA_ARGS__)
+#define TE_TYPEDEF5(_1, ...) TE_TYPEDEF _1 TE_TYPEDEF4(__VA_ARGS__)
+#define TE_TYPEDEF6(_1, ...) TE_TYPEDEF _1 TE_TYPEDEF5(__VA_ARGS__)
+
+#define TE_TAG(name, _) name,
+#define TE_TAG2(_1,_2) TE_TAG _1 TE_TAG _2
+#define TE_TAG3(_1,...) TE_TAG _1 TE_TAG2(__VA_ARGS__)
+#define TE_TAG4(_1,...) TE_TAG _1 TE_TAG3(__VA_ARGS__)
+#define TE_TAG5(_1,...) TE_TAG _1 TE_TAG4(__VA_ARGS__)
+#define TE_TAG6(_1,...) TE_TAG _1 TE_TAG5(__VA_ARGS__)
+
+#define TE_DEST_CASE(tag, _) case tag: as_##tag().~TE_DATANAME(tag)(); break;
+#define TE_DEST_CASE2(_1,_2) TE_DEST_CASE _1 TE_DEST_CASE _2
+#define TE_DEST_CASE3(_1, ...) TE_DEST_CASE _1 TE_DEST_CASE2(__VA_ARGS__)
+#define TE_DEST_CASE4(_1, ...) TE_DEST_CASE _1 TE_DEST_CASE3(__VA_ARGS__)
+#define TE_DEST_CASE5(_1, ...) TE_DEST_CASE _1 TE_DEST_CASE4(__VA_ARGS__)
+#define TE_DEST_CASE6(_1, ...) TE_DEST_CASE _1 TE_DEST_CASE5(__VA_ARGS__)
+
+#define TE_MOVE_CASE(tag, _) case tag: new(m_data) TE_DATANAME(tag)(x.unwrap_##tag()); break;
+#define TE_MOVE_CASE2(_1,_2) TE_MOVE_CASE _1 TE_MOVE_CASE _2
+#define TE_MOVE_CASE3(_1, ...) TE_MOVE_CASE _1 TE_MOVE_CASE2(__VA_ARGS__)
+#define TE_MOVE_CASE4(_1, ...) TE_MOVE_CASE _1 TE_MOVE_CASE3(__VA_ARGS__)
+#define TE_MOVE_CASE5(_1, ...) TE_MOVE_CASE _1 TE_MOVE_CASE4(__VA_ARGS__)
+#define TE_MOVE_CASE6(_1, ...) TE_MOVE_CASE _1 TE_MOVE_CASE5(__VA_ARGS__)
+
+// Macro to obtain a numbered macro for argument counts
+#define TE_GM(SUF,_1,_2,_3,_4,_5,_6,COUNT,...) SUF##COUNT
+
+#define MAXS(...) TE_GM(MAXS ,__VA_ARGS__,6,5,4,3,2)(__VA_ARGS__)
+#define TE_TYPEDEFS(...) TE_GM(TE_TYPEDEF ,__VA_ARGS__,6,5,4,3,2)(__VA_ARGS__)
+#define TE_TAGS(...) TE_GM(TE_TAG ,__VA_ARGS__,6,5,4,3,2)(__VA_ARGS__)
+#define TE_DEST_CASES(...) TE_GM(TE_DEST_CASE,__VA_ARGS__,6,5,4,3,2)(__VA_ARGS__)
+#define TE_MOVE_CASES(...) TE_GM(TE_MOVE_CASE,__VA_ARGS__,6,5,4,3,2)(__VA_ARGS__)
+#define TE_CONSS(...) TE_GM(TE_CONS ,__VA_ARGS__,6,5,4,3,2)(__VA_ARGS__)
+
+#define TAGGED_ENUM(_name, _def, ...) \
+class _name { \
+ typedef _name self_t; \
+ TE_TYPEDEFS(__VA_ARGS__) \
+ enum Tag { \
+ TE_TAGS(__VA_ARGS__)\
+ } m_tag; \
+ char m_data[MAXS(__VA_ARGS__)]; \
+public:\
+ _name(): m_tag(_def) {}\
+ _name(_name&& x): m_tag(x.m_tag) { x.m_tag = _def; switch(m_tag) { TE_MOVE_CASES(__VA_ARGS__) } } \
+ ~_name() { switch(m_tag) { TE_DEST_CASES(__VA_ARGS__) } } \
+ TE_CONSS(__VA_ARGS__) \
+}
+
+#define ENUM3(_name, _def, _t1, _v1, _t2, _v2, _t3, _v3)\
+ TAGGED_ENUM(_name, _def,\
+ (_t1, _v1), \
+ (_t2, _v2), \
+ (_t3, _v3) \
+ )
+
+/*
+ ENUM5(Inner, Any,
+ Any, bool,
+ Tuple, ::std::vector<Pattern>,
+ TupleStruct, struct { Path path; ::std::vector<Pattern> sub_patterns; },
+ Value, ::std::unique_ptr<ExprNode>,
+ Range, struct { ::std::unique_ptr<ExprNode> left; ::std::unique_ptr<ExprNode> right; }
+ ) m_contents;
+*/
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp
index c588d3e8..e217974a 100644
--- a/src/parse/expr.cpp
+++ b/src/parse/expr.cpp
@@ -34,6 +34,7 @@ AST::Expr Parse_ExprBlock(TokenStream& lex)
AST::Pattern Parse_PatternReal_Path(TokenStream& lex, AST::Path path);
AST::Pattern Parse_PatternReal(TokenStream& lex);
+AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path);
/// Parse a pattern
@@ -203,7 +204,7 @@ AST::Pattern Parse_PatternReal_Path(TokenStream& lex, AST::Path path)
case TOK_PAREN_OPEN:
return AST::Pattern(AST::Pattern::TagEnumVariant(), ::std::move(path), Parse_PatternList(lex));
case TOK_BRACE_OPEN:
- throw ParseError::Todo(lex, "struct patterns");
+ return Parse_PatternStruct(lex, ::std::move(path));
default:
lex.putback(tok);
return AST::Pattern(AST::Pattern::TagValue(), NEWNODE(AST::ExprNode_NamedValue, ::std::move(path)));
@@ -231,6 +232,49 @@ AST::Pattern Parse_PatternReal_Path(TokenStream& lex, AST::Path path)
return child_pats;
}
+AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path)
+{
+ TRACE_FUNCTION;
+ Token tok;
+ do {
+ GET_TOK(tok, lex);
+ DEBUG("tok = " << tok);
+ if( tok.type() == TOK_BRACE_CLOSE )
+ break;
+ if( tok.type() == TOK_DOUBLE_DOT ) {
+ GET_TOK(tok, lex);
+ break;
+ }
+
+ bool is_short_bind = false;
+ if( tok.type() == TOK_RWORD_REF ) {
+ is_short_bind = true;
+ GET_TOK(tok, lex);
+ }
+ if( tok.type() == TOK_RWORD_MUT ) {
+ is_short_bind = true;
+ GET_TOK(tok, lex);
+ }
+
+ CHECK_TOK(tok, TOK_IDENT);
+ ::std::string field = tok.str();
+ GET_TOK(tok, lex);
+
+ AST::Pattern pat;
+ if( is_short_bind || tok.type() != TOK_COLON ) {
+ lex.putback(tok);
+ pat = AST::Pattern(AST::Pattern::TagBind(), field);
+ }
+ else {
+ CHECK_TOK(tok, TOK_COLON);
+ pat = Parse_Pattern(lex);
+ }
+ // TODO: Append
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+ throw ParseError::Todo(lex, "struct patterns");
+}
+
ExprNodeP Parse_ExprBlockNode(TokenStream& lex);
ExprNodeP Parse_ExprBlockLine(TokenStream& lex, bool *expect_end);
void Parse_ExternBlock(TokenStream& lex, AST::MetaItems attrs, ::std::vector< AST::Item<AST::Function> >& imports);