231 lines
5.9 KiB
C
231 lines
5.9 KiB
C
#include <common/fzl_builtins.h>
|
|
#include <common/fzl_extern.h>
|
|
#include <common/fzl_opcodes.h>
|
|
#include <common/fzl_types.h>
|
|
#include <compiler/fzl_parser.h>
|
|
#include <compiler/internals/gen.h>
|
|
#include <stdbool.h>
|
|
#include <stddef.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
// Call definition
|
|
// NOTE: split by call type (builtin/declared/extern)
|
|
gen_res_t gen_call(fzl_gen_t *gen, fzl_node_t *node)
|
|
{
|
|
if (!gen || !node)
|
|
return gen_error;
|
|
|
|
// `printline(x)` builtin function
|
|
if (strcmp(node->token->value, "printline") == 0)
|
|
{
|
|
if (node->call.args_count > 0)
|
|
for (size_t i = 0; i < node->call.args_count; i++)
|
|
if (gen_common(gen, node->call.args[i]).error)
|
|
return gen_error;
|
|
|
|
gen_op(gen, FZL_OPCODE_CALL_BUILTIN);
|
|
gen_word(gen, FZL_BUILTIN_PRINTLINE);
|
|
if (node->call.args_count < 1)
|
|
return gen_error;
|
|
|
|
return gen_ok_null;
|
|
}
|
|
|
|
// `exit(x?)` builtin function
|
|
if (strcmp(node->token->value, "exit") == 0)
|
|
{
|
|
if (node->call.args_count > 0)
|
|
{
|
|
for (size_t i = 0; i < node->call.args_count; i++)
|
|
if (gen_common(gen, node->call.args[i]).error)
|
|
return gen_error;
|
|
|
|
gen_op(gen, FZL_OPCODE_CALL_BUILTIN);
|
|
gen_word(gen, FZL_BUILTIN_EXIT);
|
|
if (node->call.args_count < 1)
|
|
return gen_error;
|
|
}
|
|
|
|
return gen_ok_null;
|
|
}
|
|
|
|
if (node->call.callee->type == FZL_NODETYPE_IDENTIFIER)
|
|
{
|
|
if (node->call.args_count > 0)
|
|
for (size_t i = 0; i < node->call.args_count; i++)
|
|
if (gen_common(gen, node->call.args[i]).error)
|
|
return gen_error;
|
|
|
|
char *name = (char *)node->token->value;
|
|
fzl_sym_t sym;
|
|
bool found = gen_resolve_name(gen, name, &sym);
|
|
if (!found)
|
|
return gen_error;
|
|
|
|
if (sym.node->type == FZL_NODETYPE_EXTERN_FN)
|
|
{
|
|
size_t fn_n = 0;
|
|
fzl_extern_fn_t *fn = NULL;
|
|
for (size_t i = 0; i < gen->extern_fns_count; i++)
|
|
{
|
|
if (strcmp(gen->extern_fns[i].used_name, name) == 0)
|
|
{
|
|
fn = &gen->extern_fns[i];
|
|
fn_n = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!fn)
|
|
return gen_error;
|
|
|
|
fzl_type_t rettype;
|
|
char *rettypecn = NULL;
|
|
|
|
if (!fn->has_return)
|
|
{
|
|
rettype = FZL_TYPE_NULL;
|
|
}
|
|
else if (fn->ret_type.is_primitive)
|
|
{
|
|
rettype = fn->ret_type.primitive;
|
|
}
|
|
else
|
|
{
|
|
fzl_extern_type_t *type = &gen->extern_types[fn->ret_type.type_slot];
|
|
switch (type->kind)
|
|
{
|
|
case FZL_EXTERN_KIND_REF:
|
|
rettype = FZL_TYPE_HANDLE;
|
|
rettypecn = type->name;
|
|
break;
|
|
|
|
case FZL_EXTERN_KIND_STRUCT:
|
|
rettype = FZL_TYPE_STRUCT;
|
|
rettypecn = type->name;
|
|
break;
|
|
|
|
case FZL_EXTERN_KIND_HANDLE:
|
|
rettype = FZL_TYPE_HANDLE;
|
|
rettypecn = type->name;
|
|
break;
|
|
|
|
case FZL_EXTERN_KIND_ALIAS:
|
|
if (type->alias_target.is_primitive)
|
|
{
|
|
rettype = type->alias_target.primitive;
|
|
}
|
|
else
|
|
{
|
|
fzl_extern_type_t *aliased =
|
|
&gen->extern_types[type->alias_target.type_slot];
|
|
switch (aliased->kind)
|
|
{
|
|
case FZL_EXTERN_KIND_ALIAS:
|
|
return gen_error;
|
|
|
|
case FZL_EXTERN_KIND_HANDLE:
|
|
rettype = FZL_TYPE_HANDLE;
|
|
rettypecn = aliased->name;
|
|
break;
|
|
|
|
case FZL_EXTERN_KIND_STRUCT:
|
|
rettype = FZL_TYPE_STRUCT;
|
|
rettypecn = aliased->name;
|
|
break;
|
|
|
|
case FZL_EXTERN_KIND_REF:
|
|
rettype = FZL_TYPE_HANDLE;
|
|
rettypecn = aliased->name;
|
|
break;
|
|
|
|
default:
|
|
return gen_error;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return gen_error;
|
|
}
|
|
}
|
|
|
|
gen_op(gen, FZL_OPCODE_CALL_EXTERN);
|
|
gen_word(gen, fn_n);
|
|
|
|
return (gen_res_t){
|
|
.error = false, .type = rettype, .classname = rettypecn};
|
|
}
|
|
else
|
|
{
|
|
if (!sym.ip)
|
|
return gen_error;
|
|
|
|
gen_op(gen, FZL_OPCODE_CALL);
|
|
gen_word(gen, sym.ip);
|
|
|
|
return (gen_res_t){
|
|
.error = false, .type = sym.type, .classname = sym.classname};
|
|
}
|
|
}
|
|
|
|
if (node->call.callee->type == FZL_NODETYPE_FIELD)
|
|
{
|
|
fzl_node_t *parent_node = node->call.callee->memb.parent;
|
|
fzl_node_t *method_node = node->call.callee->memb.field;
|
|
|
|
gen_res_t parent_res = gen_common(gen, parent_node);
|
|
if (parent_res.error)
|
|
return gen_error;
|
|
|
|
if (parent_res.type != FZL_TYPE_OBJECT || !parent_res.classname)
|
|
return gen_error;
|
|
|
|
char *classname = parent_res.classname;
|
|
bool class_exists = false;
|
|
for (size_t i = 0; i < gen->classes_count; i++)
|
|
{
|
|
if (strcmp(classname, gen->classes[i]->name) == 0)
|
|
{
|
|
class_exists = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!class_exists)
|
|
return gen_error;
|
|
|
|
size_t classlen = strlen(classname);
|
|
size_t fnlen = strlen(method_node->token->value);
|
|
char *methodname = malloc(classlen + fnlen + 2);
|
|
strcpy(methodname, classname);
|
|
strcpy((methodname + classlen + 1), method_node->token->value);
|
|
methodname[classlen] = '_';
|
|
methodname[classlen + fnlen + 1] = 0;
|
|
|
|
fzl_sym_t fn_sym;
|
|
bool found_method = false;
|
|
for (ssize_t i = gen->syms_top - 1; i >= 0; i--)
|
|
if ((found_method = fzl_symt_get(gen->syms[i], methodname, &fn_sym)))
|
|
break;
|
|
|
|
free(methodname);
|
|
if (!found_method)
|
|
return gen_error;
|
|
|
|
if (node->call.args_count > 0)
|
|
for (size_t i = 0; i < node->call.args_count; i++)
|
|
if (gen_common(gen, node->call.args[i]).error)
|
|
return gen_error;
|
|
|
|
gen_op(gen, FZL_OPCODE_CALL);
|
|
gen_word(gen, fn_sym.ip);
|
|
|
|
return (gen_res_t){
|
|
.error = false, .type = fn_sym.type, .classname = fn_sym.classname};
|
|
}
|
|
|
|
return gen_error;
|
|
}
|