Files
fz-lang/src/compiler/parser/pa_externfn.c
T

155 lines
4.2 KiB
C

#include <compiler/fzl_parser.h>
#include <compiler/fzl_token.h>
#include <compiler/internals/parser.h>
#include <stdio.h>
#include <stdlib.h>
// Parse external function
fzl_node_t *pa_externfn(fzl_parser_t *parser)
{
if (!parser || !peek(parser))
return NULL;
fzl_token_t *tok = consume(parser);
if (!tok || tok->type != FZL_TOKTYPE_FUNCTION)
{
snprintf(plast_err, sizeof(plast_err),
"'%s':%zu:%zu => expected 'function' keyword",
last_known_tok->filename, last_known_tok->ln, last_known_tok->cn);
return NULL;
}
fzl_token_t *name = consume(parser);
if (!name || name->type != FZL_TOKTYPE_NAME)
{
snprintf(plast_err, sizeof(plast_err),
"'%s':%zu:%zu => expected function name after 'fn'",
last_known_tok->filename, last_known_tok->ln, last_known_tok->cn);
return NULL;
}
fzl_token_t *lpar = consume(parser);
if (!lpar || lpar->type != FZL_TOKTYPE_LPAREN)
{
snprintf(plast_err, sizeof(plast_err),
"'%s':%zu:%zu => expected '(' after function name",
last_known_tok->filename, last_known_tok->ln, last_known_tok->cn);
return NULL;
}
size_t remainder = 2;
size_t count = 0;
fzl_node_t **args = malloc(remainder * sizeof(fzl_node_t *));
if (!args)
{
snprintf(plast_err, sizeof(plast_err), "out of memory");
return NULL;
}
while (peek(parser) && !is(parser, FZL_TOKTYPE_RPAREN))
{
if (remainder <= count)
{
remainder *= 2;
fzl_node_t **newarr = realloc(args, remainder * sizeof(fzl_node_t *));
if (!newarr)
{
for (size_t i = 0; i < count; i++)
fzl_freeast(args[i]);
free(args);
snprintf(plast_err, sizeof(plast_err), "out of memory");
return NULL;
}
args = newarr;
}
bool is_out = false;
if (is(parser, FZL_TOKTYPE_OUT))
{
consume(parser);
is_out = true;
}
fzl_node_t *node = pa_expression(parser);
if (!node || node->type != FZL_NODETYPE_DECLARATION)
{
for (size_t i = 0; i < count; i++)
fzl_freeast(args[i]);
free(args);
if (!plast_err[0])
snprintf(plast_err, sizeof(plast_err),
"'%s':%zu:%zu => expected declaration",
last_known_tok->filename, last_known_tok->ln,
last_known_tok->cn);
return NULL;
}
node->var.is_out = is_out;
args[count++] = node;
if (is(parser, FZL_TOKTYPE_RPAREN))
break;
fzl_token_t *comma = consume(parser);
if (!comma || comma->type != FZL_TOKTYPE_COMMA)
{
for (size_t i = 0; i < count; i++)
fzl_freeast(args[i]);
free(args);
snprintf(plast_err, sizeof(plast_err),
"'%s':%zu:%zu => missing ',' between arguments",
last_known_tok->filename, last_known_tok->ln,
last_known_tok->cn);
return NULL;
}
}
fzl_token_t *rpar = consume(parser);
if (!rpar || rpar->type != FZL_TOKTYPE_RPAREN)
{
for (size_t i = 0; i < count; i++)
fzl_freeast(args[i]);
free(args);
snprintf(plast_err, sizeof(plast_err),
"'%s':%zu:%zu => expected ')' after arguments list",
last_known_tok->filename, last_known_tok->ln, last_known_tok->cn);
return NULL;
}
char *original_name = NULL;
fzl_token_t *type = &null_tok;
if (is(parser, FZL_TOKTYPE_NAME) || is(parser, FZL_TOKTYPE_TYPE))
type = consume(parser);
if (is(parser, FZL_TOKTYPE_EQ))
{
consume(parser);
fzl_token_t *orig = consume(parser);
if (!orig || orig->type != FZL_TOKTYPE_STR_LITERAL)
{
for (size_t i = 0; i < count; i++)
fzl_freeast(args[i]);
free(args);
snprintf(plast_err, sizeof(plast_err),
"'%s':%zu:%zu => expected original function name",
last_known_tok->filename, last_known_tok->ln,
last_known_tok->cn);
return NULL;
}
original_name = (char *)orig->value;
}
fzl_node_t *node = fzl_mknode(FZL_NODETYPE_EXTERN_FN, tok);
node->ext_fn.name = (char *)name->value;
node->ext_fn.original_name = original_name;
node->ext_fn.args_count = count;
node->ext_fn.args = args;
node->ext_fn.type = type;
return node;
}