Add support for variadic extern functions, as it turns out that you can't just specialize them with declarations. I.e., int a_func(int, ...) is different from int a_func(int, int) even if you only ever call a_func(1,2), etc. This commit is in preperation for moving to correcty variadic extern functions for the c stdlib (like printf, snprintf)

This commit is contained in:
Nathan Braswell
2016-05-19 23:17:32 -07:00
parent ce1afa45f4
commit cfcaff7887
6 changed files with 50 additions and 18 deletions

View File

@@ -75,7 +75,7 @@ typed_return = WS dec_type | ;
function = "ext" WS "fun" WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" typed_return | "fun" WS func_identifier WS template_dec WS "\(" WS opt_typed_parameter_list WS "\)" typed_return WS statement | "fun" WS func_identifier WS "\(" WS opt_typed_parameter_list WS "\)" typed_return WS statement ;
lambda = "fun" WS "\(" WS opt_typed_parameter_list WS "\)" typed_return WS statement ;
opt_typed_parameter_list = typed_parameter_list | ;
opt_typed_parameter_list = typed_parameter_list | typed_parameter_list WS "," WS "..." | ;
typed_parameter_list = typed_parameter_list WS "," WS typed_parameter | typed_parameter ;
typed_parameter = identifier WS dec_type ;

View File

