155 lines
4.2 KiB
C
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;
|
|
}
|