public override ABT.Expr GetExpr(ABT.Env env) { Option<ABT.Env.Entry> entry_opt = env.Find(this.Name); if (entry_opt.IsNone) { throw new InvalidOperationException($"Cannot find variable '{this.Name}'"); } ABT.Env.Entry entry = entry_opt.Value; switch (entry.Kind) { case ABT.Env.EntryKind.TYPEDEF: throw new InvalidOperationException($"Expected a variable '{this.Name}', not a typedef."); case ABT.Env.EntryKind.ENUM: return new ABT.ConstLong(entry.Offset, env); case ABT.Env.EntryKind.FRAME: case ABT.Env.EntryKind.GLOBAL: case ABT.Env.EntryKind.STACK: return new ABT.Variable(entry.Type, this.Name, env); default: throw new InvalidOperationException($"Cannot find variable '{this.Name}'"); } }
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); }