Implement 'extern' functionality
This commit is contained in:
parent
a29d2ed6d1
commit
5157988efa
2
ast.h
2
ast.h
@ -194,7 +194,6 @@ struct ast_s {
|
||||
struct {
|
||||
ast_t *fn;
|
||||
arg_ast_t *args;
|
||||
type_ast_t *extern_return_type;
|
||||
} FunctionCall;
|
||||
struct {
|
||||
const char *name;
|
||||
@ -231,7 +230,6 @@ struct ast_s {
|
||||
struct {
|
||||
const char *name;
|
||||
type_ast_t *type;
|
||||
bool address;
|
||||
} Extern;
|
||||
struct {
|
||||
const char *name;
|
||||
|
20
compile.c
20
compile.c
@ -58,7 +58,6 @@ static bool promote(env_t *env, CORD *code, type_t *actual, type_t *needed)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
CORD compile_declaration(env_t *env, type_t *t, const char *name)
|
||||
{
|
||||
if (t->tag == FunctionType) {
|
||||
@ -735,6 +734,25 @@ CORD compile_statement(env_t *env, ast_t *ast)
|
||||
return compile_statement(env, loop);
|
||||
}
|
||||
}
|
||||
case Extern: {
|
||||
auto ext = Match(ast, Extern);
|
||||
type_t *t = parse_type_ast(env, ext->type);
|
||||
CORD decl;
|
||||
if (t->tag == ClosureType) {
|
||||
t = Match(t, ClosureType)->fn;
|
||||
auto fn = Match(t, FunctionType);
|
||||
decl = CORD_all(compile_type(env, fn->ret), " ", ext->name, "(");
|
||||
for (arg_t *arg = fn->args; arg; arg = arg->next) {
|
||||
decl = CORD_all(decl, compile_type(env, arg->type));
|
||||
if (arg->next) decl = CORD_cat(decl, ", ");
|
||||
}
|
||||
decl = CORD_cat(decl, ")");
|
||||
} else {
|
||||
decl = compile_declaration(env, t, ext->name);
|
||||
}
|
||||
env->code->fndefs = CORD_all(env->code->fndefs, "extern ", decl, ";\n");
|
||||
return CORD_EMPTY;
|
||||
}
|
||||
case InlineCCode: return Match(ast, InlineCCode)->code;
|
||||
default:
|
||||
return CORD_asprintf("(void)%r;", compile(env, ast));
|
||||
|
28
parse.c
28
parse.c
@ -65,7 +65,7 @@ static inline const char* get_id(const char **pos);
|
||||
static inline bool comment(const char **pos);
|
||||
static inline bool indent(parse_ctx_t *ctx, const char **pos);
|
||||
static inline binop_e match_binary_operator(const char **pos);
|
||||
static ast_t *parse_fncall_suffix(parse_ctx_t *ctx, ast_t *fn, bool is_extern);
|
||||
static ast_t *parse_fncall_suffix(parse_ctx_t *ctx, ast_t *fn);
|
||||
static ast_t *parse_method_call_suffix(parse_ctx_t *ctx, ast_t *self);
|
||||
static ast_t *parse_field_suffix(parse_ctx_t *ctx, ast_t *lhs);
|
||||
static ast_t *parse_index_suffix(parse_ctx_t *ctx, ast_t *lhs);
|
||||
@ -753,7 +753,7 @@ PARSER(parse_reduction) {
|
||||
|| (new_term=parse_index_suffix(ctx, key))
|
||||
|| (new_term=parse_field_suffix(ctx, key))
|
||||
|| (new_term=parse_method_call_suffix(ctx, key))
|
||||
|| (new_term=parse_fncall_suffix(ctx, key, NORMAL_FUNCTION))
|
||||
|| (new_term=parse_fncall_suffix(ctx, key))
|
||||
);
|
||||
if (progress) key = new_term;
|
||||
}
|
||||
@ -1211,7 +1211,7 @@ PARSER(parse_term) {
|
||||
|| (new_term=parse_index_suffix(ctx, term))
|
||||
|| (new_term=parse_field_suffix(ctx, term))
|
||||
|| (new_term=parse_method_call_suffix(ctx, term))
|
||||
|| (new_term=parse_fncall_suffix(ctx, term, NORMAL_FUNCTION))
|
||||
|| (new_term=parse_fncall_suffix(ctx, term))
|
||||
);
|
||||
if (progress) term = new_term;
|
||||
}
|
||||
@ -1260,7 +1260,7 @@ ast_t *parse_method_call_suffix(parse_ctx_t *ctx, ast_t *self) {
|
||||
return NewAST(ctx->file, start, pos, MethodCall, .self=self, .name=fn, .args=args);
|
||||
}
|
||||
|
||||
ast_t *parse_fncall_suffix(parse_ctx_t *ctx, ast_t *fn, bool is_extern) {
|
||||
ast_t *parse_fncall_suffix(parse_ctx_t *ctx, ast_t *fn) {
|
||||
if (!fn) return NULL;
|
||||
|
||||
const char *start = fn->start;
|
||||
@ -1296,15 +1296,8 @@ ast_t *parse_fncall_suffix(parse_ctx_t *ctx, ast_t *fn, bool is_extern) {
|
||||
if (!match(&pos, ")"))
|
||||
parser_err(ctx, start, pos, "This parenthesis is unclosed");
|
||||
|
||||
type_ast_t *extern_return_type = NULL;
|
||||
if (is_extern) {
|
||||
if (match(&pos, ":"))
|
||||
extern_return_type = expect(ctx, start, &pos, parse_type, "I couldn't parse the return type of this external function call");
|
||||
else
|
||||
extern_return_type = NewTypeAST(ctx->file, pos, pos, VarTypeAST, .name="Void");
|
||||
}
|
||||
REVERSE_LIST(args);
|
||||
return NewAST(ctx->file, start, pos, FunctionCall, .fn=fn, .args=args, .extern_return_type=extern_return_type);
|
||||
return NewAST(ctx->file, start, pos, FunctionCall, .fn=fn, .args=args);
|
||||
}
|
||||
|
||||
binop_e match_binary_operator(const char **pos)
|
||||
@ -1355,7 +1348,7 @@ static ast_t *parse_infix_expr(parse_ctx_t *ctx, const char *pos, int min_tightn
|
||||
|| (new_term=parse_index_suffix(ctx, key))
|
||||
|| (new_term=parse_field_suffix(ctx, key))
|
||||
|| (new_term=parse_method_call_suffix(ctx, key))
|
||||
|| (new_term=parse_fncall_suffix(ctx, key, NORMAL_FUNCTION))
|
||||
|| (new_term=parse_fncall_suffix(ctx, key))
|
||||
);
|
||||
if (progress) key = new_term;
|
||||
}
|
||||
@ -1469,7 +1462,7 @@ PARSER(parse_statement) {
|
||||
if (stmt->tag == Var)
|
||||
progress = (false
|
||||
|| (new_stmt=parse_method_call_suffix(ctx, stmt))
|
||||
|| (new_stmt=parse_fncall_suffix(ctx, stmt, NORMAL_FUNCTION))
|
||||
|| (new_stmt=parse_fncall_suffix(ctx, stmt))
|
||||
);
|
||||
|
||||
if (progress) stmt = new_stmt;
|
||||
@ -1828,17 +1821,12 @@ PARSER(parse_extern) {
|
||||
const char *start = pos;
|
||||
if (!match_word(&pos, "extern")) return NULL;
|
||||
spaces(&pos);
|
||||
bool address = (match(&pos, "&") != 0);
|
||||
const char* name = get_id(&pos);
|
||||
spaces(&pos);
|
||||
// extern function call:
|
||||
if (match(&pos, "(")) {
|
||||
return parse_fncall_suffix(ctx, NewAST(ctx->file, start, pos-1, Var, .name=name), EXTERN_FUNCTION);
|
||||
}
|
||||
if (!match(&pos, ":"))
|
||||
parser_err(ctx, start, pos, "I couldn't get a type for this extern");
|
||||
type_ast_t *type = expect(ctx, start, &pos, parse_type, "I couldn't parse the type for this extern");
|
||||
return NewAST(ctx->file, start, pos, Extern, .name=name, .type=type, .address=address);
|
||||
return NewAST(ctx->file, start, pos, Extern, .name=name, .type=type);
|
||||
}
|
||||
|
||||
PARSER(parse_doctest) {
|
||||
|
3
test/extern.tm
Normal file
3
test/extern.tm
Normal file
@ -0,0 +1,3 @@
|
||||
extern CORD_cat:func(a:Text, b:Text)->Text
|
||||
>> CORD_cat("hello ", "world")
|
||||
= "hello world"
|
13
typecheck.c
13
typecheck.c
@ -233,6 +233,14 @@ void bind_statement(env_t *env, ast_t *statement)
|
||||
Table_str_set(env->imports, name, module_env);
|
||||
break;
|
||||
}
|
||||
case Extern: {
|
||||
auto ext = Match(statement, Extern);
|
||||
type_t *t = parse_type_ast(env, ext->type);
|
||||
if (t->tag == ClosureType)
|
||||
t = Match(t, ClosureType)->fn;
|
||||
set_binding(env, ext->name, new(binding_t, .type=t, .code=ext->name));
|
||||
break;
|
||||
}
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
@ -471,8 +479,6 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
}
|
||||
case FunctionCall: {
|
||||
auto call = Match(ast, FunctionCall);
|
||||
if (call->extern_return_type)
|
||||
return parse_type_ast(env, call->extern_return_type);
|
||||
type_t *fn_type_t = get_type(env, call->fn);
|
||||
if (!fn_type_t)
|
||||
code_err(call->fn, "I couldn't find this function");
|
||||
@ -547,8 +553,7 @@ type_t *get_type(env_t *env, ast_t *ast)
|
||||
return get_type(block_env, last->ast);
|
||||
}
|
||||
case Extern: {
|
||||
type_t *t = parse_type_ast(env, Match(ast, Extern)->type);
|
||||
return Match(ast, Extern)->address ? Type(PointerType, .pointed=t, .is_optional=false) : t;
|
||||
return parse_type_ast(env, Match(ast, Extern)->type);
|
||||
}
|
||||
case Declare: case Assign: case DocTest: case LinkerDirective: {
|
||||
return Type(VoidType);
|
||||
|
Loading…
Reference in New Issue
Block a user