Exemple #1
0
} END_TEST

START_TEST(test_typecheck_valid_custom_sum_type_constructor) {
    static const struct RFstring s = RF_STRING_STATIC_INIT(
        "type person { name:string | id:u32 }"
        "fn do_something()\n"
        "{\n"
        "a:person = person(\"Celina\")\n"
        "b:person = person(13)\n"
        "}\n"
    );
    front_testdriver_new_ast_main_source(&s);
    ck_assert_typecheck_ok();

    struct ast_node *fn_impl = ast_node_get_child(front_testdriver_root(), 1);
    ck_assert(fn_impl->type == AST_FUNCTION_IMPLEMENTATION);
    struct ast_node *block = ast_fnimpl_body_get(fn_impl);
    struct ast_node *bop1 = ast_node_get_child(block, 0);
    struct ast_node *bop2 = ast_node_get_child(block, 1);
    ck_assert(ast_node_is_specific_binaryop(bop1, BINARYOP_ASSIGN));
    ck_assert(ast_node_is_specific_binaryop(bop2, BINARYOP_ASSIGN));
    struct ast_node *ctor1 = ast_binaryop_right(bop1);
    struct ast_node *ctor2 = ast_binaryop_right(bop2);
    ck_assert(ctor1->type = AST_FUNCTION_CALL);
    ck_assert(ctor2->type = AST_FUNCTION_CALL);
    struct type *t_string = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_STRING);
    struct type *t_u32 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_UINT_32);
    ck_assert(type_compare(ctor1->fncall.params_type, t_string, TYPECMP_IDENTICAL));
    ck_assert(type_compare(ctor2->fncall.params_type, t_u32, TYPECMP_IDENTICAL));
} END_TEST
Exemple #2
0
} END_TEST

START_TEST(test_array_type4) {
    static const struct RFstring s = RF_STRING_STATIC_INIT(
        "{\n"
        "a:u64[] = [1, 2, 3]\n"
        "}"
    );
    front_testdriver_new_ast_main_source(&s);
    ck_assert_typecheck_ok();

    int64_t dims[] = {3};
    struct type *t_u64 = testsupport_analyzer_type_create_elemarray(
        ELEMENTARY_TYPE_UINT_64,
        dims
    );

    struct ast_node *block = ast_node_get_child(front_testdriver_module()->node, 0);
    struct ast_node *blist = ast_binaryop_right(ast_node_get_child(block, 0));
    const struct type *blist_type = ast_node_get_type(blist);
    ck_assert_msg(blist_type, "bracket type should not be NULL");
    ck_assert_msg(
        type_compare(blist_type, t_u64, TYPECMP_GENERIC),
        "Bracket type comparison failure"
    );

    struct ast_node *vardecl = ast_binaryop_left(ast_node_get_child(block, 0));
    const struct type *vardecl_type = ast_node_get_type(vardecl);
    ck_assert_msg(vardecl_type, "bracket type should not be NULL");
    ck_assert_msg(
        type_compare(vardecl_type, t_u64, TYPECMP_IDENTICAL),
        "Bracket type comparison failure"
    );
} END_TEST
Exemple #3
0
} END_TEST

START_TEST (test_type_comparison_for_sum_fncall) {
    // test for a bug concerning subtypes of sum types
    // make type a:i64 | b:u64 | c:f64 | d:string
    // just like the typechecking for function calls
    // check that comparing a subtype gives the correct matched type

    struct type *t_i64 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_INT_64);
    struct type *t_u64 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_UINT_64);
    struct type *t_f64 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_FLOAT_64);
    struct type *t_string = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_STRING);
    struct type *t_sum = testsupport_analyzer_type_create_operator(TYPEOP_SUM,
                                                                   t_i64,
                                                                   t_u64,
                                                                   t_f64,
                                                                   t_string);

    typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL);
    ck_assert(type_compare(t_u64, t_sum, TYPECMP_PATTERN_MATCHING));
    const struct type *matched_type = typemp_ctx_get_matched_type();
    ck_assert_msg(
        matched_type == t_u64,
        "Unexpected match type "RFS_PF" found",
        RFS_PA(type_str_or_die(matched_type, TSTR_DEFAULT))
    );

    typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL);
    ck_assert(type_compare(t_i64, t_sum, TYPECMP_PATTERN_MATCHING));
    matched_type = typemp_ctx_get_matched_type();
    ck_assert_msg(
        matched_type == t_i64,
        "Unexpected match type "RFS_PF" found",
        RFS_PA(type_str_or_die(matched_type, TSTR_DEFAULT))
    );

    typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL);
    ck_assert(type_compare(t_f64, t_sum, TYPECMP_PATTERN_MATCHING));
    matched_type = typemp_ctx_get_matched_type();
    ck_assert_msg(
        matched_type == t_f64,
        "Unexpected match type "RFS_PF" found",
        RFS_PA(type_str_or_die(matched_type, TSTR_DEFAULT))
    );

    typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL);
    ck_assert(type_compare(t_string, t_sum, TYPECMP_PATTERN_MATCHING));
    matched_type = typemp_ctx_get_matched_type();
    ck_assert_msg(
        matched_type == t_string,
        "Unexpected match type "RFS_PF" found",
        RFS_PA(type_str_or_die(matched_type, TSTR_DEFAULT))
    );

} END_TEST
Exemple #4
0
//compare the two parameters
int param_list_compare(struct param_list *a, struct param_list *b){
	if(!a && !b) return 1;
	if(!a || !b) return 0;
	if(a->name && b->name)
		return (strcmp(a->name, b->name) == 0 && type_compare(a->type, b->type) /*&& 
			symbol_compare(a->symbol, b->symbol)*/ && param_list_compare(a->next, b->next));
	else if(!a->name && !b->name)
		return (type_compare(a->type, b->type) /*&& symbol_compare(a->symbol, b->symbol)*/ && 
			param_list_compare(a->next, b->next));
	else return 0;
}
Exemple #5
0
void expr_typecheck_array(struct type *array_type, struct expr *e_list)
{
    if (!e_list)
        return;

    struct type *t;

    if (e_list->kind == EXPR_LIST)
        t = expr_typecheck(e_list->left);
    else if (e_list->kind == EXPR_LIST_OUTER)
        t = expr_typecheck(e_list->right);

    if (!type_compare(t, array_type))
    {
        printf("type error: line %d: ", e_list->line);
        printf("expression type ");
        type_print(t);
        printf(" (");
        expr_print(e_list->right);
        printf(")");
        printf(" found in assignment to array of type ");
        type_print(array_type);
        printf("\n");
        error_count++;
    }

    expr_typecheck_array(array_type, e_list->right);
}
Exemple #6
0
} END_TEST

