feat: finish generator
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
#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;
|
||||
|
||||
gen_res_t result;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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), node->call.callee->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;
|
||||
|
||||
if (!found_method)
|
||||
return gen_error;
|
||||
|
||||
free(methodname);
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user