RAII #2
@@ -815,7 +815,7 @@ fzl_node_t *parse_function(fzl_parser_t *parser)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fzl_token_t *type;
|
||||
fzl_token_t *type = NULL;
|
||||
if (is(parser, FZL_TOKTYPE_TYPE) || is(parser, FZL_TOKTYPE_NAME))
|
||||
type = consume(parser);
|
||||
|
||||
|
||||
+62
-73
@@ -14,6 +14,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *null_name = "<null>";
|
||||
char wlast_err[256];
|
||||
|
||||
fzl_walker_t *fzl_mkwalker(fzl_node_t *root)
|
||||
@@ -105,8 +106,11 @@ static bool is_compatible(fzl_type_t t1, fzl_type_t t2, char *c1, char *c2)
|
||||
{
|
||||
if (t1 == FZL_TYPE_OBJECT || t2 == FZL_TYPE_OBJECT)
|
||||
{
|
||||
return t1 == FZL_TYPE_OBJECT && t2 == FZL_TYPE_OBJECT &&
|
||||
(strcmp(c1, c2) == 0);
|
||||
bool classes_compatible = strcmp(c1, c2) == 0 ||
|
||||
strcmp(c1, null_name) == 0 ||
|
||||
strcmp(c2, null_name) == 0;
|
||||
|
||||
return t1 == FZL_TYPE_OBJECT && t2 == FZL_TYPE_OBJECT && classes_compatible;
|
||||
}
|
||||
|
||||
if (t1 == t2)
|
||||
@@ -290,44 +294,34 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
|
||||
case FZL_NODETYPE_FIELD:
|
||||
{
|
||||
fzl_sym_t sym;
|
||||
bool exists = false;
|
||||
for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
|
||||
if ((exists = fzl_symt_get(walker->syms[i],
|
||||
node->memb.parent->token->value, &sym)))
|
||||
break;
|
||||
fzl_walk_res_t parent_res = walk(walker, node->memb.parent);
|
||||
if (parent_res.error)
|
||||
return parent_res;
|
||||
|
||||
if (!exists)
|
||||
if (parent_res.type != FZL_TYPE_OBJECT || !parent_res.classname)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"'%s': cannot find symbol '%s' at %ld:%ld",
|
||||
node->token->filename, (char *)node->token->value,
|
||||
node->token->ln, node->token->cn);
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
if (!sym.classname)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"'%s': '%s' is not an object (at %ld:%ld)",
|
||||
node->token->filename, sym.name, node->token->ln,
|
||||
node->token->cn);
|
||||
fzl_token_t *tok = node->memb.parent->token;
|
||||
snprintf(
|
||||
wlast_err, sizeof(wlast_err),
|
||||
"'%s': cannot access field '%s' on non-object type at %ld:%ld",
|
||||
tok->filename, (char *)node->memb.field->token->value, tok->ln,
|
||||
tok->cn);
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
fzl_ctable_t *ct = NULL;
|
||||
for (size_t i = 0; i < walker->classes_count; i++)
|
||||
{
|
||||
if (strcmp(sym.classname, walker->classes[i]->name) == 0)
|
||||
if (strcmp(parent_res.classname, walker->classes[i]->name) == 0)
|
||||
{
|
||||
ct = walker->classes[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fzl_token_t *tok = node->memb.parent->token;
|
||||
if (!ct)
|
||||
{
|
||||
fzl_token_t *tok = node->memb.parent->token;
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"'%s': access to unknown class '%s' at %ld:%ld",
|
||||
tok->filename, (char *)tok->value, tok->ln, tok->cn);
|
||||
@@ -351,20 +345,17 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"'%s': cannot find field '%s' in class '%s' at %ld:%ld",
|
||||
ftok->filename, (char *)ftok->value, (char *)tok->value,
|
||||
ftok->filename, (char *)ftok->value, parent_res.classname,
|
||||
ftok->ln, ftok->cn);
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
fzl_walk_res_t parent_res = walk(walker, node->memb.parent);
|
||||
if (parent_res.error)
|
||||
return parent_res;
|
||||
|
||||
push_op(walker, FZL_OPCODE_GET_FIELD);
|
||||
push_word(walker, ctf.slot_index);
|
||||
|
||||
current_res = (fzl_walk_res_t){
|
||||
.type = ctf.type, .error = false, .classname = sym.classname};
|
||||
current_res = (fzl_walk_res_t){.type = ctf.type,
|
||||
.error = false,
|
||||
.classname = parent_res.classname};
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -483,7 +474,8 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
if (retres.error)
|
||||
return retres;
|
||||
|
||||
if (!is_compatible(retres.type, tok_to_type(walker->ctx->fn->fn.type),
|
||||
fzl_node_t *fn_node = walker->ctx->fn;
|
||||
if (!is_compatible(retres.type, tok_to_type(fn_node->fn.type),
|
||||
retres.classname, walker->ctx->fn->fn.type->value))
|
||||
{
|
||||
snprintf(
|
||||
@@ -807,80 +799,68 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
else 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;
|
||||
|
||||
fzl_sym_t res;
|
||||
bool found = false;
|
||||
for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
|
||||
if ((found = fzl_symt_get(walker->syms[i],
|
||||
parent_node->token->value, &res)))
|
||||
break;
|
||||
fzl_walk_res_t parent_res = walk(walker, parent_node);
|
||||
if (parent_res.error)
|
||||
return parent_res;
|
||||
|
||||
if (!found)
|
||||
if (parent_res.type != FZL_TYPE_OBJECT || !parent_res.classname)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"'%s': access to unknown object '%s' at %ld:%ld",
|
||||
node->token->filename, (char *)parent_node->token->value,
|
||||
node->token->ln, node->token->cn);
|
||||
"'%s': cannot call method on non-object type at %ld:%ld",
|
||||
parent_node->token->filename, parent_node->token->ln,
|
||||
parent_node->token->cn);
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
if (res.type != FZL_TYPE_OBJECT || !res.classname)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"'%s': name '%s' is not an object (at %ld:%ld)",
|
||||
parent_node->token->filename,
|
||||
(char *)parent_node->token->value,
|
||||
parent_node->token->ln, parent_node->token->cn);
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
found = false;
|
||||
char *classname = parent_res.classname;
|
||||
bool class_exists = false;
|
||||
for (size_t i = 0; i < walker->classes_count; i++)
|
||||
{
|
||||
if (strcmp(walker->classes[i]->name, res.classname) == 0)
|
||||
if (strcmp(classname, walker->classes[i]->name) == 0)
|
||||
{
|
||||
found = true;
|
||||
class_exists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found)
|
||||
if (!class_exists)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"'%s': class '%s' not found at %ld:%ld",
|
||||
node->token->filename, res.classname, node->token->ln,
|
||||
node->token->cn);
|
||||
"'%s': class '%s' not found (at %ld:%ld)",
|
||||
parent_node->token->filename, classname,
|
||||
parent_node->token->ln, parent_node->token->cn);
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
char *classname = res.classname;
|
||||
size_t classlen = strlen(res.classname);
|
||||
size_t fnlen = strlen(node->call.callee->token->value);
|
||||
size_t classlen = strlen(classname);
|
||||
size_t fnlen = strlen(method_node->token->value);
|
||||
char *methodname = malloc(classlen + fnlen + 2);
|
||||
strcpy(methodname, res.classname);
|
||||
strcpy(methodname, classname);
|
||||
strcpy((methodname + classlen + 1),
|
||||
node->call.callee->token->value);
|
||||
methodname[classlen] = '_';
|
||||
methodname[classlen + fnlen + 1] = 0;
|
||||
|
||||
found = false;
|
||||
fzl_sym_t fn_sym;
|
||||
bool found_method = false;
|
||||
for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
|
||||
if ((found = fzl_symt_get(walker->syms[i], methodname, &res)))
|
||||
if ((found_method =
|
||||
fzl_symt_get(walker->syms[i], methodname, &fn_sym)))
|
||||
break;
|
||||
|
||||
if (!found)
|
||||
if (!found_method)
|
||||
{
|
||||
snprintf(wlast_err, sizeof(wlast_err),
|
||||
"'%s': class '%s' has no method '%s' at %ld:%ld",
|
||||
node->token->filename, classname,
|
||||
(char *)node->call.callee->token->value, node->token->ln,
|
||||
node->token->cn);
|
||||
free(methodname);
|
||||
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
|
||||
}
|
||||
|
||||
fzl_walk_res_t parent = walk(walker, parent_node);
|
||||
if (parent.error)
|
||||
return parent;
|
||||
free(methodname);
|
||||
|
||||
if (node->call.args_count > 0)
|
||||
{
|
||||
@@ -893,10 +873,11 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
}
|
||||
|
||||
push_op(walker, FZL_OPCODE_CALL);
|
||||
push_word(walker, res.ip);
|
||||
push_word(walker, fn_sym.ip);
|
||||
|
||||
current_res = (fzl_walk_res_t){
|
||||
.type = res.type, .error = false, .classname = res.classname};
|
||||
current_res = (fzl_walk_res_t){.type = fn_sym.type,
|
||||
.error = false,
|
||||
.classname = fn_sym.classname};
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -931,6 +912,14 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
|
||||
push_word(walker, val);
|
||||
current_res = (fzl_walk_res_t){.type = FZL_TYPE_BOOL, .error = false};
|
||||
}
|
||||
else if (node->token->type == FZL_TOKTYPE_NULL_LITERAL)
|
||||
{
|
||||
fzl_token_t *tok = node->token;
|
||||
push_op(walker, FZL_OPCODE_PUSHNUM);
|
||||
push_word(walker, 0);
|
||||
current_res = (fzl_walk_res_t){
|
||||
.type = FZL_TYPE_OBJECT, .error = false, .classname = null_name};
|
||||
}
|
||||
break;
|
||||
|
||||
case FZL_NODETYPE_ADD:
|
||||
|
||||
Reference in New Issue
Block a user