#include global_variable constexpr u8 left_bracket = '['; global_variable constexpr u8 right_bracket = ']'; global_variable constexpr u8 left_brace = '{'; global_variable constexpr u8 right_brace = '}'; global_variable constexpr u8 left_parenthesis = '('; global_variable constexpr u8 right_parenthesis = ')'; fn bool is_space(u8 ch) { return ((ch == ' ') | (ch == '\n')) | ((ch == '\t') | (ch == '\r')); } fn bool is_lower(u8 ch) { return ((ch >= 'a') & (ch <= 'z')); } fn bool is_upper(u8 ch) { return ((ch >= 'A') & (ch <= 'Z')); } fn bool is_decimal(u8 ch) { return ((ch >= '0') & (ch <= '9')); } fn bool is_identifier_start(u8 ch) { return (is_lower(ch) | is_upper(ch)) | (ch == '_'); } fn bool is_identifier(u8 ch) { return is_identifier_start(ch) | is_decimal(ch); } fn u32 get_line(Module& module) { auto line = module.line_offset + 1; assert(line < ~(u32)0); return (u32)line; } fn u32 get_column(Module& module) { auto column = module.offset - module.line_character_offset + 1; assert(column < ~(u32)0); return (u32)column; } fn bool consume_character_if_match(Module& module, u8 expected_ch) { bool is_ch = false; auto i = module.offset; if (i < module.content.length) { auto ch = module.content[i]; is_ch = expected_ch == ch; module.offset = i + 1; } return is_ch; } fn void expect_character(Module& module, u8 expected_ch) { if (!consume_character_if_match(module, expected_ch)) { report_error(); } } fn void skip_space(Module& module) { while (1) { auto iteration_offset = module.offset; while (module.offset < module.content.length) { auto ch = module.content[module.offset]; if (!is_space(ch)) { break; } module.line_offset += ch == '\n'; module.line_character_offset = ch == '\n' ? module.offset : module.line_character_offset; module.offset += 1; } if (module.offset + 1 < module.content.length) { auto i = module.offset; auto first_ch = module.content[i]; auto second_ch = module.content[i + 1]; auto is_comment = first_ch == '/' && second_ch == '/'; if (is_comment) { while (module.offset < module.content.length) { auto ch = module.content[module.offset]; if (ch == '\n') { break; } module.offset += 1; } if (module.offset < module.content.length) { module.line_offset += 1; module.line_character_offset = module.offset; module.offset += 1; } } } if (module.offset - iteration_offset == 0) { break; } } } fn String parse_identifier(Module& module) { auto start = module.offset; if (is_identifier_start(module.content[start])) { module.offset = start + 1; while (module.offset < module.content.length) { auto i = module.offset; if (is_identifier(module.content[i])) { module.offset = i + 1; } else { break; } } } auto end = module.offset; if (end - start == 0) { report_error(); } return module.content(start, end); } fn Type* parse_type(Module& module) { trap_raw(); } void parse(Module& module) { while (1) { skip_space(module); if (module.offset == module.content.length) { break; } bool is_export = false; bool is_extern = false; auto global_line = get_line(module); auto global_column = get_column(module); if (consume_character_if_match(module, left_bracket)) { while (module.offset < module.content.length) { auto global_keyword_string = parse_identifier(module); String global_keyword_strings[] = { str("export"), str("extern"), }; enum class GlobalKeyword { export_keyword, extern_keyword, }; u32 i; for (i = 0; i < array_length(global_keyword_strings); i += 1) { String keyword = global_keyword_strings[i]; if (keyword.equal(global_keyword_string)) { break; } } if (i == array_length(global_keyword_strings)) { report_error(); } auto global_keyword = (GlobalKeyword)i; switch (global_keyword) { case GlobalKeyword::export_keyword: { is_export = true; } break; case GlobalKeyword::extern_keyword: { is_extern = true; } break; } if (consume_character_if_match(module, right_bracket)) { break; } else { report_error(); } } skip_space(module); } auto global_name = parse_identifier(module); Global* last_global = module.first_global; while (last_global) { if (global_name.equal(last_global->variable.name)) { report_error(); } if (!last_global->next) { break; } last_global = last_global->next; } Type* type_it = module.first_type; Type* forward_declaration = 0; while (type_it) { if (global_name.equal(type_it->name)) { if (type_it->id == TypeId::forward_declaration) { forward_declaration = type_it; break; } else { report_error(); } } if (!type_it->next) { break; } type_it = type_it->next; } Type* global_type = 0; if (consume_character_if_match(module, ':')) { skip_space(module); global_type = parse_type(module); skip_space(module); } trap_raw(); } }