START_TEST(test_determine_block_type2) {
    struct ast_node *block;
    static const struct RFstring s = RF_STRING_STATIC_INIT(
        "type foo {a:i8, b:string}\n"
        "{\n"
        "a:foo\n"
        "}"
    );
    front_testdriver_new_ast_main_source(&s);
    ck_assert_typecheck_ok();

    struct type *t_i8 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_INT_8);
    struct type *t_string = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_STRING);
    struct type *t_prod_1 = testsupport_analyzer_type_create_operator(TYPEOP_PRODUCT,
                                                                      t_i8,
                                                                      t_string);
    static const struct RFstring id_foo = RF_STRING_STATIC_INIT("foo");
    struct type *t_foo = testsupport_analyzer_type_create_defined(&id_foo, t_prod_1);

    block = ast_node_get_child(front_testdriver_module()->node, 1);
    ck_assert_msg(block, "Block should be the second child of the root");
    const struct type *block_type = ast_node_get_type(block);
    ck_assert_msg(block_type, "Block should have a type");
    ck_assert_msg(type_compare(block_type, t_foo, TYPECMP_IDENTICAL),
                  "Expected the block's type to be an f64");
} END_TEST
Exemple #7
0
void decl_typecheck( struct decl *d ) {
	if (!d) return;
	if (d->value) {
		struct type *T = expr_typecheck( d-> value );
		if (!type_compare(d->type, T)) {
			printf("type error: cannot initialize variable (%s) of type ", d->name);
			type_print(d->type);
			printf(" and assign it a ");
			type_print( T );
			printf("\n");
		}
	}
	if (d->type->kind == TYPE_ARRAY) {
		// for array
		decl_array_typecheck(d->type, d->name);
	} else if (d->type->kind == TYPE_FUNCTION) {
		// for function return
		decl_array_typecheck(d->type->subtype, d->name);		
	}
	
	if (d->code) {
		decl_func_sym = scope_lookup(d->name);
		stmt_typecheck(d->code);
	}
	if (d->next)
		decl_typecheck(d->next);
}
Exemple #8
0
static bool test_traversal_cb(
    const struct RFstring *name,
    const struct ast_node *desc,
    struct type *t,
    struct test_traversal_cb_ctx *ctx)
{
    ck_assert_msg(
        rf_string_equal(&ctx->names[ctx->idx], name),
        "Ast type traversal index %u expected name "RF_STR_PF_FMT" but got "
        RF_STR_PF_FMT".",
        ctx->idx,
        RF_STR_PF_ARG(&ctx->names[ctx->idx]),
        RF_STR_PF_ARG(name)
    );
    ck_assert_msg(
        type_compare(ctx->types[ctx->idx], t, TYPECMP_IDENTICAL),
        "Ast type traversal index %u expected type "RF_STR_PF_FMT" but got "
        RF_STR_PF_FMT".",
        ctx->idx,
        RF_STR_PF_ARG(type_str(ctx->types[ctx->idx], TSTR_DEFAULT)),
        RF_STR_PF_ARG(type_str(t, TSTR_DEFAULT))
    );
    ++ctx->idx;
    return true;
}
int
type_compare(const glsl_type *a, const glsl_type *b)
{
   /* If the types are the same, they trivially match.
    */
   if (a == b)
      return 0;

   switch (a->base_type) {
   case GLSL_TYPE_UINT:
   case GLSL_TYPE_INT:
   case GLSL_TYPE_BOOL:
      /* There is no implicit conversion to or from integer types or bool.
       */
      if ((a->is_integer() != b->is_integer())
	  || (a->is_boolean() != b->is_boolean()))
	 return -1;

      /* FALLTHROUGH */

   case GLSL_TYPE_FLOAT:
      if ((a->vector_elements != b->vector_elements)
	  || (a->matrix_columns != b->matrix_columns))
	 return -1;

      return 1;

   case GLSL_TYPE_SAMPLER:
   case GLSL_TYPE_STRUCT:
      /* Samplers and structures must match exactly.
       */
      return -1;

   case GLSL_TYPE_ARRAY:
      if ((b->base_type != GLSL_TYPE_ARRAY)
	  || (a->length != b->length))
	 return -1;

      /* From GLSL 1.50 spec, page 27 (page 33 of the PDF):
       *    "There are no implicit array or structure conversions."
       *
       * If the comparison of the array element types detects that a conversion
       * would be required, the array types do not match.
       */
      return (type_compare(a->fields.array, b->fields.array) == 0) ? 0 : -1;

   case GLSL_TYPE_VOID:
   case GLSL_TYPE_ERROR:
   default:
      /* These are all error conditions.  It is invalid for a parameter to
       * a function to be declared as error, void, or a function.
       */
      return -1;
   }

   /* This point should be unreachable.
    */
   assert(0);
}
Exemple #10
0
int symbol_compare(struct symbol * a, struct symbol * b) {
	if (!a && !b) {
		return 1;
	}
	else if ((!a || !b)) {
		return 0;
	}
	else {
		if (!(a->name) && !(b->name)) {
			return (a->kind==b->kind) && (a->which==b->which) && type_compare(a->type, b->type) && (a->code==b->code);
		}
		else if (!(a->name) || !(b->name)) {
			return 0;
		}
		else {
			return (a->kind==b->kind) && (a->which==b->which) && type_compare(a->type, b->type) && !strcmp(a->name, b->name) && (a->code==b->code);
		}
	}
}
Exemple #11
0
int compareWithNoCase2(const char_type* str1, const char_type* str2) {
	char_type *str1_2 = new char_type[type_length(str1)];
	char_type *str2_2 = new char_type[type_length(str2)];
	type_copy(str1_2, str1);
	type_copy(str2_2, str2);
	toupper(*str1_2);
	toupper(*str2_2);
	int result = type_compare(str1_2, str2_2);
	delete[] str1_2;
	delete[] str2_2;
	return result;
}
Exemple #12
0
int type_compare(struct type *a, struct type *b) {
    if(!a && !b)
        return 1;
    if(!a || !b)
        return 0;
    if(a->kind != b->kind)
        return 0;
    if(a->kind == TYPE_FUNCTION) {
        if(!type_compare(a->subtype,b->subtype))
            return 0;
    }
    //The following may be necessary but I'm not sure
    /*if(a->params != b->params)
    	return 0;*/
    return 1;
}
Exemple #13
0
} END_TEST

START_TEST (test_type_comparison_for_sum_fncall_with_conversion) {
    struct type *t_i8 = testsupport_analyzer_type_create_elementary(ELEMENTARY_TYPE_INT_8, false);
    struct type *t_i64 = testsupport_analyzer_type_create_elementary(ELEMENTARY_TYPE_INT_64, false);
    struct type *t_f64 = testsupport_analyzer_type_create_elementary(ELEMENTARY_TYPE_FLOAT_64, false);
    struct type *t_string = testsupport_analyzer_type_create_elementary(ELEMENTARY_TYPE_STRING, false);

    struct type *t_sum = testsupport_analyzer_type_create_operator(TYPEOP_SUM,
                                                                   t_i64,
                                                                   t_f64,
                                                                   t_string);

    typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL);
    ck_assert(type_compare(t_i8, t_sum, TYPECMP_PATTERN_MATCHING));
    const struct type *matched_type = typemp_ctx_get_matched_type();
    ck_assert_msg(matched_type == t_i64, "Unexpected match type "RF_STR_PF_FMT" found", RF_STR_PF_ARG(type_str_or_die(matched_type, TSTR_DEFAULT)));
} END_TEST
Exemple #14
0
} END_TEST

START_TEST(test_determine_block_type1) {
    struct ast_node *block;
    static const struct RFstring s = RF_STRING_STATIC_INIT(
        "{\n"
        "d:f64 = 3.14 * 0.14\n"
        "}"
    );
    front_testdriver_new_ast_main_source(&s);
    ck_assert_typecheck_ok();

    struct type *t_f64 = testsupport_analyzer_type_create_simple_elementary(ELEMENTARY_TYPE_FLOAT_64);
    block = ast_node_get_child(front_testdriver_module()->node, 0);
    ck_assert_msg(block, "Block should be the first child of the root");
    const struct type *block_type = ast_node_get_type(block);
    ck_assert_msg(block_type, "Block should have a type");
    ck_assert_msg(type_compare(block_type, t_f64, TYPECMP_IDENTICAL),
                  "Expected the block's type to be an f64");
} END_TEST
Exemple #15
0
void param_list_typecheck( struct expr * e, struct param_list *params, char *func_name) {
	while (e && params) {
		struct type *T = expr_typecheck(e);
		if (!type_compare(T, params->type)) {
			decl_has_error = 1;
			printf("type error: cannot pass variable of type ");
			type_print(T);
			printf(" to function %s\n", func_name);

		} 
		e = e->next;
		params = params->next;
	}
	if (e) {
		decl_has_error = 1;
		printf("type error: pass more variables to functions call %s than needed\n", func_name);
	}
	if (params) {
		decl_has_error = 1;
		printf("type error: not enough variables to function call %s\n", func_name);
	}
}
Exemple #16
0
} END_TEST

