mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Added $include.
This commit is contained in:
@@ -97,6 +97,7 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type, V
|
||||
case DECL_INITIALIZE:
|
||||
case DECL_FINALIZE:
|
||||
case DECL_CT_ECHO:
|
||||
case DECL_CT_INCLUDE:
|
||||
UNREACHABLE
|
||||
}
|
||||
Type *type = type_new(kind, name ? name : "$anon");
|
||||
@@ -172,6 +173,8 @@ const char *decl_to_a_name(Decl *decl)
|
||||
return "a static initializer";
|
||||
case DECL_FINALIZE:
|
||||
return "a static finalizer";
|
||||
case DECL_CT_INCLUDE:
|
||||
return "an include";
|
||||
case DECL_VAR:
|
||||
switch (decl->var.kind)
|
||||
{
|
||||
|
||||
@@ -76,7 +76,9 @@ static void compiler_lex(void)
|
||||
VECEACH(global_context.sources, i)
|
||||
{
|
||||
bool loaded = false;
|
||||
File *file = source_file_load(global_context.sources[i], &loaded);
|
||||
const char *error;
|
||||
File *file = source_file_load(global_context.sources[i], &loaded, &error);
|
||||
if (!file) error_exit(error);
|
||||
if (loaded) continue;
|
||||
Lexer lexer = { .file = file };
|
||||
lexer_init(&lexer);
|
||||
@@ -97,7 +99,9 @@ void compiler_parse(void)
|
||||
VECEACH(global_context.sources, i)
|
||||
{
|
||||
bool loaded = false;
|
||||
File *file = source_file_load(global_context.sources[i], &loaded);
|
||||
const char *error;
|
||||
File *file = source_file_load(global_context.sources[i], &loaded, &error);
|
||||
if (!file) error_exit(error);
|
||||
if (loaded) continue;
|
||||
|
||||
global_context_clear_errors();
|
||||
|
||||
@@ -393,6 +393,12 @@ typedef struct
|
||||
Module *module;
|
||||
} ImportDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
File *file;
|
||||
Decl **decls;
|
||||
} IncludeDecl;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
TypeSize size;
|
||||
@@ -696,6 +702,7 @@ typedef struct Decl_
|
||||
BitStructDecl bitstruct;
|
||||
};
|
||||
};
|
||||
IncludeDecl include;
|
||||
Decl** body_params;
|
||||
ImportDecl import;
|
||||
VarDecl var;
|
||||
@@ -2231,7 +2238,7 @@ void sema_shadow_error(Decl *decl, Decl *old);
|
||||
bool sema_type_error_on_binop(Expr *expr);
|
||||
|
||||
File *source_file_by_id(FileId file);
|
||||
File *source_file_load(const char *filename, bool *already_loaded);
|
||||
File *source_file_load(const char *filename, bool *already_loaded, const char **error);
|
||||
|
||||
|
||||
#define RANGE_EXTEND_PREV(x) do { (x)->span = extend_span_with_token((x)->span, c->prev_span); } while (0)
|
||||
|
||||
@@ -148,6 +148,7 @@ void decl_register(Decl *decl)
|
||||
case DECL_LABEL:
|
||||
case DECL_DECLARRAY:
|
||||
case DECL_BODYPARAM:
|
||||
case DECL_CT_INCLUDE:
|
||||
UNREACHABLE
|
||||
case DECL_ATTRIBUTE:
|
||||
case DECL_BITSTRUCT:
|
||||
@@ -262,6 +263,7 @@ void unit_register_global_decl(CompilationUnit *unit, Decl *decl)
|
||||
UNREACHABLE
|
||||
case DECL_CT_IF:
|
||||
case DECL_CT_SWITCH:
|
||||
case DECL_CT_INCLUDE:
|
||||
vec_add(unit->ct_ifs, decl);
|
||||
return;
|
||||
case DECL_CT_ECHO:
|
||||
|
||||
@@ -784,6 +784,8 @@ Decl *copy_decl(CopyStruct *c, Decl *decl)
|
||||
{
|
||||
case DECL_POISONED:
|
||||
break;
|
||||
case DECL_CT_INCLUDE:
|
||||
break;
|
||||
case DECL_INITIALIZE:
|
||||
case DECL_FINALIZE:
|
||||
MACRO_COPY_ASTID(copy->xxlizer.init);
|
||||
|
||||
@@ -157,6 +157,7 @@ typedef enum
|
||||
DECL_FINALIZE,
|
||||
DECL_GENERIC,
|
||||
DECL_IMPORT,
|
||||
DECL_CT_INCLUDE,
|
||||
DECL_LABEL,
|
||||
DECL_MACRO,
|
||||
DECL_STRUCT,
|
||||
@@ -171,7 +172,7 @@ typedef enum
|
||||
case DECL_DECLARRAY: case DECL_CT_IF: case DECL_CT_ELSE: case DECL_CT_ELIF: \
|
||||
case DECL_CT_SWITCH: case DECL_CT_CASE: case DECL_ATTRIBUTE: case DECL_LABEL: \
|
||||
case DECL_DEFINE: case DECL_CT_ASSERT: case DECL_GENERIC: case DECL_INITIALIZE: \
|
||||
case DECL_FINALIZE: case DECL_CT_ECHO
|
||||
case DECL_FINALIZE: case DECL_CT_ECHO: case DECL_CT_INCLUDE
|
||||
|
||||
#define NON_RUNTIME_EXPR EXPR_DESIGNATOR: case EXPR_POISONED: \
|
||||
case EXPR_TYPEINFO: case EXPR_CT_IDENT: case EXPR_HASH_IDENT: \
|
||||
|
||||
@@ -1000,6 +1000,7 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
|
||||
case DECL_FINALIZE:
|
||||
case DECL_BODYPARAM:
|
||||
case DECL_CT_ECHO:
|
||||
case DECL_CT_INCLUDE:
|
||||
UNREACHABLE;
|
||||
}
|
||||
UNREACHABLE
|
||||
|
||||
@@ -6,6 +6,7 @@ static Decl *parse_const_declaration(ParseContext *c, Visibility visibility);
|
||||
static inline Decl *parse_func_definition(ParseContext *c, Visibility visibility, AstId docs, bool is_interface);
|
||||
static inline bool parse_bitstruct_body(ParseContext *c, Decl *decl);
|
||||
static inline Decl *parse_static_top_level(ParseContext *c);
|
||||
static Decl *parse_include(ParseContext *c);
|
||||
|
||||
#define DECL_VAR_NEW(type__, var__, visible__) decl_new_var(symstr(c), c->span, type__, var__, visible__);
|
||||
|
||||
@@ -2531,6 +2532,68 @@ static bool parse_docs(ParseContext *c, AstId *docs_ref)
|
||||
}
|
||||
}
|
||||
|
||||
static Decl *parse_include(ParseContext *c)
|
||||
{
|
||||
SourceSpan loc = c->span;
|
||||
Decl *decl = decl_new(DECL_CT_INCLUDE, NULL, loc, VISIBLE_LOCAL);
|
||||
advance_and_verify(c, TOKEN_CT_INCLUDE);
|
||||
CONSUME_OR_RET(TOKEN_LPAREN, poisoned_decl);
|
||||
const char *str = symstr(c);
|
||||
CONSUME_OR_RET(TOKEN_STRING, poisoned_decl);
|
||||
CONSUME_OR_RET(TOKEN_RPAREN, poisoned_decl);
|
||||
CONSUME_EOS_OR_RET(poisoned_decl);
|
||||
bool loaded;
|
||||
const char *error;
|
||||
char *path;
|
||||
char *name;
|
||||
if (file_namesplit(c->unit->file->full_path, &name, &path))
|
||||
{
|
||||
str = file_append_path(path, str);
|
||||
}
|
||||
File *file = source_file_load(str, &loaded, &error);
|
||||
if (!file)
|
||||
{
|
||||
sema_error_at(loc, "Failed to load file %s: %s", str, error);
|
||||
return poisoned_decl;
|
||||
}
|
||||
decl->include.file = file;
|
||||
if (global_context.errors_found) return poisoned_decl;
|
||||
|
||||
Lexer current_lexer = c->lexer;
|
||||
File *current_file = c->unit->file;
|
||||
TokenType old_tok = c->tok;
|
||||
TokenData old_data = c->data;
|
||||
SourceSpan old_prev = c->prev_span;
|
||||
SourceSpan old_span = c->span;
|
||||
|
||||
c->lexer = (Lexer){ .file = decl->include.file, .context = c };
|
||||
lexer_init(&c->lexer);
|
||||
// Prime everything
|
||||
advance(c);
|
||||
advance(c);
|
||||
Decl **list = NULL;
|
||||
while (!tok_is(c, TOKEN_EOF))
|
||||
{
|
||||
Decl *inner = parse_top_level_statement(c, &c);
|
||||
if (!decl) continue;
|
||||
if (!decl_ok(decl))
|
||||
{
|
||||
decl_poison(decl);
|
||||
goto END;
|
||||
}
|
||||
vec_add(list, inner);
|
||||
}
|
||||
decl->include.decls = list;
|
||||
END:
|
||||
c->lexer = current_lexer;
|
||||
c->tok = old_tok;
|
||||
c->data = old_data;
|
||||
c->prev_span = old_prev;
|
||||
c->span = old_span;
|
||||
c->unit->file = current_file;
|
||||
return decl;
|
||||
}
|
||||
|
||||
/**
|
||||
* top_level_statement ::= visibility? top_level
|
||||
*
|
||||
@@ -2690,6 +2753,15 @@ Decl *parse_top_level_statement(ParseContext *c, ParseContext **c_ref)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TOKEN_CT_INCLUDE:
|
||||
if (!check_no_visibility_before(c, visibility)) return poisoned_decl;
|
||||
if (docs)
|
||||
{
|
||||
SEMA_ERROR(astptr(docs), "Unexpected doc comment before $include, did you mean to use a regular comment?");
|
||||
return poisoned_decl;
|
||||
}
|
||||
ASSIGN_DECL_OR_RET(decl, parse_include(c), poisoned_decl);
|
||||
break;
|
||||
case TOKEN_BITSTRUCT:
|
||||
{
|
||||
ASSIGN_DECL_OR_RET(decl, parse_bitstruct_declaration(c, visibility), poisoned_decl);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "compiler_internal.h"
|
||||
#include "parser_internal.h"
|
||||
|
||||
|
||||
// --- Parser base methods
|
||||
|
||||
/**
|
||||
@@ -55,6 +56,8 @@ bool consume(ParseContext *c, TokenType type, const char *message, ...)
|
||||
|
||||
// --- Extern functions
|
||||
|
||||
static bool parse_include(ParseContext *c, Decl *decl);
|
||||
|
||||
/**
|
||||
* module? imports top_level_statement*
|
||||
* @param c
|
||||
@@ -79,6 +82,7 @@ static inline void parse_translation_unit(ParseContext *c)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a file, generating a default context for it.
|
||||
* More contexts may be created on demand during parsing.
|
||||
|
||||
@@ -2901,6 +2901,7 @@ bool sema_analyse_decl(SemaContext *context, Decl *decl)
|
||||
case DECL_FAULTVALUE:
|
||||
case DECL_DECLARRAY:
|
||||
case DECL_BODYPARAM:
|
||||
case DECL_CT_INCLUDE:
|
||||
UNREACHABLE
|
||||
}
|
||||
decl->resolve_status = RESOLVE_DONE;
|
||||
|
||||
@@ -547,6 +547,7 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr)
|
||||
case DECL_BODYPARAM:
|
||||
case DECL_INITIALIZE:
|
||||
case DECL_FINALIZE:
|
||||
case DECL_CT_INCLUDE:
|
||||
UNREACHABLE
|
||||
case DECL_POISONED:
|
||||
return expr_poison(expr);
|
||||
|
||||
@@ -182,6 +182,7 @@ static inline bool sema_analyse_top_level_if(SemaContext *context, Decl *ct_if)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static inline bool sema_analyse_top_level_switch(SemaContext *context, Decl *ct_switch)
|
||||
{
|
||||
Expr *cond = ct_switch->ct_switch_decl.expr;
|
||||
@@ -303,6 +304,10 @@ void sema_analysis_pass_conditional_compilation(Module *module)
|
||||
case DECL_CT_SWITCH:
|
||||
success = sema_analyse_top_level_switch(&context, decl);
|
||||
break;
|
||||
case DECL_CT_INCLUDE:
|
||||
sema_append_decls(context.unit, decl->include.decls);
|
||||
success = true;
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE
|
||||
}
|
||||
|
||||
@@ -243,6 +243,7 @@ static bool sema_resolve_type_identifier(SemaContext *context, TypeInfo *type_in
|
||||
case DECL_CT_ECHO:
|
||||
case DECL_DECLARRAY:
|
||||
case DECL_BODYPARAM:
|
||||
case DECL_CT_INCLUDE:
|
||||
UNREACHABLE
|
||||
}
|
||||
UNREACHABLE
|
||||
|
||||
@@ -182,6 +182,7 @@ static void register_generic_decls(CompilationUnit *unit, Decl **decls)
|
||||
case DECL_CT_ELIF:
|
||||
case DECL_CT_ELSE:
|
||||
case DECL_BODYPARAM:
|
||||
case DECL_CT_INCLUDE:
|
||||
UNREACHABLE
|
||||
case DECL_MACRO:
|
||||
case DECL_DEFINE:
|
||||
@@ -242,7 +243,9 @@ void sema_analysis_run(void)
|
||||
VECEACH(global_context.sources, i)
|
||||
{
|
||||
bool loaded = false;
|
||||
File *file = source_file_load(global_context.sources[i], &loaded);
|
||||
const char *error;
|
||||
File *file = source_file_load(global_context.sources[i], &loaded, &error);
|
||||
if (!file) error_exit(error);
|
||||
if (loaded) continue;
|
||||
if (!parse_file(file)) has_error = true;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ File *source_file_by_id(FileId file)
|
||||
return global_context.loaded_sources[file];
|
||||
}
|
||||
|
||||
File *source_file_load(const char *filename, bool *already_loaded)
|
||||
File *source_file_load(const char *filename, bool *already_loaded, const char **error)
|
||||
{
|
||||
if (already_loaded) *already_loaded = false;
|
||||
if (!global_context.loaded_sources) global_context.loaded_sources = VECNEW(File*, LEXER_FILES_START_CAPACITY);
|
||||
@@ -31,7 +31,8 @@ File *source_file_load(const char *filename, bool *already_loaded)
|
||||
|
||||
if (!realpath(filename, full_path))
|
||||
{
|
||||
error_exit("Failed to resolve %s", filename);
|
||||
*error = str_printf("Failed to resolve %s", filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VECEACH(global_context.loaded_sources, index)
|
||||
@@ -44,7 +45,8 @@ File *source_file_load(const char *filename, bool *already_loaded)
|
||||
}
|
||||
if (vec_size(global_context.loaded_sources) == MAX_FILES)
|
||||
{
|
||||
error_exit("Exceeded max number of files %d", MAX_FILES);
|
||||
*error = str_printf("Exceeded max number of files %d", MAX_FILES);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t size;
|
||||
|
||||
@@ -1 +1 @@
|
||||
#define COMPILER_VERSION "0.3.127"
|
||||
#define COMPILER_VERSION "0.3.128"
|
||||
Reference in New Issue
Block a user