diff --git a/parser.c b/parser.c index 9545f7d..5ece824 100644 --- a/parser.c +++ b/parser.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -9,6 +10,12 @@ const AstNodeIndex null_node = 0; const AstTokenIndex null_token = ~(AstTokenIndex)(0); +static AstNodeIndex parsePrefixExpr(Parser*); +static AstNodeIndex parseTypeExpr(Parser*); +static AstNodeIndex parseBlock(Parser* p); +static AstNodeIndex parseLabeledStatement(Parser*); +static AstNodeIndex parseExpr(Parser*); + typedef struct { enum { FIELD_STATE_NONE, FIELD_STATE_SEEN, FIELD_STATE_END } tag; union { @@ -75,6 +82,12 @@ static AstTokenIndex eatToken(Parser* p, TokenizerTag tag) { } } +static AstTokenIndex assertToken(Parser* p, TokenizerTag tag) { + const AstTokenIndex token = nextToken(p); + assert(p->token_tags[token] == tag); + return token; +} + static void eatDocComments(Parser* p) { while (eatToken(p, TOKEN_DOC_COMMENT) != null_token) { } } @@ -150,8 +163,6 @@ static AstNodeIndex parseCallconv(Parser* p) { return 0; // tcc } -static AstNodeIndex parseTypeExpr(Parser*); - typedef struct { AstNodeIndex align_expr, value_expr; } NodeContainerField; @@ -207,6 +218,29 @@ static AstNodeIndex expectContainerField(Parser* p) { } } +static AstNodeIndex parseBuiltinCall(Parser* p) { + const AstNodeIndex builtin_token = assertToken(p, TOKEN_BUILTIN); + eatToken(p, TOKEN_L_PAREN); + + CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) + = initCleanupScratch(p); + + while (true) { + if (eatToken(p, TOKEN_R_PAREN) != null_token) + break; + + const AstNodeIndex param = parseExpr(p); + SLICE_APPEND(AstNodeIndex, &p->scratch, param); + // TODO finish + } + + (void)builtin_token; + + fprintf(stderr, "parseBuiltinCall not implemented\n"); + exit(1); + return 0; // tcc +} + static AstNodeIndex parsePrimaryTypeExpr(Parser* p) { const TokenizerTag tok = p->token_tags[p->tok_i]; switch (tok) { @@ -216,6 +250,7 @@ static AstNodeIndex parsePrimaryTypeExpr(Parser* p) { case TOKEN_KEYWORD_ANYFRAME: case TOKEN_STRING_LITERAL: case TOKEN_BUILTIN: + return parseBuiltinCall(p); case TOKEN_KEYWORD_FN: case TOKEN_KEYWORD_IF: case TOKEN_KEYWORD_SWITCH: @@ -516,11 +551,56 @@ static AstNodeIndex parseAssignExpr(Parser* p) { } static AstNodeIndex parseVarDeclProto(Parser* p) { - if (eatToken(p, TOKEN_KEYWORD_CONST) == null_token - || eatToken(p, TOKEN_KEYWORD_VAR) == null_token) + AstTokenIndex mut_token; + if ((mut_token = eatToken(p, TOKEN_KEYWORD_CONST)) == null_token) + if ((mut_token = eatToken(p, TOKEN_KEYWORD_VAR)) == null_token) + return null_node; + + expectToken(p, TOKEN_IDENTIFIER); + const AstNodeIndex type_node + = eatToken(p, TOKEN_COLON) == null_token ? 0 : parseTypeExpr(p); + const AstNodeIndex align_node = parseByteAlign(p); + const AstNodeIndex addrspace_node = parseAddrSpace(p); + const AstNodeIndex section_node = parseLinkSection(p); + + if (section_node == 0 && addrspace_node == 0) { + if (align_node == 0) { + return addNode( + &p->nodes, + (AstNodeItem) { + .tag = AST_NODE_SIMPLE_VAR_DECL, + .main_token = mut_token, + .data = { + .lhs = type_node, + .rhs = 0, + }, + }); + } + fprintf(stderr, "parseVarDecl got something too complicated\n"); + exit(1); + } else { + fprintf(stderr, "parseVarDecl got something too complicated\n"); + exit(1); + } + return 0; // tcc +} + +static AstTokenIndex parseBreakLabel(Parser* p) { + if (eatToken(p, TOKEN_COLON) == null_node) + return null_node; + return expectToken(p, TOKEN_IDENTIFIER); +} + +static AstNodeIndex parseCurlySuffixExpr(Parser* p) { + const AstNodeIndex lhs = parseTypeExpr(p); + if (lhs == 0) return null_node; - fprintf(stderr, "parseVarDeclProto: parsing vars is not supported\n"); + const AstTokenIndex lbrace = eatToken(p, TOKEN_L_BRACE); + if (lbrace == null_token) + return lhs; + + fprintf(stderr, "parseCurlySuffixExpr is not implemented\n"); exit(1); return 0; // tcc } @@ -619,25 +699,184 @@ static OperInfo operTable(TokenizerTag tok_tag) { } } +static AstNodeIndex parseExprPrecedence(Parser* p, int32_t min_prec) { + (void)p; + assert(min_prec >= 0); + + AstNodeIndex node = parsePrefixExpr(p); + if (node == 0) + return null_node; + + int8_t banned_prec = -1; + + while (true) { + const TokenizerTag tok_tag = p->token_tags[p->tok_i]; + const OperInfo info = operTable(tok_tag); + if (info.prec < min_prec) + break; + + assert(info.prec != banned_prec); + + const AstTokenIndex oper_token = nextToken(p); + if (tok_tag == TOKEN_KEYWORD_CATCH) { + fprintf(stderr, "parsePayload not supported\n"); + exit(1); + return 0; // tcc + } + const AstNodeIndex rhs = parseExprPrecedence(p, info.prec + 1); + assert(rhs != 0); + + node = addNode( + &p->nodes, + (AstNodeItem) { + .tag = info.tag, + .main_token = oper_token, + .data = { + .lhs = node, + .rhs = rhs, + }, + }); + + if (info.assoc == ASSOC_NONE) + banned_prec = info.prec; + } + + return node; +} + +static AstNodeIndex parseExpr(Parser* p) { return parseExprPrecedence(p, 0); } + +static AstNodeIndex parsePrimaryExpr(Parser* p) { + const char* tok = tokenizerGetTagString(p->token_tags[p->tok_i]); + switch (p->token_tags[p->tok_i]) { + case TOKEN_KEYWORD_ASM: + case TOKEN_KEYWORD_IF: + fprintf(stderr, "parsePrimaryExpr does not implement %s\n", tok); + exit(1); + break; + case TOKEN_KEYWORD_BREAK: + return addNode( + &p->nodes, + (AstNodeItem) { + .tag = AST_NODE_BREAK, + .main_token = nextToken(p), + .data = { + .lhs = parseBreakLabel(p), + .rhs = parseExpr(p), + }, + }); + case TOKEN_KEYWORD_CONTINUE: + return addNode( + &p->nodes, + (AstNodeItem) { + .tag = AST_NODE_CONTINUE, + .main_token = nextToken(p), + .data = { + .lhs = parseBreakLabel(p), + .rhs = parseExpr(p), + }, + }); + case TOKEN_KEYWORD_COMPTIME: + case TOKEN_KEYWORD_NOSUSPEND: + case TOKEN_KEYWORD_RESUME: + case TOKEN_KEYWORD_RETURN: + fprintf(stderr, "parsePrimaryExpr does not implement %s\n", tok); + exit(1); + return 0; // tcc + case TOKEN_IDENTIFIER: + if (p->token_tags[p->tok_i + 1] == TOKEN_COLON) { + switch (p->token_tags[p->tok_i + 2]) { + case TOKEN_KEYWORD_INLINE: + case TOKEN_KEYWORD_FOR: + case TOKEN_KEYWORD_WHILE: + fprintf(stderr, "parsePrimaryExpr NotImplemented\n"); + exit(1); + return 0; // tcc + case TOKEN_L_BRACE: + p->tok_i += 2; + return parseBlock(p); + default: + return parseCurlySuffixExpr(p); + } + } else { + return parseCurlySuffixExpr(p); + } + case TOKEN_KEYWORD_INLINE: + case TOKEN_KEYWORD_FOR: + case TOKEN_KEYWORD_WHILE: + fprintf(stderr, "parsePrimaryExpr does not implement %s\n", tok); + exit(1); + return 0; // tcc + case TOKEN_L_BRACE: + return parseBlock(p); + default: + return parseCurlySuffixExpr(p); + } +} + +static AstNodeIndex parsePrefixExpr(Parser* p) { + AstNodeTag tag; + switch (p->token_tags[p->tok_i]) { + case TOKEN_BANG: + tag = AST_NODE_BOOL_NOT; + break; + case TOKEN_MINUS: + tag = AST_NODE_NEGATION; + break; + case TOKEN_TILDE: + tag = AST_NODE_BIT_NOT; + break; + case TOKEN_MINUS_PERCENT: + tag = AST_NODE_NEGATION_WRAP; + break; + case TOKEN_AMPERSAND: + tag = AST_NODE_ADDRESS_OF; + break; + case TOKEN_KEYWORD_TRY: + tag = AST_NODE_TRY; + break; + case TOKEN_KEYWORD_AWAIT: + tag = AST_NODE_AWAIT; + break; + default: + return parsePrimaryExpr(p); + } + return addNode( + &p->nodes, + (AstNodeItem) { + .tag = tag, + .main_token = nextToken(p), + .data = { + .lhs = parsePrefixExpr(p), + .rhs = 0, + }, + }); +} + static AstNodeIndex expectVarDeclExprStatement(Parser* p) { CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch))) = initCleanupScratch(p); - // while(true) { - // const AstNodeIndex var_decl_proto = parseVarDeclProto(p); - // if (var_decl_proto != 0) { - // SLICE_APPEND(AstNodeIndex, &p->scratch, var_decl_proto); - // } else { + while (true) { + const AstNodeIndex var_decl_proto = parseVarDeclProto(p); + if (var_decl_proto != 0) { + SLICE_APPEND(AstNodeIndex, &p->scratch, var_decl_proto); + } else { + const AstNodeIndex expr = parseExpr(p); + SLICE_APPEND(AstNodeIndex, &p->scratch, expr); + } + if (eatToken(p, TOKEN_COMMA) == null_node) + break; + } - // } - //} + const uint32_t lhs_count = p->scratch.len - scratch_top.old_len; + assert(lhs_count > 0); - fprintf(stderr, "expectVarDeclExprStatement not implemented\n"); + fprintf(stderr, "expectVarDeclExprStatement only partially implemented\n"); exit(1); return 0; // tcc } -static AstNodeIndex parseLabeledStatement(Parser*); static AstNodeIndex expectStatement(Parser* p, bool allow_defer_var) { if (eatToken(p, TOKEN_KEYWORD_COMPTIME) != null_token) { fprintf(stderr, "expectStatement: comptime keyword not supported\n");