public static void Bind(BindingContext context, Function function) { if (function.Type.Return == null) throw new InvalidOperationException("Can only bind functions whose type is already bound."); var scope = new Scope(); // create a local slot for the arg if there is one if (function.Type.Parameter.Unbound != Decl.Unit) { scope.Define(context.NameGenerator.Generate(), Decl.Unit /* ignored */, false); } var binder = new FunctionBinder(function, context, scope); // bind the function function.Bind(context, binder); // make sure declared return type matches actual return type if (!DeclComparer.TypesMatch(function.Type.Return.Bound, function.Body.Bound.Type)) { if (function.Body.Bound.Type == Decl.EarlyReturn) { //### bob: should find the return expr throw new CompileException(function.Position, "Unneeded explicit \"return\"."); } else { throw new CompileException(function.Position, String.Format("{0} is declared to return {1} but is returning {2}.", function.Name, function.Type.Return.Bound, function.Body.Bound.Type)); } } }
public ICallable Instantiate(BindingContext context, IEnumerable <IBoundDecl> typeArgs, IBoundDecl argType) { bool canInfer; var genericContext = BuildContext(context, BaseType.Type.Parameter.Unbound, argType, ref typeArgs, out canInfer); // bail if we couldn't get the right number of type arguments if ((typeArgs == null) || (TypeParameters.Count != typeArgs.Count())) { return(null); } // create a new bound function type with the type arguments applied FuncType funcType = BaseType.Type.CloneFunc(); TypeBinder.Bind(genericContext, funcType); // make sure the concrete argument types of this instance match what we're actually given if (!DeclComparer.TypesMatch(funcType.Parameter.Bound, argType)) { return(null); } // create a new unbound function with the proper type Function instance = new Function(BaseType.Position, BaseType.BaseName, funcType, BaseType.ParamNames, BaseType.Body.Unbound, typeArgs, canInfer); instance.BindSearchSpace(BaseType.SearchSpace); // don't instantiate it multiple times // note that this must happen *before* the function is bound, in case the // newly instantiated generic function is recursive. context.Compiler.Functions.Add(instance); // bind it with the type arguments in context FunctionBinder.Bind(genericContext, instance); return(instance); }
public void BindAll() { // bind the types of the user functions and add them to the main table foreach (var unbound in mUnbound) { Bind(unbound); } // copy the functions to a queue because binding a function may cause generics // to be instantiated, adding to the collection. // (we don't need to worry about binding the newly added generics, because they // are bound as part of the instantiation process. binding is how the compiler // determines if a generic's type arguments are valid.) mToBind = new Queue <Function>(Functions); // bind the bodies of all of the functions while (mToBind.Count > 0) { var function = mToBind.Dequeue(); var context = new BindingContext(mCompiler, function.SearchSpace); FunctionBinder.Bind(context, function); } }
public void Bind(BindingContext context, FunctionBinder binder) { Body.Bind(context, binder); NumLocals = binder.Scope.NumVariables; }