diff options
Diffstat (limited to 'src/parse/expr.cpp')
-rw-r--r-- | src/parse/expr.cpp | 631 |
1 files changed, 631 insertions, 0 deletions
diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp new file mode 100644 index 00000000..e632d47f --- /dev/null +++ b/src/parse/expr.cpp @@ -0,0 +1,631 @@ +/*
+ */
+#include "preproc.hpp"
+#include "parseerror.hpp"
+#include "../ast/ast.hpp"
+#include "common.hpp"
+#include "../macros.hpp"
+#include <iostream>
+#include "tokentree.hpp"
+
+using AST::ExprNode;
+
+AST::ExprNode Parse_ExprBlockNode(TokenStream& lex);
+AST::ExprNode Parse_Stmt(TokenStream& lex, bool& opt_semicolon);
+AST::ExprNode Parse_Expr0(TokenStream& lex);
+AST::ExprNode Parse_ExprBlocks(TokenStream& lex);
+AST::ExprNode Parse_Expr1(TokenStream& lex);
+
+AST::Expr Parse_Expr(TokenStream& lex, bool const_only)
+{
+ return AST::Expr(Parse_Expr0(lex));
+}
+
+AST::Expr Parse_ExprBlock(TokenStream& lex)
+{
+ return AST::Expr(Parse_ExprBlockNode(lex));
+}
+
+AST::Pattern Parse_Pattern(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+
+ AST::Path path;
+ Token tok;
+ tok = lex.getToken();
+ if( tok.type() == TOK_RWORD_REF )
+ {
+ throw ParseError::Todo("ref bindings");
+ tok = lex.getToken();
+ }
+ switch( tok.type() )
+ {
+ case TOK_IDENT:
+ // 1. Identifiers could be either a bind or a value
+ // - If the path resolves to a single node, either a local enum value, or a binding
+ lex.putback(tok);
+ path = Parse_Path(lex, false, PATH_GENERIC_EXPR);
+ if( path.length() == 1 && path[0].args().size() == 0 )
+ {
+ // Could be a name binding, check the next token
+ GET_TOK(tok, lex);
+ if(tok.type() != TOK_PAREN_OPEN) {
+ lex.putback(tok);
+ return AST::Pattern(AST::Pattern::TagMaybeBind(), path[0].name());
+ }
+ lex.putback(tok);
+ }
+ // otherwise, it's a value check
+ if(0)
+ case TOK_DOUBLE_COLON:
+ // 2. Paths are enum/struct names
+ {
+ path = Parse_Path(lex, true, PATH_GENERIC_EXPR);
+ }
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_PAREN_OPEN: {
+ // A list of internal patterns
+ ::std::vector<AST::Pattern> child_pats;
+ do {
+ AST::Pattern pat = Parse_Pattern(lex);
+ child_pats.push_back(pat);
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ CHECK_TOK(tok, TOK_PAREN_CLOSE);
+ return AST::Pattern(AST::Pattern::TagEnumVariant(), path, child_pats);
+ }
+ default:
+ lex.putback(tok);
+ return AST::Pattern(AST::Pattern::TagValue(), ExprNode(ExprNode::TagNamedValue(), path));
+ }
+ break;
+ case TOK_INTEGER:
+ return AST::Pattern( AST::Pattern::TagValue(), ExprNode(ExprNode::TagInteger(), tok.intval(), tok.datatype()) );
+ case TOK_PAREN_OPEN:
+ throw ParseError::Todo("tuple patterns");
+ default:
+ throw ParseError::Unexpected(tok);
+ }
+ throw ParseError::BugCheck("Parse_TT_Stmt should early return");
+}
+
+ExprNode Parse_ExprBlockNode(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+
+ ::std::vector<ExprNode> nodes;
+ Token tok;
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
+ while( GET_TOK(tok, lex) != TOK_BRACE_CLOSE )
+ {
+ lex.putback(tok);
+ bool opt_semicolon = false;
+ // NOTE: This semicolon handling is SHIT.
+ nodes.push_back(Parse_Stmt(lex, opt_semicolon));
+ if( GET_TOK(tok, lex) != TOK_BRACE_CLOSE ) {
+ if( !opt_semicolon )
+ CHECK_TOK(tok, TOK_SEMICOLON);
+ else
+ lex.putback(tok);
+ }
+ else {
+ nodes.push_back(ExprNode());
+ break;
+ }
+ }
+ return AST::ExprNode(ExprNode::TagBlock(), nodes);
+}
+
+AST::ExprNode Parse_Stmt(TokenStream& lex, bool& opt_semicolon)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+ // 1. Handle 'let'
+ // 2. Handle new blocks
+ // 3. Handle a sequence of expressions broken by ';'
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_BRACE_OPEN:
+ lex.putback(tok);
+ opt_semicolon = true;
+ return Parse_ExprBlockNode(lex);
+ case TOK_RWORD_LET: {
+ //ret.append();
+ AST::Pattern pat = Parse_Pattern(lex);
+ GET_CHECK_TOK(tok, lex, TOK_EQUAL);
+ AST::ExprNode val = Parse_Expr1(lex);
+ opt_semicolon = false;
+ return ExprNode(ExprNode::TagLetBinding(), pat, val);
+ }
+ case TOK_RWORD_RETURN:
+ return ExprNode(ExprNode::TagReturn(), Parse_Expr1(lex));
+ case TOK_RWORD_LOOP:
+ throw ParseError::Todo("loop");
+ break;
+ case TOK_RWORD_FOR:
+ throw ParseError::Todo("for");
+ break;
+ case TOK_RWORD_WHILE:
+ throw ParseError::Todo("while");
+ break;
+ default: {
+ lex.putback(tok);
+ opt_semicolon = true;
+ return Parse_Expr0(lex);
+ }
+ }
+
+}
+
+::std::vector<AST::ExprNode> Parse_ParenList(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+
+ ::std::vector<ExprNode> rv;
+ Token tok;
+ GET_CHECK_TOK(tok, lex, TOK_PAREN_OPEN);
+ if( (tok = lex.getToken()).type() != TOK_PAREN_CLOSE )
+ {
+ lex.putback(tok);
+ do {
+ rv.push_back( Parse_Expr1(lex) );
+ } while( (tok = lex.getToken()).type() == TOK_COMMA );
+ CHECK_TOK(tok, TOK_PAREN_CLOSE);
+ }
+ return rv;
+}
+
+// 0: Assign
+AST::ExprNode Parse_Expr0(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+
+ AST::ExprNode rv = Parse_ExprBlocks(lex);
+ Token tok = lex.getToken();
+ if( tok.type() == TOK_EQUAL )
+ {
+ ExprNode val = Parse_Expr1(lex);
+ rv = ExprNode(ExprNode::TagAssign(), rv, val);
+ }
+ else
+ {
+ lex.putback(tok);
+ }
+ return rv;
+}
+
+/// Parse an 'if' statement
+// Note: TOK_RWORD_IF has already been eaten
+AST::ExprNode Parse_IfStmt(TokenStream& lex)
+{
+ TRACE_FUNCTION;
+
+ Token tok;
+ ExprNode cond;
+ if( GET_TOK(tok, lex) == TOK_RWORD_LET ) {
+ throw ParseError::Todo("if let");
+ }
+ else {
+ lex.putback(tok);
+ cond = Parse_Expr0(lex);
+ }
+
+ // Contents
+ ExprNode code = Parse_ExprBlockNode(lex);
+
+ // Handle else:
+ ExprNode altcode;
+ if( GET_TOK(tok, lex) == TOK_RWORD_ELSE )
+ {
+ // Recurse for 'else if'
+ if( GET_TOK(tok, lex) == TOK_RWORD_IF ) {
+ altcode = Parse_IfStmt(lex);
+ }
+ // - or get block
+ else {
+ lex.putback(tok);
+ altcode = Parse_ExprBlockNode(lex);
+ }
+ }
+ // - or nothing
+ else {
+ lex.putback(tok);
+ altcode = ExprNode();
+ }
+
+ return ExprNode(ExprNode::TagIf(), cond, code, altcode);
+}
+
+// 0.5: Blocks
+AST::ExprNode Parse_ExprBlocks(TokenStream& lex)
+{
+ Token tok = lex.getToken();
+ switch( tok.type() )
+ {
+ case TOK_RWORD_MATCH: {
+ // 1. Get expression
+ AST::ExprNode switch_val = Parse_Expr1(lex);
+ GET_CHECK_TOK(tok, lex, TOK_BRACE_OPEN);
+ ::std::vector< ::std::pair<AST::Pattern, ExprNode> > arms;
+ do {
+ if( GET_TOK(tok, lex) == TOK_BRACE_CLOSE )
+ break;
+ lex.putback(tok);
+ AST::Pattern pat = Parse_Pattern(lex);
+ GET_CHECK_TOK(tok, lex, TOK_FATARROW);
+ bool opt_semicolon = false;
+ AST::ExprNode val = Parse_Stmt(lex, opt_semicolon);
+ arms.push_back( ::std::make_pair(pat, val) );
+ } while( GET_TOK(tok, lex) == TOK_COMMA );
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+ return AST::ExprNode(ExprNode::TagMatch(), switch_val, arms);
+ }
+ case TOK_RWORD_IF:
+ // TODO: if let
+ return Parse_IfStmt(lex);
+ default:
+ lex.putback(tok);
+ return Parse_Expr1(lex);
+ }
+}
+
+
+#define LEFTASSOC(cur, _next, cases) \
+AST::ExprNode _next(TokenStream& lex); \
+AST::ExprNode cur(TokenStream& lex) \
+{ \
+ AST::ExprNode (*next)(TokenStream&) = _next;\
+ AST::ExprNode rv = next(lex); \
+ while(true) \
+ { \
+ Token tok; \
+ switch((tok = lex.getToken()).type()) \
+ { \
+ cases \
+ default: \
+ ::std::cout << "<<" << #cur << ::std::endl; \
+ lex.putback(tok); \
+ return rv; \
+ } \
+ } \
+}
+// 1: Bool OR
+LEFTASSOC(Parse_Expr1, Parse_Expr2,
+ case TOK_DOUBLE_PIPE:
+ throw ParseError::Todo("expr - boolean OR");
+)
+// 2: Bool AND
+LEFTASSOC(Parse_Expr2, Parse_Expr3,
+ case TOK_DOUBLE_AMP:
+ throw ParseError::Todo("expr - boolean AND");
+)
+// 3: (In)Equality
+LEFTASSOC(Parse_Expr3, Parse_Expr4,
+ case TOK_DOUBLE_EQUAL:
+ rv = ExprNode(ExprNode::TagBinOp(), ExprNode::BINOP_CMPEQU, rv, next(lex));
+ break;
+ case TOK_EXCLAM_EQUAL:
+ rv = ExprNode(ExprNode::TagBinOp(), ExprNode::BINOP_CMPNEQU, rv, next(lex));
+ break;
+)
+// 4: Comparisons
+LEFTASSOC(Parse_Expr4, Parse_Expr5,
+ case TOK_LT:
+ throw ParseError::Todo("expr - less than");
+ case TOK_GT:
+ throw ParseError::Todo("expr - greater than");
+ case TOK_LTE:
+ throw ParseError::Todo("expr - less than or equal");
+ case TOK_GTE:
+ throw ParseError::Todo("expr - greater than or equal");
+)
+// 5: Bit OR
+LEFTASSOC(Parse_Expr5, Parse_Expr6,
+ case TOK_PIPE:
+ rv = ExprNode(ExprNode::TagBinOp(), ExprNode::BINOP_BITOR, rv, next(lex));
+ break;
+)
+// 6: Bit XOR
+LEFTASSOC(Parse_Expr6, Parse_Expr7,
+ case TOK_CARET:
+ rv = ExprNode(ExprNode::TagBinOp(), ExprNode::BINOP_BITXOR, rv, next(lex));
+ break;
+)
+// 7: Bit AND
+LEFTASSOC(Parse_Expr7, Parse_Expr8,
+ case TOK_AMP:
+ rv = ExprNode(ExprNode::TagBinOp(), ExprNode::BINOP_BITAND, rv, next(lex));
+ break;
+)
+// 8: Bit Shifts
+LEFTASSOC(Parse_Expr8, Parse_Expr9,
+ case TOK_DOUBLE_LT:
+ rv = ExprNode(ExprNode::TagBinOp(), ExprNode::BINOP_SHL, rv, next(lex));
+ break;
+ case TOK_DOUBLE_GT:
+ rv = ExprNode(ExprNode::TagBinOp(), ExprNode::BINOP_SHR, rv, next(lex));
+ break;
+)
+// 9: Add / Subtract
+LEFTASSOC(Parse_Expr9, Parse_Expr10,
+ case TOK_PLUS:
+ throw ParseError::Todo("expr - add");
+ case TOK_DASH:
+ throw ParseError::Todo("expr - sub");
+)
+// 10: Cast
+LEFTASSOC(Parse_Expr10, Parse_Expr11,
+ case TOK_RWORD_AS:
+ rv = ExprNode(ExprNode::TagCast(), rv, Parse_Type(lex));
+ break;
+)
+// 11: Times / Divide / Modulo
+LEFTASSOC(Parse_Expr11, Parse_Expr12,
+ case TOK_STAR:
+ throw ParseError::Todo("expr - multiply");
+ case TOK_SLASH:
+ throw ParseError::Todo("expr - divide");
+ case TOK_PERCENT:
+ throw ParseError::Todo("expr - modulo");
+)
+// 12: Unaries
+AST::ExprNode Parse_ExprFC(TokenStream& lex);
+AST::ExprNode Parse_Expr12(TokenStream& lex)
+{
+ Token tok;
+ switch((tok = lex.getToken()).type())
+ {
+ case TOK_DASH:
+ throw ParseError::Todo("expr - negate");
+ case TOK_EXCLAM:
+ throw ParseError::Todo("expr - logical negate");
+ case TOK_STAR:
+ throw ParseError::Todo("expr - dereference");
+ case TOK_RWORD_BOX:
+ throw ParseError::Todo("expr - box");
+ case TOK_AMP:
+ throw ParseError::Todo("expr - borrow");
+ default:
+ lex.putback(tok);
+ return Parse_ExprFC(lex);
+ }
+}
+
+AST::ExprNode Parse_ExprVal(TokenStream& lex);
+AST::ExprNode Parse_ExprFC(TokenStream& lex)
+{
+ AST::ExprNode val = Parse_ExprVal(lex);
+ while(true)
+ {
+ Token tok;
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_PAREN_OPEN:
+ // Function call
+ lex.putback(tok);
+ val = AST::ExprNode(AST::ExprNode::TagCallObject(), val, Parse_ParenList(lex));
+ break;
+ case TOK_DOT:
+ // Field access
+ // TODO: What about tuple indexing?
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ val = AST::ExprNode(AST::ExprNode::TagField(), tok.str());
+ break;
+ default:
+ lex.putback(tok);
+ return val;
+ }
+ }
+}
+
+AST::ExprNode Parse_ExprVal(TokenStream& lex)
+{
+ Token tok;
+ AST::Path path;
+ switch((tok = lex.getToken()).type())
+ {
+ case TOK_IDENT:
+ // Get path
+ lex.putback(tok);
+ path = Parse_Path(lex, false, PATH_GENERIC_EXPR);
+ if(0)
+ case TOK_DOUBLE_COLON:
+ path = Parse_Path(lex, true, PATH_GENERIC_EXPR);
+ switch( GET_TOK(tok, lex) )
+ {
+ case TOK_BRACE_OPEN: {
+ // Braced structure literal
+ // - A series of 0 or more pairs of <ident>: <expr>,
+ // - '..' <expr>
+ ::std::vector< ::std::pair< ::std::string, AST::ExprNode> > items;
+ while( GET_TOK(tok, lex) == TOK_IDENT )
+ {
+ ::std::string name = tok.str();
+ GET_CHECK_TOK(tok, lex, TOK_COLON);
+ AST::ExprNode val = Parse_Expr0(lex);
+ items.push_back( ::std::make_pair(name, val) );
+ if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE )
+ break;
+ CHECK_TOK(tok, TOK_COMMA);
+ }
+ AST::ExprNode base_val;
+ if( tok.type() == TOK_DOUBLE_DOT )
+ {
+ // default
+ base_val = Parse_Expr0(lex);
+ GET_TOK(tok, lex);
+ }
+ CHECK_TOK(tok, TOK_BRACE_CLOSE);
+ return ExprNode(ExprNode::TagStructLiteral(), path, base_val, items);
+ }
+ case TOK_PAREN_OPEN: {
+ lex.putback(tok);
+ // Function call
+ ::std::vector<AST::ExprNode> args = Parse_ParenList(lex);
+ return ExprNode(ExprNode::TagCallPath(), path, args);
+ }
+ default:
+ // Value
+ lex.putback(tok);
+ return ExprNode(ExprNode::TagNamedValue(), path);
+ }
+ case TOK_INTEGER:
+ return ExprNode(ExprNode::TagInteger(), tok.intval(), tok.datatype());
+ case TOK_FLOAT:
+ throw ParseError::Todo("Float");
+ case TOK_RWORD_SELF: {
+ AST::Path path;
+ path.append( AST::PathNode("self", ::std::vector<TypeRef>()) );
+ return ExprNode(ExprNode::TagNamedValue(), path);
+ }
+ case TOK_PAREN_OPEN: {
+ ExprNode 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
+ MacroExpander expanded_macro = Macro_Invoke(tok.str().c_str(), Parse_TT(lex));
+
+ return Parse_Expr0(expanded_macro);
+ }
+ default:
+ throw ParseError::Unexpected(tok);
+ }
+}
+
+// Token Tree Parsing
+TokenTree Parse_TT(TokenStream& lex)
+{
+ Token tok = lex.getToken();
+ eTokenType closer = TOK_PAREN_CLOSE;
+ switch(tok.type())
+ {
+ case TOK_PAREN_OPEN:
+ closer = TOK_PAREN_CLOSE;
+ break;
+ case TOK_SQUARE_OPEN:
+ closer = TOK_SQUARE_CLOSE;
+ break;
+ case TOK_BRACE_OPEN:
+ closer = TOK_BRACE_CLOSE;
+ break;
+ default:
+ return TokenTree(tok);
+ }
+
+ ::std::vector<TokenTree> items;
+ items.push_back(tok);
+ while(GET_TOK(tok, lex) != closer && tok.type() != TOK_EOF)
+ {
+ lex.putback(tok);
+ items.push_back(Parse_TT(lex));
+ }
+ items.push_back(tok);
+ return TokenTree(items);
+}
+
+TokenTree Parse_TT_Path(TokenStream& lex)
+{
+ throw ParseError::Todo("TokenTree path");
+}
+/// Parse a token tree path
+TokenTree Parse_TT_Val(TokenStream& lex)
+{
+ Token tok;
+ ::std::vector<TokenTree> ret;
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_PAREN_OPEN:
+ lex.putback(tok);
+ return Parse_TT(lex);
+
+ case TOK_IDENT:
+ case TOK_DOUBLE_COLON: {
+ lex.putback(tok);
+ TokenTree inner = Parse_TT_Path(lex);
+ if(GET_TOK(tok, lex) == TOK_BRACE_OPEN) {
+ lex.putback(tok);
+ ret.push_back(inner);
+ ret.push_back(Parse_TT(lex));
+ }
+ else {
+ lex.putback(tok);
+ return inner;
+ }
+ break; }
+ case TOK_RWORD_SELF:
+ return TokenTree(tok);
+ case TOK_RWORD_MATCH:
+ ret.push_back(TokenTree(tok));
+ ret.push_back(Parse_TT(lex));
+ break;
+ case TOK_RWORD_IF:
+ ret.push_back(TokenTree(tok));
+ ret.push_back(Parse_TT(lex));
+ if( GET_TOK(tok, lex) == TOK_RWORD_ELSE ) {
+ ret.push_back(TokenTree(tok));
+ ret.push_back(Parse_TT(lex));
+ }
+ else {
+ lex.putback(tok);
+ }
+ break;
+ default:
+ // Oh, fail :(
+ throw ParseError::Unexpected(tok);
+ }
+ return TokenTree(ret);
+}
+/// Parse a token tree expression
+TokenTree Parse_TT_Expr(TokenStream& lex)
+{
+ Token tok;
+ ::std::vector<TokenTree> ret;
+
+ ret.push_back(Parse_TT_Val(lex));
+ // 1. Get left associative blocks until nothing matches
+ bool cont = true;
+ while(cont)
+ {
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_PLUS:
+ case TOK_DASH:
+ ret.push_back(tok);
+ ret.push_back(Parse_TT_Val(lex));
+ break;
+ case TOK_DOT:
+ ret.push_back(tok);
+ GET_CHECK_TOK(tok, lex, TOK_IDENT);
+ ret.push_back(tok);
+ switch(GET_TOK(tok, lex))
+ {
+ case TOK_DOUBLE_COLON:
+ throw ParseError::Todo("Generic type params in TT expr");
+ case TOK_PAREN_OPEN:
+ lex.putback(tok);
+ ret.push_back(Parse_TT(lex));
+ break;
+ default:
+ lex.putback(tok);
+ break;
+ }
+ break;
+ default:
+ lex.putback(tok);
+ cont = false;
+ break;
+ }
+ }
+ return TokenTree(ret);
+
+}
+TokenTree Parse_TT_Stmt(TokenStream& lex)
+{
+ throw ParseError::Todo("Parse_TT_Stmt");
+}
+TokenTree Parse_TT_Block(TokenStream& lex)
+{
+ throw ParseError::Todo("Parse_TT_Block");
+}
|