147 lines
3.5 KiB
C
147 lines
3.5 KiB
C
#include "tysolver.h"
|
|
#include "lib/tysy.h"
|
|
|
|
void tysolver_init(tysolver_t* tysolver, sym_t* sym, tysy_t* tysy)
|
|
{
|
|
assert(tysolver);
|
|
assert(sym);
|
|
assert(tysy);
|
|
|
|
tysolver->sym = sym;
|
|
tysolver->tysy = tysy;
|
|
tysolver->scope = 0;
|
|
}
|
|
|
|
void tysolver_free(tysolver_t* tysolver)
|
|
{
|
|
assert(tysolver);
|
|
}
|
|
|
|
/*
|
|
#define NODE_TYPE(G) \
|
|
G(NODE_MOD), \
|
|
G(NODE_LET), G(NODE_IDENT), G(NODE_ASSIGN), G(NODE_VARDECL)
|
|
*/
|
|
type_t* tysolver_try_solve_node(tysolver_t* tysolver, node_t* node)
|
|
{
|
|
assert(tysolver);
|
|
assert(node);
|
|
|
|
switch (node->type)
|
|
{
|
|
case NODE_BLOCK: {
|
|
tysolver->scope++;
|
|
|
|
if (node->children.size > 0)
|
|
{
|
|
size_t last = node->children.size - 1;
|
|
|
|
return tysolver_try_solve_node(tysolver,
|
|
(node_t*) node->children.data[last]);
|
|
}
|
|
tysolver->scope--;
|
|
} break;
|
|
|
|
case NODE_VARDECL: {
|
|
return tysolver_try_solve_node(tysolver,
|
|
(node_t*) node->children.data[1]);
|
|
} break;
|
|
|
|
case NODE_IDENT: {
|
|
char* name = node->value.data;
|
|
|
|
sym_entry_t* entry = sym_try_find_by_name(tysolver->sym,
|
|
name,
|
|
tysolver->scope,
|
|
SYM_PRE | SYM_DECL,
|
|
node);
|
|
return entry ? entry->type : NULL;
|
|
} break;
|
|
|
|
case NODE_SUB:
|
|
case NODE_DIV:
|
|
case NODE_MODULO:
|
|
case NODE_POW:
|
|
case NODE_NUM: {
|
|
type_t* ty = tysy_try_find_type(tysolver->tysy, "num");
|
|
assert(ty);
|
|
return ty;
|
|
} break;
|
|
|
|
case NODE_ADD: {
|
|
return tysolver_try_solve_node(tysolver,
|
|
(node_t*) node->children.data[0]);
|
|
} break;
|
|
|
|
case NODE_MUL: {
|
|
type_t* lhs = tysolver_try_solve_node(tysolver,
|
|
(node_t*) node->children.data[0]);
|
|
|
|
type_t* rhs = tysolver_try_solve_node(tysolver,
|
|
(node_t*) node->children.data[1]);
|
|
|
|
if (type_eq(lhs, rhs) && lhs->kind == TYPE_NUM)
|
|
{
|
|
return tysolver_try_solve_node(tysolver,
|
|
(node_t*) node->children.data[0]);
|
|
}
|
|
else if ((lhs->kind == TYPE_NUM && rhs->kind == TYPE_STR)
|
|
|| (rhs->kind == TYPE_NUM && lhs->kind == TYPE_STR))
|
|
{
|
|
return tysy_try_find_type(tysolver->tysy, "str");
|
|
}
|
|
else
|
|
{
|
|
tysolver_error(tysolver, node);
|
|
}
|
|
|
|
} break;
|
|
|
|
case NODE_ASSERT:
|
|
case NODE_EQ:
|
|
case NODE_NE:
|
|
case NODE_LT:
|
|
case NODE_LE:
|
|
case NODE_GT:
|
|
case NODE_GE:
|
|
case NODE_AND:
|
|
case NODE_OR:
|
|
case NODE_NOT:
|
|
case NODE_BOOL: {
|
|
type_t* ty = tysy_try_find_type(tysolver->tysy, "bool");
|
|
assert(ty);
|
|
return ty;
|
|
} break;
|
|
|
|
case NODE_STR: {
|
|
type_t* ty = tysy_try_find_type(tysolver->tysy, "str");
|
|
assert(ty);
|
|
return ty;
|
|
} break;
|
|
|
|
case NODE_IF:
|
|
case NODE_FUNCALL: {
|
|
return NULL;
|
|
} break;
|
|
|
|
case NODE_FUNDECL: {
|
|
type_t* ty = tysy_try_find_type(tysolver->tysy, "fun");
|
|
assert(ty);
|
|
return ty;
|
|
} break;
|
|
|
|
default: {
|
|
tysolver_error(tysolver, node);
|
|
} break;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void tysolver_error(tysolver_t* tysolver, node_t* node)
|
|
{
|
|
fprintf(stderr, "Cannot solve type of '%s'.\n",
|
|
NodeTypeStr[node->type]);
|
|
abort();
|
|
}
|