function Decl *parse_decl(Parser *p); function Decl *parse_struct(Parser *p, Token *name, Decl_Kind kind, Decl_Struct_Kind); function Typespec *parse_type(Parser *p); function Typespec * parse_type_function(Parser *p, Token *token){ Typespec *result = typespec_function(p, token, 0); if(!token_is(p, TK_CloseParen)) for(;;) { // Optional name if(token_is(p, TK_Identifier)){ if(token_peek_is(p, 1, TK_Colon)){ token_next(p); token_next(p); } } // Parse type if(token_is(p, TK_Identifier)){ Typespec *arg = parse_type(p); typespec_function_push(result, arg); } else if(!token_match(p, TK_Comma)){ break; } } token_expect(p, TK_CloseParen); if(token_is(p, TK_Identifier)) result->function_spec.ret = parse_type(p); else result->function_spec.ret = typespec_name(p, token_get(p), intern_void); return result; } function Typespec * parse_type(Parser *p){ // Parse as function type or normal Token *token = 0; Typespec *result = 0; if((token = token_match(p, TK_Identifier))){ result = typespec_name(p, token, token->intern_val); } else if((token = token_match(p, TK_OpenParen))){ result = parse_type_function(p, token); } else{ parser_push_error(p, token, "Failed to parse type, unexpected token"); return 0; } // Parse Pointer/Array for(;;){ if((token = token_match(p, TK_Mul))){ result = typespec_pointer(p, token, result); } else if((token = token_match(p, TK_OpenBracket))){ Expr *expr = parse_expr(p); result = typespec_array(p, token, result, expr); token_expect(p, TK_CloseBracket); } else if(token_match(p, TK_At)){ break; } else break; } return result; } function Expr * parse_expr_assignment(Parser *p){ Expr *result = 0; if(token_match(p, TK_Assign)){ result = parse_expr(p); } return result; } function void parse_note_list(Parser *p, Note *parent) { if(token_match(p, TK_OpenParen)) { if(token_match(p, TK_CloseParen)){ return; } do { Token *name = token_expect(p, TK_Identifier); Note *current = note_push_new(p, parent, name, name->intern_val, 0); parse_note_list(p, current); if(token_match(p, TK_Assign)) { current->expr = parse_expr(p); } } while(token_match(p, TK_Comma)); token_expect(p, TK_CloseParen); } } function void parse__notes(Parser *p, Note *result) { while(token_match(p, TK_At)) { Token *name = token_expect(p, TK_Identifier); Note *current = note_push_new(p, result, name, name->intern_val, 0); parse_note_list(p, current); if(token_match(p, TK_Assign)) { current->expr = parse_expr(p); } token_match(p, TK_Semicolon); } } function Note parse_notes(Parser *p){ Note result = {0}; parse__notes(p, &result); return result; } function Token * parse_get_token_name(Parser *p, S32 count){ Token *result = token_next(p); for(S32 i = 0; i < count; i++) token_next(p); return result; } function Decl * parse_enum(Parser *p, Token *name){ Typespec *type = 0; if(token_match(p, TK_Colon)) type = parse_type(p); else type = typespec_name(p, token_get(p), intern_s64); Decl *result = decl_enum(p, name, name->intern_val, type); token_expect(p, TK_OpenBrace); do{ Note notes = parse_notes(p); Token *token = token_match(p, TK_Identifier); if(token){ Expr *expr = parse_expr_assignment(p); decl_enum_push(p, result, token, token->intern_val, expr, ¬es); } else break; } while(token_match(p, TK_Comma)); token_expect(p, TK_CloseBrace); return result; } function Decl * parse_struct(Parser *p, Token *name, Decl_Kind kind, Decl_Struct_Kind struct_kind){ Decl *result = decl_struct(p, kind, name, name->intern_val, struct_kind); token_expect(p, TK_OpenBrace); while(!token_is(p, TK_CloseBrace)){ Decl *decl = 0; if((decl = parse_decl(p))){ } else if(token_match_keyword(p, keyword_union)){ decl = parse_struct(p, token_get(p), DECL_Union, STRUCT_Nested); } else if(token_match_keyword(p, keyword_struct)){ decl = parse_struct(p, token_get(p), DECL_Struct, STRUCT_Nested); } else if(token_is(p, TK_Identifier) && token_peek_is(p, 1, TK_Colon) && token_peek_is_keyword(p, 2, keyword_union)){ decl = parse_struct(p, parse_get_token_name(p, 2), DECL_Union, STRUCT_Nested); } else if(token_is(p, TK_Identifier) && token_peek_is(p, 1, TK_Colon) && token_peek_is_keyword(p, 2, keyword_struct)){ decl = parse_struct(p, parse_get_token_name(p, 2), DECL_Struct, STRUCT_Nested); } else { parser_push_error(p, token_get(p), "Unexpected token while parsing struct"); break; } if(decl) decl_struct_push(result, decl); } token_expect(p, TK_CloseBrace); return result; } function Decl * parse_variable(Parser *p, Token *name){ Typespec *type = parse_type(p); Expr *expr = parse_expr_assignment(p); return decl_variable(p, name, name->intern_val, type, expr); } function Decl * parse_typedef(Parser *p, Token *name){ Typespec *type = parse_type(p); return decl_typedef(p, name, name->intern_val, type); } function Stmt * parse_stmt(Parser *p); function Stmt * parse_stmt_list(Parser *p){ Token *token = token_expect(p, TK_OpenBrace); Stmt *result = stmt_list(p, token); while(!token_match(p, TK_CloseBrace)) { Stmt *stmt = parse_stmt(p); stmt_push(result, stmt); } return result; } function Stmt * parse_stmt(Parser *p){ Token *token = token_get(p); Decl *decl = parse_decl(p); if(decl){ Stmt *result = stmt_decl(p, token, decl); return result; } else if(token_match_keyword(p, keyword_return)){ Expr *expr = parse_expr(p); Stmt *result = stmt_return(p, token, expr); token_expect(p, TK_Semicolon); return result; } else if(token_match_keyword(p, keyword_if)){ Expr *expr = parse_expr(p); Stmt *if_body = parse_stmt_list(p); Stmt *result = stmt_if(p, token, if_body, expr); Stmt *head = result; while(token_match_keyword(p, keyword_else)){ if(token_match_keyword(p, keyword_if)){ expr = parse_expr(p); if_body = parse_stmt_list(p); head = head->next = stmt_if(p, token, if_body, expr); } else{ if_body = parse_stmt_list(p); head = head->next = stmt_if(p, token, if_body, 0); break; } } return result; } else if((token_is(p, TK_OpenBrace))){ Stmt *result = parse_stmt_list(p); return result; } else{ Expr *expr = parse_expr(p); token_expect(p, TK_Semicolon); return stmt_expr(p, token, expr); } } function Decl * parse_function(Parser *p, Token *name){ Decl *result = decl_function(p, name, name->intern_val, 0); if(!token_is(p, TK_CloseParen)){ for(;;) { if(token_peek_is(p, 1, TK_Colon)){ if(token_peek_is(p, 2, TK_Identifier) || token_peek_is(p, 2, TK_OpenParen)){ Token *name = parse_get_token_name(p,1); Typespec *type = parse_type(p); decl_function_push(p, result, name, name->intern_val, type); } } else if(!token_match(p, TK_Comma)) break; } } token_expect(p, TK_CloseParen); if(token_is(p, TK_Identifier)) result->function_decl.ret = parse_type(p); else result->function_decl.ret = typespec_name(p, token_get(p), intern_void); result->function_decl.body = parse_stmt_list(p); return result; } function Decl * parse_decl(Parser *p){ Decl *result = 0; Note notes = parse_notes(p); if(token_is(p, TK_Identifier)){ if(token_peek_is(p, 1, TK_DoubleColon)){ if(token_peek_is_keyword(p, 2, keyword_struct)){ result = parse_struct(p, parse_get_token_name(p,2), DECL_Struct, STRUCT_Base); } else if(token_peek_is_keyword(p, 2, keyword_union)){ result = parse_struct(p, parse_get_token_name(p,2), DECL_Union, STRUCT_Base); } else if(token_peek_is_keyword(p, 2, keyword_enum)){ result = parse_enum(p, parse_get_token_name(p,2)); } else if(token_peek_is_keyword(p, 2, keyword_typedef)){ result = parse_typedef(p, parse_get_token_name(p,2)); } else if(token_peek_is(p, 2, TK_OpenParen)){ result = parse_function(p, parse_get_token_name(p,2)); } } else if(token_peek_is(p, 1, TK_Colon)){ if(token_peek_is(p, 2, TK_Identifier) || token_peek_is(p, 2, TK_OpenParen)){ result = parse_variable(p, parse_get_token_name(p,1)); token_expect(p, TK_Semicolon); } } } if(result){ decl_pass_notes(result, ¬es); } else if(notes.first != 0){ parser_push_error(p, token_get(p), "Detected notes that are not attached to anything"); } return result; } function Decl * parse(Parser *p){ Decl *result = decl_new(p, DECL_List, token_get(p), (Intern_String){0}); for(;;){ Decl *decl = 0; if(token_is(p, TK_End)) { break; } else if((decl = parse_decl(p))){ // Noop } else token_next(p); if(decl){ decl_list_push(result, decl); } } return result; } function void gen_stmt(Stmt *stmt); function void gen_end(); function void gen_begin(Arena *arena, Parser *p); function void expr_print(Parser *p, Expr *expr); function void parser_test(){ Parser p = {0}; { parser_init(&p); Intern_String a = intern_string(&p, lit("Thing")); Intern_String b = intern_string(&p, lit("Thing")); assert(a.s.str == b.s.str); } String exprs[] = { lit("(534>43?435:42,234,cast(S64)32/*todo cast*/,Thing[10][2],Thing(1,2))"), lit("(4+2*53)"), lit("((4+2)*53)"), lit("++5"), lit("5--"), // @Todo(Krzosa): lit("-5"), lit("(+5)"), lit("sizeof(32) + sizeof(:S32*)"), lit("cast(S64**)5"), lit("cast(S64)5+3"), lit("534>43?435:42"), }; for(S64 i = 0; i < buff_cap(exprs); i++){ parser_lex_stream(&p, exprs[i], lit("File")); Expr *expr = parse_expr(&p); assert(expr); expr_print(&p, expr); lex_print("\n"); } String stmts[] = { lit("Thing :: struct { test: int; } "), lit("thing: S32 = 100; "), lit("thing = thing + 10; "), lit("thing++; "), lit("{ thing_scoped: S32 = 10; thing_scoped += 10; } "), }; for(S64 i = 0; i < buff_cap(stmts); i++){ parser_lex_stream(&p, stmts[i], lit("File")); Stmt *stmt = parse_stmt(&p); assert(stmt); gen_begin(&p.scratch, &p); gen_stmt(stmt); gen_end(); lex_print("\n"); } }