START_TEST(test_array_type3) {
    static const struct RFstring s = RF_STRING_STATIC_INIT(
        "a:u64[42][13][24]\n"
    );
    front_testdriver_new_ast_main_source(&s);
    ck_assert_typecheck_ok();

    int64_t dims[] = {42, 13, 24};
    struct type *t_u64 = testsupport_analyzer_type_create_elemarray(
        ELEMENTARY_TYPE_UINT_64,
        dims
    );
    struct ast_node *typedesc = ast_node_get_child(front_testdriver_module()->node, 0);
    const struct type *n_type = ast_node_get_type(typedesc);
    ck_assert_msg(n_type, "Type should not be NULL");
    ck_assert_msg(
        type_compare(n_type, t_u64, TYPECMP_IDENTICAL),
        "Node type comparison failure"
    );
} END_TEST
Exemple #17
0
//checks if a function call matches up to the function types
void function_typecheck(const char *function_name, struct expr *e, struct param_list *p, int param, int func_params) {
	if(!e && !p) return; //only for no parameters
	if(!e) {
		printf("type error: In call to function %s, expected %d parameters, but received %d\n", function_name, param, func_params);
		error_count++;
		return;
	} 
	if(!p) {
		struct expr *e1;
		if(e->kind == EXPR_COMMA) e1 = e->left;
		else e1 = e;
		struct type *t = expr_typecheck(e1);
		printf("type error: In call to function %s, expected %d parameters, but received %d\n", function_name, param, func_params);
		error_count++;
		return;
	}
	int last_expr = 0, last_param = 0;
	if(e->kind != EXPR_COMMA) last_expr = 1;
	if(!p->next) last_param = 1;

	struct type *t = expr_typecheck(e->left);
	if(e->kind == EXPR_COMMA){
		if(!type_compare(t, p->type)){
			printf("type error: In call to function %s, expected parameter %d to be of type ", function_name, param);
			type_print(p->type);
			printf(". Instead, expression ");
			expr_print(e->left);
			printf(" of type ");
			type_print(t);
			printf(" was passed to parameter %d\n", param);
			error_count++;
		}	
	}

	if(last_expr && last_param) return;
	function_typecheck(function_name, e->right, p->next, ++param, func_params);
}
Exemple #18
0
// compare two types
int type_compare( struct type *a, struct type *b ){
	if(!a && !b) return 1;
	if(!a || !b) return 0;
	return (a->kind == b->kind && param_list_compare(a->params, b->params) && 
		type_compare(a->subtype, b->subtype) && expr_compare(a->opt_expr, b->opt_expr));
}
Exemple #19
0
struct type * expr_typecheck( struct expr *e ) {
	if (!e) return type_create(TYPE_VOID, 0, 0);
	struct type *L;
	struct type *R;
	switch (e->kind) {
		case EXPR_INT_VAL:
			return type_create(TYPE_INTEGER, 0, 0);
		case EXPR_NAME:
			return type_copy(e->symbol->type);
		case EXPR_STRING_VAL:
			return type_create(TYPE_STRING, 0, 0);
		case EXPR_CHAR_VAL:
			return type_create(TYPE_CHARACTER, 0, 0);
		case EXPR_BOOLEAN_VAL:
			return type_create(TYPE_BOOLEAN, 0, 0);
		case EXPR_ARRAY_VAL:
		{
			struct expr *vals = e->right;
			struct type *subtype = 0;
			int num_subtype = 0;
			while (vals) {
				struct type *cur_t = expr_typecheck(vals);
				if (!subtype) {
					subtype = cur_t;
				}
				if (!type_compare(subtype, cur_t)) {
					decl_has_error = 1;
					printf("type error: array of element type ");
					type_print(subtype);
					printf(" cannot have expression of type ");
					type_print(cur_t);
					printf("\n");
				}
				num_subtype++;
				vals = vals->next;
			}
			struct type *t = type_create(TYPE_ARRAY, 0, subtype);
			t->num_subtype = expr_create_integer_literal(num_subtype);
			return t;
		}
			//return type_copy(e->symbol->type);
		case EXPR_ARRAY_SUB:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot use ");
				type_print(R);
				printf(" as index to an array\n");
			}
			if (L->kind != TYPE_ARRAY) {
				decl_has_error = 1;
				printf("type error: access an ");
				type_print(R);
				printf(" as an array\n");
			}
			return type_copy(L->subtype);
		case EXPR_FUNCTION_VAL:
			// need to check function params!!!!!
			param_list_typecheck(e->right, e->symbol->params, e->name);
			return type_copy(e->symbol->type->subtype);
		case EXPR_ADD:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot add ");
				type_print(L);
				printf(" to a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_INTEGER, 0, 0);
		case EXPR_SUB:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if ( !(L->kind == TYPE_INTEGER && L->kind == TYPE_INTEGER) || R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot subtract ");
				type_print(L);
				printf(" to a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_INTEGER, 0, 0);
		case EXPR_MUL:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot multiply ");
				type_print(L);
				printf(" to a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_INTEGER, 0, 0);
		case EXPR_DIV:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot divide ");
				type_print(L);
				printf(" to a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_INTEGER, 0, 0);
		case EXPR_MODULO:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot module ");
				type_print(L);
				printf(" to a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_INTEGER, 0, 0);
		case EXPR_EXPO:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot expo ");
				type_print(L);
				printf(" to a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_INTEGER, 0, 0);
		case EXPR_POST_DECREASE:
			L = expr_typecheck(e->left);
			if (L->kind != TYPE_INTEGER ) {
				decl_has_error = 1;
				printf("type error: cannot decrease a ");
				type_print(L);
				printf("\n");
			}
			return type_create(TYPE_INTEGER, 0, 0);
		case EXPR_POST_INCREASE:
			L = expr_typecheck(e->left);
			if (L->kind != TYPE_INTEGER ) {
				decl_has_error = 1;
				printf("type error: cannot add a ");
				type_print(L);
				printf("\n");
			}
			return type_create(TYPE_INTEGER, 0, 0);
		case EXPR_GE:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot make greater equal than compare ");
				type_print(L);
				printf(" with a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_BOOLEAN, 0, 0);		
		case EXPR_LE:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot make less equal compare ");
				type_print(L);
				printf(" with a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_BOOLEAN, 0, 0);		
		case EXPR_GT:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot make greater than compare ");
				type_print(L);
				printf(" with a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_BOOLEAN, 0, 0);		
		case EXPR_LT:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) {
				decl_has_error = 1;
				printf("type error: cannot make less than compare ");
				type_print(L);
				printf(" with a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_BOOLEAN, 0, 0);
		case EXPR_AND:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN) {
				decl_has_error = 1;
				printf("type error: cannot and ");
				type_print(L);
				printf(" with a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_BOOLEAN, 0, 0);
		case EXPR_NOT:
			R = expr_typecheck(e->right);
			if (R->kind != TYPE_BOOLEAN) {
				decl_has_error = 1;
				printf("type error: cannot not a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_BOOLEAN, 0, 0);
		case EXPR_OR:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN) {
				decl_has_error = 1;
				printf("type error: cannot or ");
				type_print(L);
				printf(" with a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_BOOLEAN, 0, 0);
		case EXPR_EQ:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind == TYPE_FUNCTION || R->kind == TYPE_FUNCTION
				|| L->kind == TYPE_ARRAY || R->kind == TYPE_ARRAY) {
				decl_has_error = 1;
				printf("type error: cannot compare equality ");
				type_print(L);
				printf(" with a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_BOOLEAN, 0, 0);
		case EXPR_NEQ:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind == TYPE_FUNCTION || R->kind == TYPE_FUNCTION
				|| L->kind == TYPE_ARRAY || R->kind == TYPE_ARRAY) {
				decl_has_error = 1;
				printf("type error: cannot compare non equality ");
				type_print(L);
				printf(" with a ");
				type_print(R);
				printf("\n");
			}
			return type_create(TYPE_BOOLEAN, 0, 0);
		case EXPR_ASSIGN:
			L = expr_typecheck(e->left);
			R = expr_typecheck(e->right);
			if (L->kind == TYPE_FUNCTION || R->kind == TYPE_FUNCTION) {
				decl_has_error = 1;
				printf("type error: cannot assign ");
				type_print(R);
				printf(" to a ");
				type_print(L);
				printf("\n");
			}
			if (!type_compare(L, R)) {
				decl_has_error = 1; 
				printf("type error: cannot assign ");
				type_print(R);
				printf(" to a ");
				type_print(L);
				printf("\n");
			}
			return type_copy(R);
	}
}
Exemple #20
0
static int F() { // function declaration
    Tdata_type ftype;

    switch (token.type) {
    case TT_INT:
    case TT_DOUBLE:
    case TT_STRING: // rule: type idf ( AL ) FD
        ftype = get_type();
        tmp_ftype = ftype;
        next();

        check(TT_ID);
        try(add_func(ftype, token.p_string));
        next();

        term(TT_L_BRACKET);
        call(AL);
        term(TT_R_BRACKET);
        return(FD);

    default:
        return ERR_PARSER;
    }
}

static int AL() { // first function argument
    switch (token.type) {
    case TT_INT:
    case TT_DOUBLE:
    case TT_STRING: // rule: AL -> AD AL2
        call(AD);
        return(AL2);

    default: // rule: AL -> eps
        return OK;
    }
}

static int AL2() { // remaining function arguments
    switch (token.type) {
    case TT_COMMA: // rule: AL2 -> , AD AL2
        next();
        call(AD);
        return(AL2);

    default: // rule: AL2 -> eps
        return OK;
    }
}

static int AD() { // argument
    Tdata_type atype;

    switch (token.type) {
    case TT_INT:
    case TT_DOUBLE:
    case TT_STRING: // rule: AD -> type id
        atype = get_type();
        next();

        check(TT_ID);
        try(add_param(atype, token.p_string));
        next();

        return OK;

    default:
        return ERR_PARSER;
    }
}

static int FD() { // function definition
    unsigned i;

    switch (token.type) {
    case TT_SEMICOLON: // rule: FD -> ;
        try(func_declaration());

        next();
        return OK;

    case TT_OPEN_BRACKET: // rule: FD -> { STL }
        i = get_line();
        try(func_definition(i)); // instruction pointer

        next();

        call(STL);

        term(TT_CLOSE_BRACKET);

        remove_block();
        generate(I_ERR, NULL, NULL, NULL); // no return => runtime error

        return OK;

    default:
        return ERR_PARSER;
    }
}

static int STL() { // stat list
    switch (token.type) {
    case TT_CLOSE_BRACKET: // rule: STL -> eps
        return OK;

    default: // rule: STL -> S STL
        call(S);
        return(STL);
    }
}

static int S() { // stat
    unsigned i;
    Tlocal_sym_tab_node *conv;

    switch (token.type) {
    case TT_AUTO:
    case TT_INT:
    case TT_DOUBLE:
    case TT_STRING: // rule: S -> D ;
        call(D);
        term(TT_SEMICOLON);
        return OK;

    case TT_OPEN_BRACKET: // rule: S -> { STL }
        next();

        try(add_block());

        call(STL);

        term(TT_CLOSE_BRACKET);

        remove_block();

        return OK;

    case TT_IF: // rule: S -> if ( E ) S else S
        next();
        term(TT_L_BRACKET);

        call(E);
        try(type_compare(tmp_psitem.type, TYPE_INT));

        if (tmp_psitem.type != TYPE_INT) {
            try(tmp_var(TYPE_INT, &conv));

            generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv);
        } else {
            conv = tmp_psitem.value.ptr;
        }

        Tlocal_sym_tab_node *label;
        try(tmp_var(TYPE_INT, &label));
        generate(I_JUMPIFN, conv, label, NULL);

        term(TT_R_BRACKET);
        call(S);

        Tlocal_sym_tab_node *endif;
        try(tmp_var(TYPE_INT, &endif));
        generate(I_JUMP, NULL, endif, NULL);

        i = get_line();
        set_var_value_int(label->name, i);

        call(ELSE);

        i = get_line();
        set_var_value_int(endif->name, i);

        return OK;

    case TT_FOR: // rule: S -> for ( D ; E ; E ) S
        try(add_block());

        next();
        term(TT_L_BRACKET);
        call(D);
        term(TT_SEMICOLON);

        Tlocal_sym_tab_node *cond;
        try(tmp_var(TYPE_INT, &cond));
        i = get_line();
        set_var_value_int(cond->name, i);

        call(E);
        try(type_compare(tmp_psitem.type, TYPE_INT));

        if (tmp_psitem.type != TYPE_INT) {
            try(tmp_var(TYPE_INT, &conv));

            generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv);
        } else {
            conv = tmp_psitem.value.ptr;
        }

        Tlocal_sym_tab_node *endfor;
        try(tmp_var(TYPE_INT, &endfor));
        generate(I_JUMPIFN, conv, endfor, NULL);

        Tlocal_sym_tab_node *statlist;
        try(tmp_var(TYPE_INT, &statlist));
        generate(I_JUMP, NULL, statlist, NULL);

        Tlocal_sym_tab_node *assign;
        try(tmp_var(TYPE_INT, &assign));
        i = get_line();
        set_var_value_int(assign->name, i);

        term(TT_SEMICOLON);
        call(E);

        generate(I_JUMP, NULL, cond, NULL);

        i = get_line();
        set_var_value_int(statlist->name, i);

        term(TT_R_BRACKET);
        call(S);

        generate(I_JUMP, NULL, assign, NULL);

        i = get_line();
        set_var_value_int(endfor->name, i);

        remove_block();

        return OK;

    case TT_WHILE: // rule: S -> while ( E ) S
        next();

        term(TT_L_BRACKET);

        Tlocal_sym_tab_node *wcond;
        try(tmp_var(TYPE_INT, &wcond));
        i = get_line();
        set_var_value_int(wcond->name, i);

        call(E);
        try(type_compare(tmp_psitem.type, TYPE_INT));

        if (tmp_psitem.type != TYPE_INT) {
            try(tmp_var(TYPE_INT, &conv));

            generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv);
        } else {
            conv = tmp_psitem.value.ptr;
        }

        Tlocal_sym_tab_node *endwhile;
        try(tmp_var(TYPE_INT, &endwhile));
        generate(I_JUMPIFN, conv, endwhile, NULL);

        term (TT_R_BRACKET);

        call(S);

        generate(I_JUMP, NULL, wcond, NULL);

        i = get_line();
        set_var_value_int(endwhile->name, i);

        return OK;

    case TT_DO: // rule: S -> do S while ( E ) ;
        next();

        Tlocal_sym_tab_node *dwbody;
        try(tmp_var(TYPE_INT, &dwbody));
        i = get_line();
        set_var_value_int(dwbody->name, i);

        call(S);

        term(TT_WHILE);

        term(TT_L_BRACKET);

        call(E);
        try(type_compare(tmp_psitem.type, TYPE_INT));

        if (tmp_psitem.type != TYPE_INT) {
            try(tmp_var(TYPE_INT, &conv));

            generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv);
        } else {
            conv = tmp_psitem.value.ptr;
        }

        generate(I_JUMPIF, conv, dwbody, NULL);

        term(TT_R_BRACKET);

        term(TT_SEMICOLON);

        return OK;

    case TT_RETURN: // rule: S -> return E ;
        next();

        call(E);
        try(type_compare(tmp_ftype, tmp_psitem.type));

        if (tmp_psitem.type != tmp_ftype) {
            try(tmp_var(tmp_ftype, &conv));

            generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv);
        } else {
            conv = tmp_psitem.value.ptr;
        }

        generate(I_RETURN, conv, NULL, NULL);

        term(TT_SEMICOLON);
        return OK;

    case TT_CIN: // rule: S -> cin >> id IN ;
        next();
        term(TT_IN);

        check(TT_ID);
        if (!var_exists(token.p_string))
            return ERR_UNDEF;
        Tlocal_sym_tab_node *var = get_var(token.p_string);

        generate(I_CIN, NULL, NULL, var);

        next();

        call(IN);
        term(TT_SEMICOLON);
        return OK;

    case TT_COUT: // rule: S -> cout << E OUT ;
        next();
        term(TT_OUT);

        call(E);

        generate(I_COUT, tmp_psitem.value.ptr, NULL, NULL);

        call(OUT);
        term(TT_SEMICOLON);
        return OK;

    default: // rule: S -> E ;
        call(E);
        term(TT_SEMICOLON);
        return OK;
    }
}

static int D() { // variable declaration
    Tdata_type vtype;

    switch (token.type) {
    case TT_AUTO:
    case TT_INT:
    case TT_DOUBLE:
    case TT_STRING: // rule: D -> type id I
        vtype = get_type();
        tmp_type = vtype;
        next();

        check(TT_ID);
        try(add_var(vtype, token.p_string));
        try(tmpstr(token.p_string));
        next();

        return(I);

    default:
        return ERR_PARSER;
    }
}

static int I() { // variable definition
    switch (token.type) {
    case TT_ASSIGN: // rule: I -> = E
        next();
        call(E);

        try(assign_type_compare(tmp_buffer.str, tmp_psitem.type));

        Tlocal_sym_tab_node *var = get_var(tmp_buffer.str);
        Tlocal_sym_tab_node *conv;

        if (tmp_psitem.type != var->data_type) {
            try(tmp_var(var->data_type, &conv));

            generate(I_CONVERT, tmp_psitem.value.ptr, NULL, conv);
        } else {
            conv = tmp_psitem.value.ptr;
        }

        generate(I_ASSIGN, conv, NULL, var);

        return OK;

    default: // rule: I -> eps
        if (tmp_type == TYPE_AUTO)
            return ERR_AUTO;
        return OK;
    }
}

static int ELSE() { // else
    switch (token.type) {
    case TT_ELSE: // rule: ELSE -> else S
        next();

        return(S);

    default: // rule: ELSE -> eps
        return OK;
    }
}

static int IN() { // input variables
    switch (token.type) {
    case TT_IN: // rule: IN -> >> id IN
        next();

        check(TT_ID);
        if (!var_exists(token.p_string))
            return ERR_UNDEF;
        Tlocal_sym_tab_node *var = get_var(token.p_string);

        generate(I_CIN, NULL, NULL, var);

        next();

        return(IN);

    default: // rule: IN -> eps
        return OK;
    }
}

static int OUT() { // output expressions
    switch (token.type) {
    case TT_OUT: // rule: OUT -> << E OUT
        next();
        call(E);

        generate(I_COUT, tmp_psitem.value.ptr, NULL, NULL);

        return(OUT);

    default: // rule: OUT -> eps
        return OK;
    }
}

static int E() { // expression
    Tpsa_stack *psa_stack = ps_init();

    ps_push(psa_stack, OP_END);

    if (get_prec(OP_END) == ' ') {
        fprintf(stderr, "Syntax error: 'expression' expected, but '%s' given.\n", token_[token.type]);

        return ERR_PARSER;
    }

    int err;

    do {
        Tps_item *ps_item = ps_first_term(psa_stack);
        switch (get_prec(ps_item->op)) {
        case '=':
            err = ps_push_token(psa_stack);
            if (err != OK) {
                ps_destroy(psa_stack);
                return err;
            }
            next();
            break;

        case '<':
            err = ps_ins_after(psa_stack, ps_item, OP_EXPR);
            if (err != OK) {
                ps_destroy(psa_stack);
                return err;
            }

            err = ps_push_token(psa_stack);
            if (err != OK) {
                ps_destroy(psa_stack);
                return err;
            }

            next();
            break;

        case '>':
            err = psa(psa_stack);
            if (err != OK) {
                ps_destroy(psa_stack);
                return err;
            }
            break;
        }
    } while (get_prec(ps_first_term(psa_stack)->op) != ' ');

    Tps_item *top = ps_top(psa_stack);

    if (top->op != OP_NTERM || ps_prev(psa_stack)->op != OP_END) {
        fprintf(stderr, "Syntax error: unexpected '%s'\n", token_[token.type]);
        return ERR_PARSER;
    }

    tmp_psitem.type = top->type;
    tmp_psitem.value = top->value;

    ps_destroy(psa_stack);

    return OK;
}

int parse() {
    next();

    strInit(&tmp_buffer);

    int err = P();

    strFree(&tmp_buffer);

    return err;
}
Exemple #21
0
enum traversal_cb_res typecheck_function_call(
    struct ast_node *n,
    struct analyzer_traversal_ctx *ctx)
{
    const struct RFstring *fn_name;
    const struct type *fn_type;
    const struct type *fn_declared_args_type;
    const struct type *fn_found_args_type;
    struct ast_node *fn_call_args = ast_fncall_args(n);

    // check for existence of function
    fn_name = ast_fncall_name(n);
    fn_type = type_lookup_identifier_string(fn_name, ctx->current_st);

    if (!fn_type || !type_is_callable(fn_type)) {
        analyzer_err(ctx->m, ast_node_startmark(n),
                     ast_node_endmark(n),
                     "Undefined function call \""RFS_PF"\" detected",
                     RFS_PA(fn_name));
        goto fail;
    }

    // create the arguments ast node array
    ast_fncall_arguments(n);

    // also check the ast node of the function declaration to get more
    // information if it's not a conversion
    if (!type_is_explicitly_convertable_elementary(fn_type)) {
        const struct ast_node *fndecl = symbol_table_lookup_node(
            ctx->current_st,
            fn_name,
            NULL
        );
        RF_ASSERT(fndecl, "Since fn_type was found so should fndecl be found here");
        if (fndecl->fndecl.position == FNDECL_PARTOF_FOREIGN_IMPORT) {
            n->fncall.type = AST_FNCALL_FOREIGN;
        }
    }

    fn_found_args_type = (fn_call_args)
        ? ast_node_get_type(fn_call_args)
        : type_elementary_get_type(ELEMENTARY_TYPE_NIL);

    if (!fn_found_args_type) { // argument typechecking failed
        goto fail;
    }

    if (type_is_explicitly_convertable_elementary(fn_type)) {
        // silly way to check if it's only 1 argument. Maybe figure out safer way?
        if (!fn_call_args || fn_found_args_type->category == TYPE_CATEGORY_OPERATOR) {
            analyzer_err(
                ctx->m,
                ast_node_startmark(n),
                ast_node_endmark(n),
                "Invalid arguments for explicit conversion to \""
                RFS_PF"\".",
                RFS_PA(fn_name)
            );
            goto fail;
        }

        // check if the explicit conversion is valid
        if (!type_compare(fn_found_args_type, fn_type, TYPECMP_EXPLICIT_CONVERSION)) {
            analyzer_err(ctx->m, ast_node_startmark(n), ast_node_endmark(n),
                         "Invalid explicit conversion. "RFS_PF".",
                         RFS_PA(typecmp_ctx_get_error()));
            goto fail;
        }
        n->fncall.type = AST_FNCALL_EXPLICIT_CONVERSION;
    } else {
        //check that the types of its arguments do indeed match
        fn_declared_args_type = type_callable_get_argtype(fn_type);
        n->fncall.declared_type = fn_declared_args_type;
        if (type_is_sumop(fn_declared_args_type)) {
            n->fncall.type = AST_FNCALL_SUM;
        }
        typecmp_ctx_set_flags(TYPECMP_FLAG_FUNCTION_CALL);
        if (!type_compare(
                fn_found_args_type,
                fn_declared_args_type,
                n->fncall.type == AST_FNCALL_SUM
                    ? TYPECMP_PATTERN_MATCHING :
                    TYPECMP_IMPLICIT_CONVERSION)) {
            RFS_PUSH();
            analyzer_err(
                ctx->m, ast_node_startmark(n), ast_node_endmark(n),
                RFS_PF" "RFS_PF"() is called with argument type of \""RFS_PF
                "\" which does not match the expected "
                "type of \""RFS_PF"\"%s"RFS_PF".",
                RFS_PA(type_callable_category_str(fn_type)),
                RFS_PA(fn_name),
                RFS_PA(type_str_or_die(fn_found_args_type, TSTR_DEFAULT)),
                RFS_PA(type_str_or_die(fn_declared_args_type, TSTR_DEFINED_ONLY_CONTENTS)),
                typecmp_ctx_have_error() ? ". " : "",
                RFS_PA(typecmp_ctx_get_error())
            );
            RFS_POP();
            goto fail;
        }
        // the function call's matched type should be either a specific sum type
        // that may have matched or the entirety of the called arguments
        if (!(n->fncall.params_type = typemp_ctx_get_matched_type())) {
            n->fncall.params_type = fn_found_args_type;
        }
    }

    traversal_node_set_type(n, type_callable_get_rettype(fn_type), ctx);
    return TRAVERSAL_CB_OK;

fail:
    traversal_node_set_type(n, NULL, ctx);
    return TRAVERSAL_CB_ERROR;
}
Exemple #22
0
struct type * expr_typecheck(struct expr *e)
{
    if (!e)
        return type_create(TYPE_VOID, 0, 0);

    struct type *l, *r;

    switch(e->kind)
    {
    case EXPR_INTEGER_LITERAL:
        return type_create(TYPE_INTEGER, 0, 0);
    case EXPR_BOOLEAN_LITERAL:
        return type_create(TYPE_BOOLEAN, 0, 0);
    case EXPR_CHAR_LITERAL:
        return type_create(TYPE_CHARACTER, 0, 0);
    case EXPR_STRING_LITERAL:
        return type_create(TYPE_STRING, 0, 0);
    case EXPR_VARIABLE:
        return type_create(e->symbol->type->kind, 0, 0);
    case EXPR_FUNCTION_CALL:
        param_list_typecheck(e->symbol->type->params, e->right, 0);
        return type_create(e->symbol->type->subtype->kind, 0, 0);
    case EXPR_ADD:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: cannot add type ", e->line);
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" to type ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_INTEGER, 0, 0);
    case EXPR_UNARY:
        r = expr_typecheck(e->right);
        if (r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: ", e->line);
            printf("unary operator (-) cannot be applied to type ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            error_count++;
        }
        return type_create(TYPE_INTEGER, 0, 0);
    case EXPR_ASSIGN:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind == TYPE_FUNCTION || r->kind == TYPE_FUNCTION)
        {
            printf("type error: line %d: ", e->line);
            printf("= operator not compatible with functions\n");
            error_count++;
        }
        else if (!(type_compare(l, r)))
        {
            printf("type error: line %d: cannot assign type ", e->line);
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf(" to type ");
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(l->kind, 0, 0);
    case EXPR_LIST:
        l = expr_typecheck(e->left);
        expr_typecheck(e->right);
        return l;
    case EXPR_LIST_OUTER:
        r = expr_typecheck(e->right);
        return r;;
    case EXPR_SUB:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: cannot subtract type ", e->line);
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" from type ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_INTEGER, 0, 0);
    case EXPR_MUL:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: cannot multiply type ", e->line);
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" and type ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_INTEGER, 0, 0);
    case EXPR_DIV:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: cannot divide type ", e->line);
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" by type ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_INTEGER, 0, 0);
    case EXPR_MOD:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: cannot modulus type ", e->line);
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" with type ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_INTEGER, 0, 0);
    case EXPR_POW:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: cannot exponentiate type ", e->line);
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" by type ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_INTEGER, 0, 0);
    case EXPR_INCR:
        r = expr_typecheck(e->right);
        if (r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: ", e->line);
            printf("++ operator not compatible with type ");
            type_print(e->symbol->type);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;

        }
        return type_create(TYPE_INTEGER, 0, 0);
    case EXPR_DECR:
        r = expr_typecheck(e->right);
        if (r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: ", e->line);
            printf("-- operator not compatible with type ");
            type_print(e->symbol->type);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_INTEGER, 0, 0);
    case EXPR_NOT:
        r = expr_typecheck(e->right);
        if (r->kind != TYPE_BOOLEAN)
        {
            printf("type error: line %d: ", e->line);
            printf("! operator requires boolean type boolean type operand (found ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf(" )\n" );
            error_count++;
        }
        return type_create(TYPE_BOOLEAN, 0, 0);
    case EXPR_LT:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: ", e->line);
            printf("< operator not compatible with types ");
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" and ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_BOOLEAN, 0, 0);
    case EXPR_LE:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: ", e->line);
            printf("<= operator not compatible with types ");
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" and ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_BOOLEAN, 0, 0);
    case EXPR_GT:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: ", e->line);
            printf("> operator not compatible with types ");
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" and ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_BOOLEAN, 0, 0);
    case EXPR_GE:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_INTEGER || r->kind != TYPE_INTEGER)
        {
            printf("type error: line %d: ", e->line);
            printf(">= operator not compatible with types ");
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" and ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_BOOLEAN, 0, 0);
    case EXPR_EQ:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind == TYPE_ARRAY
                || l->kind == TYPE_FUNCTION
                || r->kind == TYPE_ARRAY
                || r->kind == TYPE_FUNCTION)
        {
            printf("type error: line %d: ", e->line);
            printf("== operator not compatible with types ");
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" and ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        else if (!type_compare(l, r))
        {
            printf("type error: line %d: ", e->line);
            printf("cannot use == operator on non-matching types ");
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" and ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_BOOLEAN, 0, 0);
    case EXPR_NE:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind == TYPE_ARRAY
                || l->kind == TYPE_FUNCTION
                || r->kind == TYPE_ARRAY
                || r->kind == TYPE_FUNCTION)
        {
            printf("type error: line %d:", e->line);
            printf("!= operator not compatible with types ");
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" and ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        else if (!type_compare(l, r))
        {
            printf("type error: line %d:", e->line);
            printf("cannot use != operator on non-matching types ");
            printf(" (");
            expr_print(e->left);
            printf(")");
            type_print(l);
            printf(" and ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_BOOLEAN, 0, 0);
    case EXPR_AND:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_BOOLEAN || r->kind != TYPE_BOOLEAN)
        {
            printf("type error: line %d: ", e->line);
            printf("&& operator not compatible with types ");
            type_print(l);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf(" and ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_BOOLEAN, 0, 0);
    case EXPR_OR:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_BOOLEAN || r->kind != TYPE_BOOLEAN)
        {
            printf("type error: line %d: ", e->line);
            printf("|| operator not compatible with types ");
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf(" and ");
            type_print(r);
            printf(" (");
            expr_print(e->right);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(TYPE_BOOLEAN, 0, 0);
    case EXPR_ARRAY_MEMBER:
        l = expr_typecheck(e->left);
        r = expr_typecheck(e->right);
        if (l->kind != TYPE_ARRAY && l->kind != TYPE_STRING)
        {
            printf("type error: line %d: ", e->line);
            printf("[] operator cannot follow a variable of type ");
            type_print(l);
            printf(" (");
            expr_print(e->left);
            printf(")");
            printf("\n");
            error_count++;
        }
        return type_create(type_array_type(e), 0, 0);
    case EXPR_INDEX:
        if (e->left)
        {
            l = expr_typecheck(e->left->right);
            if (l->kind != TYPE_INTEGER)
            {
                printf("type error: line %d: ", e->line);
                printf("an array index cannot be type ");
                type_print(l);
                printf(" (");
                expr_print(e->left->right);
                printf(")");
                printf("\n");
                error_count++;
            }
            expr_typecheck(e->right);
        }
        else
        {
            r = expr_typecheck(e->right);
            if (r->kind != TYPE_INTEGER)
            {
                printf("type error: line %d: ", e->line);
                printf("an array index cannot be type ");
                type_print(r);
                printf(" (");
                expr_print(e->right);
                printf(")");
                printf("\n");
                error_count++;
            }
        }
        return type_create(TYPE_INTEGER, 0, 0);
    default:
        fprintf(stderr, "cminor: ERROR! Illegal expr type found!\n");
        exit(1);
    }
}
Exemple #23
0
void stmt_typecheck(struct stmt *s, struct type *ret, int *returned) {
  if(!s) return;
  switch(s -> kind) {
    struct type *expr;
    struct expr *curr;
    case STMT_DECL:
      decl_typecheck(s -> decl);
      break;
    case STMT_EXPR:
      // need to typecheck, but don't need type
      type_delete(expr_typecheck(s -> expr));
      break;
    case STMT_IF_ELSE:
      expr = expr_typecheck(s -> expr);
      if(expr -> kind != TYPE_BOOLEAN) {
        fprintf(stderr, "TYPE_ERROR: cannot use a(n) ");
        type_fprint(stderr, expr);
        fprintf(stderr, " as the if statement expression (currently ");
        expr_fprint(stderr, s -> expr);
        fprintf(stderr, ") requires a boolean\n");
        type_error_count++;
      }
      stmt_typecheck(s -> body, ret, returned);
      stmt_typecheck(s -> else_body, ret, returned);
      type_delete(expr);
      break;
    case STMT_FOR:
      type_delete(expr_typecheck(s -> init_expr));
      expr = expr_typecheck(s -> expr);
      // need to check that the middle
      // expression is actually there
      if(expr && expr -> kind != TYPE_BOOLEAN) {
        fprintf(stderr, "TYPE_ERROR: cannot use a ");
        type_fprint(stderr, expr);
        fprintf(stderr, " as the middle expression requires a boolean (or an empty expression)\n");
        type_error_count++;
      }
      type_delete(expr);
      type_delete(expr_typecheck(s -> next_expr));
      stmt_typecheck(s -> body, ret, returned);
      break;
    case STMT_WHILE:
      break;
    case STMT_PRINT:
      curr = s -> expr;
      while(curr) {
        expr = expr_typecheck(curr);
        // pass type through new symbol
        if(!type_is_atomic(expr)) {
          fprintf(stderr, "TYPE_ERROR: cannot print (print ");
          expr_fprint(stderr, s -> expr);
          fprintf(stderr, ") a non-atomic value (");
          type_fprint(stderr, expr);
          fprintf(stderr, ")\n");
          type_error_count++;
        }
        switch(expr -> kind) {
          case TYPE_BOOLEAN:
            curr -> print_type = 1;
            break;
          case TYPE_CHARACTER:
            curr -> print_type = 2;
            break;
          case TYPE_INTEGER:
            curr -> print_type = 3;
            break;
          case TYPE_STRING:
            curr -> print_type = 4;
            break;
          case TYPE_ARRAY:
            curr -> print_type = 0;
            fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n");
            exit(1);
            break;
          case TYPE_ARRAY_DECL:
            curr -> print_type = 0;
            fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n");
            exit(1);
            break;
          case TYPE_FUNCTION:
            curr -> print_type = 0;
            fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n");
            exit(1);
            break;
          case TYPE_VOID:
            curr -> print_type = 0;
            fprintf(stderr, "Bad entry into switch on type_kind in stmt_typecheck (case STMT_PRINT)\n");
            exit(1);
            break;
        }
        type_delete(expr);
        curr = curr -> next;
      }
      break;
    case STMT_RET:
      // always set to 1
      *returned = 1;
      expr = expr_typecheck(s -> expr);
      if(!s -> expr) {
        type_delete(expr);
        expr = type_create(TYPE_VOID, 0, 0, 0);
      }
      if(!type_compare(expr, ret)) {
        fprintf(stderr, "TYPE_ERROR: the return statement (return ");
        expr_fprint(stderr, s -> expr);
        fprintf(stderr, ") does not match the function return type (");
        type_fprint(stderr, ret);
        fprintf(stderr, ")\n");
        type_error_count++;
      }
      type_delete(expr);
      break;
    case STMT_BLOCK:
      stmt_typecheck(s -> body, ret, returned);
      break;
  }
  stmt_typecheck(s -> next, ret, returned);
}
static int
parameter_lists_match(const exec_list *list_a, const exec_list *list_b)
{
   const exec_node *node_a = list_a->head;
   const exec_node *node_b = list_b->head;
   int total_score = 0;

   for (/* empty */
	; !node_a->is_tail_sentinel()
	; node_a = node_a->next, node_b = node_b->next) {
      /* If all of the parameters from the other parameter list have been
       * exhausted, the lists have different length and, by definition,
       * do not match.
       */
      if (node_b->is_tail_sentinel())
	 return -1;


      const ir_variable *const param = (ir_variable *) node_a;
      const ir_instruction *const actual = (ir_instruction *) node_b;

      /* Determine whether or not the types match.  If the types are an
       * exact match, the match score is zero.  If the types don't match
       * but the actual parameter can be coerced to the type of the declared
       * parameter, the match score is one.
       */
      int score;
      switch ((enum ir_variable_mode)(param->mode)) {
      case ir_var_auto:
      case ir_var_uniform:
      case ir_var_temporary:
	 /* These are all error conditions.  It is invalid for a parameter to
	  * a function to be declared as auto (not in, out, or inout) or
	  * as uniform.
	  */
	 assert(0);
	 return -1;

      case ir_var_in:
	 score = type_compare(param->type, actual->type);
	 break;

      case ir_var_out:
	 score = type_compare(actual->type, param->type);
	 break;

      case ir_var_inout:
	 /* Since there are no bi-directional automatic conversions (e.g.,
	  * there is int -> float but no float -> int), inout parameters must
	  * be exact matches.
	  */
	 score = (type_compare(actual->type, param->type) == 0) ? 0 : -1;
	 break;

      default:
	 assert(false);
      }

      if (score < 0)
	 return -1;

      total_score += score;
   }

   /* If all of the parameters from the other parameter list have been
    * exhausted, the lists have different length and, by definition, do not
    * match.
    */
   if (!node_b->is_tail_sentinel())
      return -1;

   return total_score;
}
Exemple #25
0
struct type * expr_typecheck(struct expr *e) {
	if(!e) return type_create(TYPE_VOID, 0, 0, 0);
	struct type *L = expr_typecheck(e->left);
	struct type *R = expr_typecheck(e->right);
	switch(e->kind) {
		case EXPR_ASSIGNMENT:
			if(L->kind == TYPE_FUNCTION){
				printf("type error: cannot use assignment operator on function ");
				expr_print(e->left);
				error_count++;
			}
			if(R->kind == TYPE_FUNCTION){
				printf("type error: cannot use assignment operator on function ");
				expr_print(e->right);
				error_count++;
			}
			if(!type_compare(L, R)){
				printf("type error: cannot assign ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf(" to ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf("\n");
				error_count++;
			}
			return L;
			break;
		case EXPR_GE:
			if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){
				printf("type error: cannot use operator >= to compare ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" and ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf(". This operator can only be used on two integers.\n");
				error_count++;
			}
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_LE:
			if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){
				printf("type error: cannot use operator <= to compare ");
				type_print(L);
				expr_print(e->left);
				printf(" and ");
				type_print(R);
				expr_print(e->right);
				printf(". This operator can only be used on two integers.\n");
				error_count++;
			}
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_GT:
			if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){
				printf("type error: cannot use operator > to compare ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" and ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf(". This operator can only be used on two integers.\n");
				error_count++;
			}
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_LT:
			if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){
				printf("type error: cannot use operator < to compare ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" and ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf(". This operator can only be used on two integers.\n");
				error_count++;
			}
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_EQ:
			if(L->kind == TYPE_ARRAY){
				printf("type error: cannot use operator == on array ");
				expr_print(e->left);
				printf("\n");
				error_count++;	
			} else if(L->kind == TYPE_FUNCTION){
				printf("type error: cannot use operator == on function ");
				expr_print(e->left);
				printf("\n");
				error_count++;	
			}
			if(R->kind == TYPE_ARRAY){
				printf("type error: cannot use operator == on array ");
				expr_print(e->right);
				printf("\n");
				error_count++;	
			} else if(R->kind == TYPE_FUNCTION){
				printf("type error: cannot use operator == on function ");
				expr_print(e->right);
				printf("\n");
				error_count++;	
			}
			if(L->kind != R->kind){
				printf("type error: cannot use operator == to compare ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" and ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_NE:
			if(L->kind == TYPE_ARRAY){
				printf("type error: cannot use operator != on array ");
				expr_print(e->left);
				printf("\n");
				error_count++;	
			} else if(L->kind == TYPE_FUNCTION){
				printf("type error: cannot use operator != on function ");
				expr_print(e->left);
				printf("\n");
				error_count++;	
			}
			if(R->kind == TYPE_ARRAY){
				printf("type error: cannot use operator != on array ");
				expr_print(e->right);
				printf("\n");
				error_count++;	
			} else if(R->kind == TYPE_FUNCTION){
				printf("type error: cannot use operator != on function ");
				expr_print(e->right);
				printf("\n");
				error_count++;	
			}
			if(L->kind != R->kind){
				printf("type error: cannot use operator != to compare ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" and ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_ADD:
			if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){
				printf("type error: cannot add ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" to ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_INTEGER, 0, 0, 0);
			break;
		case EXPR_SUB:
				
			if((L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER) && L->kind != TYPE_VOID){
				printf("type error: cannot subtract ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf(" from ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_INTEGER, 0, 0, 0);
			break;
		case EXPR_MUL:
			if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){
				printf("type error: cannot multiply ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" with ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_INTEGER, 0, 0, 0);
			break;
		case EXPR_DIV:
			if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){
				printf("type error: cannot divide ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf(" from ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_INTEGER, 0, 0, 0);
			break;
		case EXPR_MOD:
			if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){
				printf("type error: cannot perform modular division ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" mod ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_INTEGER, 0, 0, 0);
			break;
		case EXPR_POW:
			if(L->kind != TYPE_INTEGER || R->kind != TYPE_INTEGER){
				printf("type error: cannot exponentiate ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" ^ ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_INTEGER, 0, 0, 0);
			break;
		case EXPR_POSTFIX_PLUS:
			if(L->kind != TYPE_INTEGER){
				printf("type error: cannot increment ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf("\n");
				error_count++;
			} 
			if(e->left->kind != EXPR_IDENT) {
				printf("type error: cannot increment non-variable ");
				expr_print(e->left);
				printf("\n");
				error_count++;
			}	
			return type_create(TYPE_INTEGER, 0, 0, 0);
			break;
		case EXPR_POSTFIX_MINUS:
			if(L->kind != TYPE_INTEGER){
				printf("type error: cannot decrement ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf("\n");
				error_count++;
			}
			if(e->left->kind != EXPR_IDENT) {
				printf("type error: cannot decrement non-variable ");
				expr_print(e->left);
				printf("\n");
				error_count++;
			}	
			return type_create(TYPE_INTEGER, 0, 0, 0);
			break;
		case EXPR_LOGICAL_NOT:
			if(R->kind != TYPE_BOOLEAN){
				printf("type error: cannot negate non-boolean ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_LOGICAL_AND:
			if(L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN){
				printf("type error: cannot use && to compare non-boolean ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" and ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_LOGICAL_OR:
			if(L->kind != TYPE_BOOLEAN || R->kind != TYPE_BOOLEAN){
				printf("type error: cannot use && to compare non-boolean ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" and ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_INTEGER_LITERAL:
			return type_create(TYPE_INTEGER, 0, 0, 0);
			break;
		case EXPR_STRING_LITERAL:
			return type_create(TYPE_STRING, 0, 0, 0);
			break;
		case EXPR_CHAR_LITERAL:
			return type_create(TYPE_CHARACTER, 0, 0, 0);
			break;
		case EXPR_TRUE:
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_FALSE:
			return type_create(TYPE_BOOLEAN, 0, 0, 0);
			break;
		case EXPR_IDENT:
			return e->symbol->type;
			break;
		case EXPR_FCALL:
			if(L->kind != TYPE_FUNCTION) {
				printf("type error: cannot execute function call to non-function ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf("\n");
				error_count++;
			}
			function_typecheck(e->left->name, e->right, e->left->symbol->type->params, 1, function_params(e)+1);
			return L->subtype;
			break;
		case EXPR_ARRCALL:
			if(L->kind != TYPE_ARRAY) {
				printf("type error: cannot index into non-array ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf("\n");
				error_count++;
			} 
			//return the number of subtypes that the index requires
			int i;
			struct type *T = L;
			for(i = 0; i < array_call_subtypes(e->right); i++){
				T = T->subtype;
			}
			return T;
			break;
		case EXPR_ARRINDEX:
			if(L->kind != TYPE_INTEGER){
				printf("type error: cannot index an array using non-integer ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf("\n");
				error_count++;
			}
			return type_create(TYPE_INTEGER, 0, 0, 0);
			break;
		case EXPR_PARENS:
			return R;
			break;
		case EXPR_BLOCK:
			return type_create(TYPE_ARRAY, 0, R, exprs_in_block(e)-1);
			break;
		case EXPR_BLOCK_COMMA:
			if(L->kind != R->kind && R->kind != TYPE_VOID){
				printf("type error: cannot have ");
				type_print(L);
				printf(" ");
				expr_print(e->left);
				printf(" and ");
				type_print(R);
				printf(" ");
				expr_print(e->right);
				printf(" in the same expression list\n");
				error_count++;
				return type_create(TYPE_VOID,0,0,0);
			}
			return L;
			break;
		case EXPR_COMMA:
			return R;
			break;
	}
}