mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-06 07:38:48 +00:00
Add "pure" procedure types
This commit is contained in:
@@ -1961,6 +1961,22 @@ relative_data_types :: proc() {
|
|||||||
fmt.println(rel_slice[1]);
|
fmt.println(rel_slice[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pure_procedures :: proc() {
|
||||||
|
fmt.println("\n#pure procedures");
|
||||||
|
|
||||||
|
square :: proc "pure" (x: int) -> int {
|
||||||
|
return x*x + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
do_math :: proc "pure" (x: int) -> int {
|
||||||
|
// Only "pure" procedure calls are allowed within a "pure" procedure
|
||||||
|
return square(x) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
x := do_math(5);
|
||||||
|
fmt.println("do_math(5) ==", x);
|
||||||
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
when true {
|
when true {
|
||||||
the_basics();
|
the_basics();
|
||||||
@@ -1993,5 +2009,6 @@ main :: proc() {
|
|||||||
union_maybe();
|
union_maybe();
|
||||||
explicit_context_definition();
|
explicit_context_definition();
|
||||||
relative_data_types();
|
relative_data_types();
|
||||||
|
pure_procedures();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -1174,11 +1174,14 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
CheckerContext new_ctx = *ctx_;
|
CheckerContext new_ctx = *ctx_;
|
||||||
CheckerContext *ctx = &new_ctx;
|
CheckerContext *ctx = &new_ctx;
|
||||||
|
|
||||||
|
GB_ASSERT(type->kind == Type_Proc);
|
||||||
|
|
||||||
ctx->scope = decl->scope;
|
ctx->scope = decl->scope;
|
||||||
ctx->decl = decl;
|
ctx->decl = decl;
|
||||||
ctx->proc_name = proc_name;
|
ctx->proc_name = proc_name;
|
||||||
ctx->curr_proc_decl = decl;
|
ctx->curr_proc_decl = decl;
|
||||||
ctx->curr_proc_sig = type;
|
ctx->curr_proc_sig = type;
|
||||||
|
ctx->curr_proc_calling_convention = type->Proc.calling_convention;
|
||||||
|
|
||||||
ast_node(bs, BlockStmt, body);
|
ast_node(bs, BlockStmt, body);
|
||||||
|
|
||||||
@@ -1187,7 +1190,6 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
defer (array_free(&using_entities));
|
defer (array_free(&using_entities));
|
||||||
|
|
||||||
{
|
{
|
||||||
GB_ASSERT(type->kind == Type_Proc);
|
|
||||||
if (type->Proc.param_count > 0) {
|
if (type->Proc.param_count > 0) {
|
||||||
TypeTuple *params = &type->Proc.params->Tuple;
|
TypeTuple *params = &type->Proc.params->Tuple;
|
||||||
for_array(i, params->variables) {
|
for_array(i, params->variables) {
|
||||||
@@ -1242,7 +1244,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
|
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_open_scope(ctx, body);
|
check_open_scope(ctx, body);
|
||||||
{
|
{
|
||||||
for_array(i, using_entities) {
|
for_array(i, using_entities) {
|
||||||
|
|||||||
+32
-14
@@ -1165,6 +1165,11 @@ Entity *check_ident(CheckerContext *c, Operand *o, Ast *n, Type *named_type, Typ
|
|||||||
if (e->flags & EntityFlag_Value) {
|
if (e->flags & EntityFlag_Value) {
|
||||||
o->mode = Addressing_Value;
|
o->mode = Addressing_Value;
|
||||||
}
|
}
|
||||||
|
if (c->curr_proc_calling_convention == ProcCC_Pure) {
|
||||||
|
if (e->scope->flags & (ScopeFlag_Global|ScopeFlag_File|ScopeFlag_Pkg)) {
|
||||||
|
error(n, "Global variables are not allowed within a \"pure\" procedure, got '%.*s'", LIT(e->token.string));
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Entity_Procedure:
|
case Entity_Procedure:
|
||||||
@@ -7434,6 +7439,14 @@ ExprKind check_call_expr(CheckerContext *c, Operand *operand, Ast *call, Ast *pr
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if (c->curr_proc_calling_convention == ProcCC_Pure) {
|
||||||
|
if (pt->kind == Type_Proc && pt->Proc.calling_convention != ProcCC_Pure) {
|
||||||
|
error(call, "Only \"pure\" procedure calls are allowed within a \"pure\" procedure");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (pt->kind == Type_Proc && pt->Proc.calling_convention == ProcCC_Odin) {
|
if (pt->kind == Type_Proc && pt->Proc.calling_convention == ProcCC_Odin) {
|
||||||
init_core_context(c->checker);
|
init_core_context(c->checker);
|
||||||
@@ -7755,23 +7768,28 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
|
|||||||
case_ast_node(i, Implicit, node)
|
case_ast_node(i, Implicit, node)
|
||||||
switch (i->kind) {
|
switch (i->kind) {
|
||||||
case Token_context:
|
case Token_context:
|
||||||
if (c->proc_name.len == 0 && c->curr_proc_sig == nullptr) {
|
{
|
||||||
error(node, "'context' is only allowed within procedures %p", c->curr_proc_decl);
|
if (c->proc_name.len == 0 && c->curr_proc_sig == nullptr) {
|
||||||
return kind;
|
error(node, "'context' is only allowed within procedures %p", c->curr_proc_decl);
|
||||||
}
|
return kind;
|
||||||
|
}
|
||||||
|
if (c->curr_proc_calling_convention == ProcCC_Pure) {
|
||||||
|
error(node, "'context' is not allowed within a \"pure\" procedure");
|
||||||
|
} else {
|
||||||
|
if (unparen_expr(c->assignment_lhs_hint) == node) {
|
||||||
|
c->scope->flags |= ScopeFlag_ContextDefined;
|
||||||
|
}
|
||||||
|
|
||||||
if (unparen_expr(c->assignment_lhs_hint) == node) {
|
if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) {
|
||||||
c->scope->flags |= ScopeFlag_ContextDefined;
|
error(node, "'context' has not been defined within this scope");
|
||||||
}
|
// Continue with value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((c->scope->flags & ScopeFlag_ContextDefined) == 0) {
|
init_core_context(c->checker);
|
||||||
error(node, "'context' has not been defined within this scope");
|
o->mode = Addressing_Context;
|
||||||
// Continue with value
|
o->type = t_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_core_context(c->checker);
|
|
||||||
o->mode = Addressing_Context;
|
|
||||||
o->type = t_context;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1301,6 +1301,11 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
case_end;
|
case_end;
|
||||||
|
|
||||||
case_ast_node(as, AssignStmt, node);
|
case_ast_node(as, AssignStmt, node);
|
||||||
|
if (ctx->curr_proc_calling_convention == ProcCC_Pure) {
|
||||||
|
error(node, "Assignment statements are not allowed within a \"pure\" procedure");
|
||||||
|
// Continue
|
||||||
|
}
|
||||||
|
|
||||||
switch (as->op.kind) {
|
switch (as->op.kind) {
|
||||||
case Token_Eq: {
|
case Token_Eq: {
|
||||||
// a, b, c = 1, 2, 3; // Multisided
|
// a, b, c = 1, 2, 3; // Multisided
|
||||||
@@ -2027,6 +2032,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
|||||||
check_arity_match(ctx, vd);
|
check_arity_match(ctx, vd);
|
||||||
check_init_variables(ctx, entities, entity_count, vd->values, str_lit("variable declaration"));
|
check_init_variables(ctx, entities, entity_count, vd->values, str_lit("variable declaration"));
|
||||||
|
|
||||||
|
if (ctx->curr_proc_calling_convention == ProcCC_Pure) {
|
||||||
|
if (vd->values.count == 0) {
|
||||||
|
error(node, "Variable declarations without assignment are not allowed within \"pure\" procedures");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (isize i = 0; i < entity_count; i++) {
|
for (isize i = 0; i < entity_count; i++) {
|
||||||
Entity *e = entities[i];
|
Entity *e = entities[i];
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -2452,6 +2452,7 @@ void set_procedure_abi_types(gbAllocator allocator, Type *type) {
|
|||||||
switch (type->Proc.calling_convention) {
|
switch (type->Proc.calling_convention) {
|
||||||
case ProcCC_Odin:
|
case ProcCC_Odin:
|
||||||
case ProcCC_Contextless:
|
case ProcCC_Contextless:
|
||||||
|
case ProcCC_Pure:
|
||||||
if (is_type_pointer(new_type) & !is_type_pointer(e->type)) {
|
if (is_type_pointer(new_type) & !is_type_pointer(e->type)) {
|
||||||
e->flags |= EntityFlag_ImplicitReference;
|
e->flags |= EntityFlag_ImplicitReference;
|
||||||
}
|
}
|
||||||
@@ -2548,7 +2549,9 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
|||||||
type->Proc.has_named_results = first->token.string != "";
|
type->Proc.has_named_results = first->token.string != "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result_count == 0 && cc == ProcCC_Pure) {
|
||||||
|
error(proc_type_node, "\"pure\" procedures must have at least 1 return value");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool optional_ok = (pt->tags & ProcTag_optional_ok) != 0;
|
bool optional_ok = (pt->tags & ProcTag_optional_ok) != 0;
|
||||||
|
|||||||
@@ -297,6 +297,7 @@ struct CheckerContext {
|
|||||||
String proc_name;
|
String proc_name;
|
||||||
DeclInfo * curr_proc_decl;
|
DeclInfo * curr_proc_decl;
|
||||||
Type * curr_proc_sig;
|
Type * curr_proc_sig;
|
||||||
|
ProcCallingConvention curr_proc_calling_convention;
|
||||||
bool in_proc_sig;
|
bool in_proc_sig;
|
||||||
ForeignContext foreign_context;
|
ForeignContext foreign_context;
|
||||||
gbAllocator allocator;
|
gbAllocator allocator;
|
||||||
|
|||||||
@@ -1434,6 +1434,7 @@ void ir_print_calling_convention(irFileBuffer *f, irModule *m, ProcCallingConven
|
|||||||
switch (cc) {
|
switch (cc) {
|
||||||
case ProcCC_Odin: ir_write_str_lit(f, ""); break;
|
case ProcCC_Odin: ir_write_str_lit(f, ""); break;
|
||||||
case ProcCC_Contextless: ir_write_str_lit(f, ""); break;
|
case ProcCC_Contextless: ir_write_str_lit(f, ""); break;
|
||||||
|
case ProcCC_Pure: ir_write_str_lit(f, ""); break;
|
||||||
// case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
|
// case ProcCC_CDecl: ir_write_str_lit(f, "ccc "); break;
|
||||||
case ProcCC_CDecl: ir_write_str_lit(f, ""); break;
|
case ProcCC_CDecl: ir_write_str_lit(f, ""); break;
|
||||||
case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break;
|
case ProcCC_StdCall: ir_write_str_lit(f, "cc 64 "); break;
|
||||||
|
|||||||
@@ -2987,6 +2987,7 @@ Ast *parse_results(AstFile *f, bool *diverging) {
|
|||||||
ProcCallingConvention string_to_calling_convention(String s) {
|
ProcCallingConvention string_to_calling_convention(String s) {
|
||||||
if (s == "odin") return ProcCC_Odin;
|
if (s == "odin") return ProcCC_Odin;
|
||||||
if (s == "contextless") return ProcCC_Contextless;
|
if (s == "contextless") return ProcCC_Contextless;
|
||||||
|
if (s == "pure") return ProcCC_Pure;
|
||||||
if (s == "cdecl") return ProcCC_CDecl;
|
if (s == "cdecl") return ProcCC_CDecl;
|
||||||
if (s == "c") return ProcCC_CDecl;
|
if (s == "c") return ProcCC_CDecl;
|
||||||
if (s == "stdcall") return ProcCC_StdCall;
|
if (s == "stdcall") return ProcCC_StdCall;
|
||||||
|
|||||||
@@ -176,6 +176,7 @@ enum ProcCallingConvention {
|
|||||||
ProcCC_Invalid = 0,
|
ProcCC_Invalid = 0,
|
||||||
ProcCC_Odin,
|
ProcCC_Odin,
|
||||||
ProcCC_Contextless,
|
ProcCC_Contextless,
|
||||||
|
ProcCC_Pure,
|
||||||
ProcCC_CDecl,
|
ProcCC_CDecl,
|
||||||
ProcCC_StdCall,
|
ProcCC_StdCall,
|
||||||
ProcCC_FastCall,
|
ProcCC_FastCall,
|
||||||
|
|||||||
Reference in New Issue
Block a user