more parser
This commit is contained in:
267
parser.c
267
parser.c
@@ -1,3 +1,4 @@
|
|||||||
|
#include <assert.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -9,6 +10,12 @@
|
|||||||
const AstNodeIndex null_node = 0;
|
const AstNodeIndex null_node = 0;
|
||||||
const AstTokenIndex null_token = ~(AstTokenIndex)(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 {
|
typedef struct {
|
||||||
enum { FIELD_STATE_NONE, FIELD_STATE_SEEN, FIELD_STATE_END } tag;
|
enum { FIELD_STATE_NONE, FIELD_STATE_SEEN, FIELD_STATE_END } tag;
|
||||||
union {
|
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) {
|
static void eatDocComments(Parser* p) {
|
||||||
while (eatToken(p, TOKEN_DOC_COMMENT) != null_token) { }
|
while (eatToken(p, TOKEN_DOC_COMMENT) != null_token) { }
|
||||||
}
|
}
|
||||||
@@ -150,8 +163,6 @@ static AstNodeIndex parseCallconv(Parser* p) {
|
|||||||
return 0; // tcc
|
return 0; // tcc
|
||||||
}
|
}
|
||||||
|
|
||||||
static AstNodeIndex parseTypeExpr(Parser*);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
AstNodeIndex align_expr, value_expr;
|
AstNodeIndex align_expr, value_expr;
|
||||||
} NodeContainerField;
|
} 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) {
|
static AstNodeIndex parsePrimaryTypeExpr(Parser* p) {
|
||||||
const TokenizerTag tok = p->token_tags[p->tok_i];
|
const TokenizerTag tok = p->token_tags[p->tok_i];
|
||||||
switch (tok) {
|
switch (tok) {
|
||||||
@@ -216,6 +250,7 @@ static AstNodeIndex parsePrimaryTypeExpr(Parser* p) {
|
|||||||
case TOKEN_KEYWORD_ANYFRAME:
|
case TOKEN_KEYWORD_ANYFRAME:
|
||||||
case TOKEN_STRING_LITERAL:
|
case TOKEN_STRING_LITERAL:
|
||||||
case TOKEN_BUILTIN:
|
case TOKEN_BUILTIN:
|
||||||
|
return parseBuiltinCall(p);
|
||||||
case TOKEN_KEYWORD_FN:
|
case TOKEN_KEYWORD_FN:
|
||||||
case TOKEN_KEYWORD_IF:
|
case TOKEN_KEYWORD_IF:
|
||||||
case TOKEN_KEYWORD_SWITCH:
|
case TOKEN_KEYWORD_SWITCH:
|
||||||
@@ -516,11 +551,56 @@ static AstNodeIndex parseAssignExpr(Parser* p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static AstNodeIndex parseVarDeclProto(Parser* p) {
|
static AstNodeIndex parseVarDeclProto(Parser* p) {
|
||||||
if (eatToken(p, TOKEN_KEYWORD_CONST) == null_token
|
AstTokenIndex mut_token;
|
||||||
|| eatToken(p, TOKEN_KEYWORD_VAR) == null_token)
|
if ((mut_token = eatToken(p, TOKEN_KEYWORD_CONST)) == null_token)
|
||||||
|
if ((mut_token = eatToken(p, TOKEN_KEYWORD_VAR)) == null_token)
|
||||||
return null_node;
|
return null_node;
|
||||||
|
|
||||||
fprintf(stderr, "parseVarDeclProto: parsing vars is not supported\n");
|
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;
|
||||||
|
|
||||||
|
const AstTokenIndex lbrace = eatToken(p, TOKEN_L_BRACE);
|
||||||
|
if (lbrace == null_token)
|
||||||
|
return lhs;
|
||||||
|
|
||||||
|
fprintf(stderr, "parseCurlySuffixExpr is not implemented\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
return 0; // tcc
|
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) {
|
static AstNodeIndex expectVarDeclExprStatement(Parser* p) {
|
||||||
CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch)))
|
CleanupScratch scratch_top __attribute__((__cleanup__(cleanupScratch)))
|
||||||
= initCleanupScratch(p);
|
= initCleanupScratch(p);
|
||||||
|
|
||||||
// while(true) {
|
while (true) {
|
||||||
// const AstNodeIndex var_decl_proto = parseVarDeclProto(p);
|
const AstNodeIndex var_decl_proto = parseVarDeclProto(p);
|
||||||
// if (var_decl_proto != 0) {
|
if (var_decl_proto != 0) {
|
||||||
// SLICE_APPEND(AstNodeIndex, &p->scratch, var_decl_proto);
|
SLICE_APPEND(AstNodeIndex, &p->scratch, var_decl_proto);
|
||||||
// } else {
|
} 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);
|
exit(1);
|
||||||
return 0; // tcc
|
return 0; // tcc
|
||||||
}
|
}
|
||||||
|
|
||||||
static AstNodeIndex parseLabeledStatement(Parser*);
|
|
||||||
static AstNodeIndex expectStatement(Parser* p, bool allow_defer_var) {
|
static AstNodeIndex expectStatement(Parser* p, bool allow_defer_var) {
|
||||||
if (eatToken(p, TOKEN_KEYWORD_COMPTIME) != null_token) {
|
if (eatToken(p, TOKEN_KEYWORD_COMPTIME) != null_token) {
|
||||||
fprintf(stderr, "expectStatement: comptime keyword not supported\n");
|
fprintf(stderr, "expectStatement: comptime keyword not supported\n");
|
||||||
|
|||||||
Reference in New Issue
Block a user