Files
corelang/new_parse.cpp

374 lines
9.8 KiB
C++

function Token *
token_get(S64 i = 0){
i += pctx->token_iter;
if(i >= pctx->tokens.len){
return &pctx->empty_token;
}
Token *result = &pctx->tokens[i];
if(result->kind == TK_NewLine){
pctx->indent = result->indent;
}
return result;
}
function Token *
token_next(){
Token *token = token_get();
pctx->token_iter++;
return token;
}
function Token *
token_is(Token_Kind kind){
Token *token = token_get();
if(token->kind == kind){
return token;
}
return 0;
}
function Token *
token_match(Token_Kind kind){
Token *token = token_get();
if(token->kind == kind){
return token_next();
}
return 0;
}
function Token *
token_match_keyword(Intern_String string){
Token *token = token_get();
if(token->kind == TK_Keyword){
if(string.str == token->intern_val.str){
token = token_next();
return token;
}
}
return 0;
}
function void
parsing_error(Token *token, const char *str, ...){
Scratch scratch;
STRING_FMT(scratch, str, string);
// @Note(Krzosa): Print nice error message
printf("\nError: %s", string.str);
if(token){
printf(" %s:%d\n", token->file.str, (S32)token->line);
// @Note(Krzosa): Print error line
{
int i = 0;
while(token->line_begin[i]!='\n' && token->line_begin[i]!=0) i++;
printf("%.*s\n", i, token->line_begin);
// @Note(Krzosa): Print error marker
int token_i = token->str - token->line_begin;
for(int i = 0; i < token_i-2; i++) printf(" ");
printf("^^^^^^\n");
}
}
__debugbreak();
}
function Token *
token_expect(Token_Kind kind){
Token *token = token_get();
if(token->kind == kind){
token = token_next();
return token;
}
parsing_error(token, "Expected token of kind: [%s], got instead token of kind: [%s]", token_kind_string(kind).str, token_kind_string(token->kind).str);
return 0;
}
//-----------------------------------------------------------------------------
// Expression parsing
//-----------------------------------------------------------------------------
/*
add = [+-]
mul = [/%*]
compare = == | != | >= | > | <= | <
logical = [&|^] | && | ||
unary = [&*-!~+] | ++ | --
atom_expr = Int
| Float
| String
| Identifier
| 'cast' '(' typespec ',' expr ')'
| 'size_type' '(' typespec ')'
| 'size_expr' '(' expr ')'
| '{' compound_expr '}'
| '(' expr ')'
| '(' ':' typespec ')' '{' compound_expr '}'
postfix_expr = atom_expr ('[' expr ']' | '.' Identifier | ++ | -- | '(' expr_list ')')*
unary_expr = unary ? unary_expr : atom_expr
mul_expr = atom_expr (mul atom_expr)*
add_expr = mul_expr (add mul_expr)*
logical_expr = add_expr (logical add_expr)*
compare_expr = logical_expr (compare logical_expr)*
ternary_expr = compare_expr ('?' ternary_expr ':' ternary_expr)?
expr = logical_expr
Compound literals
- (:[23]*Type){}
- Type{}
- { }
*/
function Ast_Expr *parse_expr(S64 rbp = 0);
function Ast_Typespec *parse_typespec();
function Ast_Expr *
parse_expr_compound(){
Scratch scratch;
Token *pos = token_get();
Array<Ast_Expr *> exprs = {scratch};
while(!token_is(TK_CloseBrace)){
Token *token = token_get();
Ast_Expr *index = 0;
Ast_Expr *name = 0;
if(token_match(TK_OpenBracket)){
index = parse_expr();
token_expect(TK_CloseBracket);
token_expect(TK_Assign);
}
else if(token_is(TK_Identifier)){
token = token_next();
name = ast_expr_identifier(token, token->intern_val);
token_expect(TK_Assign);
}
Ast_Expr *item = parse_expr();
Ast_Expr *item_comp = ast_expr_compound_item(token, index, name, item);
exprs.add(item_comp);
if(!token_match(TK_Comma)){
break;
}
}
token_expect(TK_CloseBrace);
Ast_Expr *result = ast_expr_compound(pos, 0, exprs);
return result;
}
function Ast_Expr *
parse_expr_nud(Token *token){
switch(token->kind){
case TK_StringLit: return ast_expr_string(token, token->intern_val);
case TK_Identifier: return ast_expr_identifier(token, token->intern_val);
case TK_Integer: return ast_expr_integer(token, token->int_val);
case TK_Keyword: {
if(token->intern_val == keyword_cast){
token_expect(TK_OpenParen);
Ast_Expr *expr = parse_expr();
token_expect(TK_Colon);
Ast_Typespec *typespec = parse_typespec();
token_expect(TK_CloseParen);
return ast_expr_cast(token, expr, typespec);
}
else {
parsing_error(token, "Unexpected keyword: [%s], expected keyword [cast]", token->intern_val.str);
return 0;
}
}break;
case TK_OpenBrace: return parse_expr_compound();
case TK_OpenParen: {Ast_Expr *result = parse_expr(); token_expect(TK_CloseParen); return result;}
default: parsing_error(token, "Unexpected token of kind: [%s] in expression", token_kind_string(token->kind).str); return 0;
}
}
function S64
op_precedence(Token_Kind kind){
S64 result = pctx->pt[kind];
return result;
}
function Ast_Expr *
parse_expr_led(Token *op, Ast_Expr *left){
enum{ Left_Associative, Right_Associative };
S64 assoc = Left_Associative;
Ast_Expr *right = parse_expr(op_precedence(op->kind) - assoc);
switch(op->kind){
case TK_Add: case TK_Mul: case TK_Sub: case TK_Div: return ast_expr_binary(left, right, op);
default: parsing_error(op, "Unexpected token of kind: [%s] in expression", token_kind_string(op->kind).str); return 0;
}
}
function Ast_Expr *
parse_expr(S64 rbp){
Token *token = token_next();
Ast_Expr *left = parse_expr_nud(token);
while(rbp < op_precedence(token_get()->kind)){
token = token_next();
left = parse_expr_led(token, left);
}
return left;
}
function S64
expr_eval(Ast_Expr *expr){
switch(expr->kind){
case AK_Expr_Int: return expr->int_val;
case AK_Expr_Binary : {
S64 left = expr_eval(expr->binary.left);
S64 right = expr_eval(expr->binary.right);
switch(expr->binary.op){
case TK_Add: return left + right;
case TK_Sub: return left - right;
case TK_Mul: return left * right;
case TK_Div: return left / right;
default: invalid_codepath;
}
}break;
default: invalid_codepath;
}
return 0;
}
#define TEST_PARSER() \
Scratch scratch(thread_ctx.scratch);\
Parse_Ctx ctx = {}; \
ctx.init(scratch, scratch); \
pctx = &ctx
function void
test_parse_expr(){
TEST_PARSER();
struct Test{String str;S64 val;};
Array<Test> exprs = {scratch};
exprs.add({"(4+5)*2"_s, (4+5)*2});
exprs.add({"4+5*2"_s, 4+5*2});
exprs.add({"4*5+5"_s, 4*5+5});
exprs.add({"4+5+5+3"_s, 4+5+5+3});
Iter(exprs){
lex_restream(&ctx, it->str, "test_expr"_s);
Ast_Expr *result = parse_expr();
S64 val = expr_eval(result);
assert(val == it->val);
}
}
//-----------------------------------------------------------------------------
// Parsing declarations
//-----------------------------------------------------------------------------
function Ast_Typespec *
parse_optional_type(){
Ast_Typespec *result = 0;
if(token_match(TK_Colon)) result = parse_typespec();
return result;
}
function Ast_Typespec *
parse_typespec_function(Token *token){
Scratch scratch;
Array<Ast_Typespec *> args = {scratch};
if(!token_is(TK_CloseParen)) {
for(;;) {
args.add(parse_typespec());
if(!token_match(TK_Comma)){
break;
}
}
}
token_expect(TK_CloseParen);
Ast_Typespec *ret = parse_optional_type();
Ast_Typespec *result = ast_typespec_func(token, ret, args);
return result;
}
// [10]*int - Array of 10 pointers to ints
function Ast_Typespec *
parse_typespec_recurse(){
Token *token = token_get();
if(token_match(TK_Mul)){
Ast_Typespec *result = parse_typespec_recurse();
result = ast_typespec_pointer(token, result);
return result;
}
else if(token_match(TK_OpenBracket)){
Ast_Expr *expr = parse_expr();
token_expect(TK_CloseBracket);
Ast_Typespec *result = parse_typespec_recurse();
result = ast_typespec_array(token, result, expr);
return result;
}
else if(token_match(TK_OpenParen)){
Ast_Typespec *result = parse_typespec_function(token);
return result;
}
else if(token_match(TK_Identifier)){
Ast_Typespec *result = ast_typespec_name(token, token->intern_val);
return result;
}
else{
parsing_error(token, "Failed to parse type, unexpected token of kind", token_kind_string(token->kind).str);
return 0;
}
}
function Ast_Typespec *
parse_typespec(){
Ast_Typespec *result = parse_typespec_recurse();
return result;
}
function Ast_Expr *
parse_assign_expr(){
Ast_Expr *result = 0;
if(token_match(TK_Assign)) result = parse_expr();
return result;
}
function Ast_Decl *
parse_decl(){
Ast_Decl *result = 0;
if(token_is(TK_Identifier)){
if(pctx->indent != 0) parsing_error(token_get(), "Top level declarations shouldn't be indented");
Token *name = token_next();
if(token_match(TK_DoubleColon)){ // Constant
Ast_Expr *expr = parse_expr();
result = ast_decl_const(name, name->intern_val, expr);
}
else if(token_match(TK_Colon)){
Ast_Typespec *typespec = 0;
Ast_Expr *expr = 0;
if(!token_is(TK_Assign)) typespec = parse_typespec();
if(token_match(TK_Assign)) expr = parse_expr();
if(!expr && !typespec) parsing_error(name, "invalid declaration, no type or value");
result = ast_decl_var(name, typespec, name->intern_val, expr);
}
else{
Token *token = token_get();
parsing_error(token, "Unexpected token: [%s] when parsing a declaration", token_kind_string(token->kind).str);
}
}
return result;
}
function Ast_Package *
parse_file(){
Scratch scratch;
Token *token = token_get();
Array<Ast_Decl *>decls = {scratch};
while(!token_is(TK_End)){
while(token_match(TK_NewLine));
Ast_Decl *decl = parse_decl();
if(!decl) break;
decls.add(decl);
}
Ast_Package *result = ast_package(token, token->file, decls);
return result;
}