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 ; 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 ; 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_list = typed_parameter_list WS "," WS typed_parameter | typed_parameter ;
typed_parameter = identifier WS dec_type ; 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 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 { 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 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>() var ptr = new<ast_node>()
ptr->copy_construct(&ast_node::function(to_ret)) ptr->copy_construct(&ast_node::function(to_ret))
return ptr return ptr
@@ -305,7 +307,8 @@ obj function (Object) {
var body_statement: *ast_node var body_statement: *ast_node
var scope: map<string, vector<*ast_node>> var scope: map<string, vector<*ast_node>>
var is_extern: bool 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) name.copy_construct(&name_in)
parameters.copy_construct(&parameters_in) parameters.copy_construct(&parameters_in)
closed_variables.construct() closed_variables.construct()
@@ -313,6 +316,7 @@ obj function (Object) {
type = type_in type = type_in
body_statement = null<ast_node>() body_statement = null<ast_node>()
is_extern = is_extern_in is_extern = is_extern_in
is_variadic = is_variadic_in
return this return this
} }
fun copy_construct(old: *function) { fun copy_construct(old: *function) {
@@ -323,6 +327,7 @@ obj function (Object) {
closed_variables.copy_construct(&old->closed_variables) closed_variables.copy_construct(&old->closed_variables)
scope.copy_construct(&old->scope) scope.copy_construct(&old->scope)
is_extern = old->is_extern is_extern = old->is_extern
is_variadic = old->is_variadic
} }
fun destruct() { fun destruct() {
name.destruct() name.destruct()
@@ -335,7 +340,7 @@ obj function (Object) {
copy_construct(&other) copy_construct(&other)
} }
fun operator==(other: ref function): bool { 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 { 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") error(child, "parameter type none")
parameters.add(ast_identifier_ptr(concat_symbol_tree(get_node("identifier", child)), param_type, null<ast_node>())) 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 // 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 // fix up the enclosing_scope's
parameters.for_each(fun(n: *ast_node) n->identifier.enclosing_scope = function_node;) parameters.for_each(fun(n: *ast_node) n->identifier.enclosing_scope = function_node;)
// add to scope // 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 { 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() var param_string = string()
param_types.for_each(fun(t: *type) param_string += t->to_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)*/ /*println(string("type sizes don't match ") + param_types.size + " with needed " + param_string)*/
return false 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 // don't care about references
if (!func_param_types[j]->equality(param_types[j], false)) { 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())*/ /*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>())))) 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>()))) 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", 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 + ")") 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) { // parameters.for_each(fun(param: *ast_node) {
for (var i = 0; i < parameters.size; i++;) { for (var i = 0; i < parameters.size; i++;) {
var param = parameters[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 != "") if (call_string != "")
call_string += ", " call_string += ", "

View File

@@ -47,7 +47,7 @@ fun print(toPrint: double) {
var int_str = new<char>(how_much+2) var int_str = new<char>(how_much+2)
snprintf(int_str, (how_much+1) cast ulong, "%f", toPrint) snprintf(int_str, (how_much+1) cast ulong, "%f", toPrint)
print(int_str) print(int_str)
delete(int_str) /*delete(int_str)*/
} }
fun print<T>(toPrint: T): void fun print<T>(toPrint: T): void
print(string::to_string(toPrint)) 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 { fun type_ptr(base: base_type, indirection: int, is_ref: bool): *type {
return new<type>()->construct(base, indirection, is_ref) 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): *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) 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 { 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) 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 { fun type_ptr(traits: set<string>): *type {
return new<type>()->construct(traits) return new<type>()->construct(traits)
@@ -54,6 +55,7 @@ fun type_ptr(traits: set<string>): *type {
obj type (Object) { obj type (Object) {
var base: base_type var base: base_type
var parameter_types: vector<*type> var parameter_types: vector<*type>
var is_variadic: bool
var return_type: *type var return_type: *type
var indirection: int var indirection: int
var type_def: *ast_node var type_def: *ast_node
@@ -67,6 +69,7 @@ obj type (Object) {
type_def = null<ast_node>() type_def = null<ast_node>()
traits.construct() traits.construct()
is_ref = false is_ref = false
is_variadic = false
return this return this
} }
fun construct(traits_in: set<string>): *type { fun construct(traits_in: set<string>): *type {
@@ -77,6 +80,7 @@ obj type (Object) {
type_def = null<ast_node>() type_def = null<ast_node>()
traits.copy_construct(&traits_in) traits.copy_construct(&traits_in)
is_ref = false is_ref = false
is_variadic = false
return this return this
} }
fun construct(base_in: base_type, indirection_in: int, is_ref_in: bool): *type { 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>() type_def = null<ast_node>()
traits.construct() traits.construct()
is_ref = is_ref_in is_ref = is_ref_in
is_variadic = false
return this return this
} }
fun construct(type_def_in: *ast_node, traits_in: set<string>): *type { fun construct(type_def_in: *ast_node, traits_in: set<string>): *type {
@@ -100,9 +105,10 @@ obj type (Object) {
type_def = type_def_in type_def = type_def_in
traits.copy_construct(&traits_in) traits.copy_construct(&traits_in)
is_ref = false is_ref = false
is_variadic = false
return this 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()) base.copy_construct(&base_type::function())
parameter_types.copy_construct(&parameter_types_in) parameter_types.copy_construct(&parameter_types_in)
return_type = return_type_in return_type = return_type_in
@@ -110,6 +116,7 @@ obj type (Object) {
type_def = null<ast_node>() type_def = null<ast_node>()
traits.construct() traits.construct()
is_ref = is_ref_in is_ref = is_ref_in
is_variadic = is_variadic_in
return this return this
} }
fun copy_construct(old: *type) { fun copy_construct(old: *type) {
@@ -120,6 +127,7 @@ obj type (Object) {
type_def = old->type_def type_def = old->type_def
traits.copy_construct(&old->traits) traits.copy_construct(&old->traits)
is_ref = old->is_ref is_ref = old->is_ref
is_variadic = old->is_variadic
} }
fun operator=(other: ref type) { fun operator=(other: ref type) {
destruct() destruct()
@@ -134,7 +142,7 @@ obj type (Object) {
fun operator==(other: ref type):bool return equality(other, true); 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: *type, care_about_ref: bool):bool return equality(*other, care_about_ref);
fun equality(other: ref type, care_about_ref: bool):bool { 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 return false
for (var i = 0; i < parameter_types.size; i++;) for (var i = 0; i < parameter_types.size; i++;)
if (!deref_equality(parameter_types[i], other.parameter_types[i])) if (!deref_equality(parameter_types[i], other.parameter_types[i]))
@@ -156,6 +164,8 @@ obj type (Object) {
var indr_string = string("") var indr_string = string("")
if (is_ref) if (is_ref)
indr_string += " ref " indr_string += " ref "
if (is_variadic)
indr_string += " variadic "
for (var i = 0; i < indirection; i++;) indr_string += "*" for (var i = 0; i < indirection; i++;) indr_string += "*"
match (base) { match (base) {
base_type::none() return indr_string + string("none") + trait_string base_type::none() return indr_string + string("none") + trait_string