@@ -285,8 +285,10 @@ obj adt_def (Object) {
return name == other.name && self_type == other.self_type && options == other.options && option_funcs == other.option_funcs && regular_funcs == other.regular_funcs
}
}
fun ast_function_ptr(name: string, type: *type, parameters: vector<*ast_node>, is_extern: bool): *ast_node {
var to_ret.construct(name, type, parameters, is_extern): function
fun ast_function_ptr(name: string, type: *type, parameters: vector<*ast_node>, is_extern: bool): *ast_node
return ast_function_ptr(name, type, parameters, is_extern, false)
fun ast_function_ptr(name: string, type: *type, parameters: vector<*ast_node>, is_extern: bool, is_variadic: bool): *ast_node {
var to_ret.construct(name, type, parameters, is_extern, is_variadic): function
var ptr = new<ast_node>()
ptr->copy_construct(&ast_node::function(to_ret))
return ptr
@@ -305,7 +307,8 @@ obj function (Object) {
var body_statement: *ast_node
var scope: map<string, vector<*ast_node>>
var is_extern: bool
fun construct(name_in: string, type_in: *type, parameters_in: vector<*ast_node>, is_extern_in: bool): *function {
var is_variadic: bool
fun construct(name_in: string, type_in: *type, parameters_in: vector<*ast_node>, is_extern_in: bool, is_variadic_in: bool): *function {
name.copy_construct(&name_in)
parameters.copy_construct(&parameters_in)
closed_variables.construct()
@@ -313,6 +316,7 @@ obj function (Object) {
type = type_in
body_statement = null<ast_node>()
is_extern = is_extern_in
is_variadic = is_variadic_in
return this
}
fun copy_construct(old: *function) {
@@ -323,6 +327,7 @@ obj function (Object) {
closed_variables.copy_construct(&old->closed_variables)
scope.copy_construct(&old->scope)
is_extern = old->is_extern
is_variadic = old->is_variadic
}
fun destruct() {
name.destruct()
@@ -335,7 +340,7 @@ obj function (Object) {
copy_construct(&other)
}
fun operator==(other: ref function): bool {
return name == name && type == other.type && parameters == other.parameters && body_statement == other.body_statement && closed_variables == other.closed_variables && is_extern == other.is_extern
return name == name && type == other.type && parameters == other.parameters && body_statement == other.body_statement && closed_variables == other.closed_variables && is_extern == other.is_extern && is_variadic == other.is_variadic
}
}
fun ast_template_ptr(name: string, syntax_node: *tree<symbol>, template_types: vector<string>, template_type_replacements: map<string, *type>, is_function: bool): *ast_node {

View File

@@ -236,8 +236,11 @@ obj ast_transformation (Object) {
error(child, "parameter type none")
parameters.add(ast_identifier_ptr(concat_symbol_tree(get_node("identifier", child)), param_type, null<ast_node>()))
})
var is_variadic = get_node("\"...\"", node) != null<tree<symbol>>()
if (is_variadic)
println(function_name + " IS VARIDIC")
// figure out function type and make function_node
var function_node = ast_function_ptr(function_name, type_ptr(parameters.map(fun(parameter: *ast_node): *type return parameter->identifier.type;), return_type), parameters, get_node("\"ext\"", node) && true)
var function_node = ast_function_ptr(function_name, type_ptr(parameters.map(fun(parameter: *ast_node): *type return parameter->identifier.type;), return_type, 0, false, is_variadic), parameters, get_node("\"ext\"", node) != null<tree<symbol>>(), is_variadic)
// fix up the enclosing_scope's
parameters.for_each(fun(n: *ast_node) n->identifier.enclosing_scope = function_node;)
// add to scope
@@ -1223,14 +1226,19 @@ fun unify_type(template_type: *tree<symbol>, param_type: *type, new_map: *map<st
}
}
fun function_satisfies_params(node: *ast_node, param_types: vector<*type>): bool {
var func_param_types = get_ast_type(node)->parameter_types
var func_type = get_ast_type(node)
var func_param_types = func_type->parameter_types
var param_string = string()
param_types.for_each(fun(t: *type) param_string += t->to_string() + ", ";)
if (func_param_types.size != param_types.size) {
if (!func_type->is_variadic && func_param_types.size != param_types.size) {
/*println(string("type sizes don't match ") + param_types.size + " with needed " + param_string)*/
return false
} else if (param_types.size < func_param_types.size) {
return false
}
for (var j = 0; j < param_types.size; j++;) {
// note we iterate over the func_param_types which will stop short if function is variadic
// just like we want
for (var j = 0; j < func_param_types.size; j++;) {
// don't care about references
if (!func_param_types[j]->equality(param_types[j], false)) {
/*println(string("types don't match ") + func_param_types[j]->to_string() + " with needed " + param_types[j]->to_string())*/

View File

@@ -226,6 +226,10 @@ obj c_generator (Object) {
if (!parameter_type->is_ref && parameter_type->indirection == 0 && (parameter_type->is_adt() || (parameter_type->is_object() && has_method(parameter_type->type_def, "destruct", vector<*type>()))))
defer_stack->top().second.push(ast_statement_ptr(make_method_call(parameter, "destruct", vector<*ast_node>())))
})
if (backing.is_variadic) {
parameter_types += ", ..."
parameters += ", ..."
}
return make_pair(type_to_c(backing.type->return_type) + " " + decorated_name + "(" + parameter_types + ");\n",
type_to_c(backing.type->return_type) + " " + decorated_name + "(" + parameters + ")")
}
@@ -858,7 +862,12 @@ obj c_generator (Object) {
// parameters.for_each(fun(param: *ast_node) {
for (var i = 0; i < parameters.size; i++;) {
var param = parameters[i]
var in_function_param_type = func_type->parameter_types[i]
var in_function_param_type = null<type>()
// grab type from param itself if we're out of param types (because variadic function)
if (i < func_type->parameter_types.size)
in_function_param_type = func_type->parameter_types[i]
else
in_function_param_type = get_ast_type(param)->clone_without_ref()
if (call_string != "")
call_string += ", "

View File

@@ -47,7 +47,7 @@ fun print(toPrint: double) {
var int_str = new<char>(how_much+2)
snprintf(int_str, (how_much+1) cast ulong, "%f", toPrint)
print(int_str)
delete(int_str)
/*delete(int_str)*/
}
fun print<T>(toPrint: T): void
print(string::to_string(toPrint))

View File

@@ -41,11 +41,12 @@ fun type_ptr(base: base_type, indirection: int): *type return type_ptr(base, ind
fun type_ptr(base: base_type, indirection: int, is_ref: bool): *type {
return new<type>()->construct(base, indirection, is_ref)
}
fun type_ptr(parameters: vector<*type>, return_type: *type): *type return type_ptr(parameters, return_type, 0, false);
fun type_ptr(parameters: vector<*type>, return_type: *type, indirection: int): *type return type_ptr(parameters, return_type, indirection, false)
fun type_ptr(parameters: vector<*type>, return_type: *type, indirection: int, is_ref: bool): *type {
return new<type>()->construct(parameters, return_type, indirection, is_ref)
}
fun type_ptr(parameters: vector<*type>, return_type: *type): *type return type_ptr(parameters, return_type, 0, false, false);
fun type_ptr(parameters: vector<*type>, return_type: *type, indirection: int): *type return type_ptr(parameters, return_type, indirection, false, false)
fun type_ptr(parameters: vector<*type>, return_type: *type, indirection: int, is_ref: bool): *type
return new<type>()->construct(parameters, return_type, indirection, is_ref, false)
fun type_ptr(parameters: vector<*type>, return_type: *type, indirection: int, is_ref: bool, is_variadic: bool): *type
return new<type>()->construct(parameters, return_type, indirection, is_ref, is_variadic)
fun type_ptr(traits: set<string>): *type {
return new<type>()->construct(traits)
@@ -54,6 +55,7 @@ fun type_ptr(traits: set<string>): *type {
obj type (Object) {
var base: base_type
var parameter_types: vector<*type>
var is_variadic: bool
var return_type: *type
var indirection: int
var type_def: *ast_node
@@ -67,6 +69,7 @@ obj type (Object) {
type_def = null<ast_node>()
traits.construct()
is_ref = false
is_variadic = false
return this
}
fun construct(traits_in: set<string>): *type {
@@ -77,6 +80,7 @@ obj type (Object) {
type_def = null<ast_node>()
traits.copy_construct(&traits_in)
is_ref = false
is_variadic = false
return this
}
fun construct(base_in: base_type, indirection_in: int, is_ref_in: bool): *type {
@@ -87,6 +91,7 @@ obj type (Object) {
type_def = null<ast_node>()
traits.construct()
is_ref = is_ref_in
is_variadic = false
return this
}
fun construct(type_def_in: *ast_node, traits_in: set<string>): *type {
@@ -100,9 +105,10 @@ obj type (Object) {
type_def = type_def_in
traits.copy_construct(&traits_in)
is_ref = false
is_variadic = false
return this
}
fun construct(parameter_types_in: vector<*type>, return_type_in: *type, indirection_in: int, is_ref_in: bool): *type {
fun construct(parameter_types_in: vector<*type>, return_type_in: *type, indirection_in: int, is_ref_in: bool, is_variadic_in: bool): *type {
base.copy_construct(&base_type::function())
parameter_types.copy_construct(&parameter_types_in)
return_type = return_type_in
@@ -110,6 +116,7 @@ obj type (Object) {
type_def = null<ast_node>()
traits.construct()
is_ref = is_ref_in
is_variadic = is_variadic_in
return this
}
fun copy_construct(old: *type) {
@@ -120,6 +127,7 @@ obj type (Object) {
type_def = old->type_def
traits.copy_construct(&old->traits)
is_ref = old->is_ref
is_variadic = old->is_variadic
}
fun operator=(other: ref type) {
destruct()
@@ -134,7 +142,7 @@ obj type (Object) {
fun operator==(other: ref type):bool return equality(other, true);
fun equality(other: *type, care_about_ref: bool):bool return equality(*other, care_about_ref);
fun equality(other: ref type, care_about_ref: bool):bool {
if (parameter_types.size != other.parameter_types.size)
if (parameter_types.size != other.parameter_types.size || is_variadic != other.is_variadic)
return false
for (var i = 0; i < parameter_types.size; i++;)
if (!deref_equality(parameter_types[i], other.parameter_types[i]))
@@ -156,6 +164,8 @@ obj type (Object) {
var indr_string = string("")
if (is_ref)
indr_string += " ref "
if (is_variadic)
indr_string += " variadic "
for (var i = 0; i < indirection; i++;) indr_string += "*"
match (base) {
base_type::none() return indr_string + string("none") + trait_string