public override ABT.Expr GetExpr(ABT.Env env) {
// Step 1: get arguments passed into the function.
// Note that currently the arguments are not casted based on the prototype.
var args = this.Args.Select(_ => _.GetExpr(env)).ToList();
// A special case:
// If we cannot find the function prototype in the environment, make one up.
// This function returns int.
// Update the environment to add this function Type.
if ((this.Func is Variable) && env.Find((this.Func as Variable).Name).IsNone) {
// TODO: get this env used.
env = env.PushEntry(ABT.Env.EntryKind.TYPEDEF, (this.Func as Variable).Name, ABT.FunctionType.Create(new ABT.LongType(true), args.ConvertAll(_ => Tuple.Create("", _.Type)), false
)
);
}
// Step 2: get function expression.
ABT.Expr func = this.Func.GetExpr(env);
// Step 3: get the function Type.
ABT.FunctionType func_type;
switch (func.Type.Kind) {
case ABT.ExprTypeKind.FUNCTION:
func_type = func.Type as ABT.FunctionType;
break;
case ABT.ExprTypeKind.POINTER:
var ref_t = (func.Type as ABT.PointerType).RefType;
if (!(ref_t is ABT.FunctionType)) {
throw new InvalidOperationException("Expected a function pointer.");
}
func_type = ref_t as ABT.FunctionType;
break;
default:
throw new InvalidOperationException("Expected a function in function call.");
}
Int32 num_args_prototype = func_type.Args.Count;
Int32 num_args_actual = args.Count;
// If this function doesn't take varargs, make sure the number of arguments match that in the prototype.
if (!func_type.HasVarArgs && num_args_actual != num_args_prototype) {
throw new InvalidOperationException("Number of arguments mismatch.");
}
// Anyway, you can't call a function with fewer arguments than the prototype.
if (num_args_actual < num_args_prototype) {
throw new InvalidOperationException("Too few arguments.");
}
// Make implicit cast.
args = args.GetRange(0, num_args_prototype).Zip(func_type.Args,
(arg, entry) => ABT.TypeCast.MakeCast(arg, entry.type)
).Concat(args.GetRange(num_args_prototype, num_args_actual - num_args_prototype)).ToList();
return new ABT.FuncCall(func, func_type, args);
}
}