protected override Value?Visit(Expression.Proc proc) { // It it's cached, just return that if (compiledProcs.TryGetValue(proc, out var procVal)) { return(procVal); } WithSubcontext(() => { procVal = Builder.DefineProc(nameContext.NameOf(proc)); // Add it to the cache here to get ready for recursion compiledProcs.Add(proc, procVal); // For now we make every procedure public procVal.Visibility = Visibility.Public; // We need the return type Debug.Assert(proc.Signature.Return != null); var returnType = EvaluateType(proc.Signature.Return); procVal.Return = TranslateToLirType(returnType); // We need to compile parameters foreach (var param in proc.Signature.Parameters) { // Get the parameter type, define it in the Lir code var paramType = EvaluateType(param.Type); var lirParamType = TranslateToLirType(paramType); var paramValue = Builder.DefineParameter(lirParamType); // We make parameters mutable by making them allocate space on the stack and refer to that space var paramSpace = Builder.Alloc(lirParamType); // Copy the initial value Builder.Store(paramSpace, paramValue); if (param.Name != null) { // It has a symbol, we store the allocated space associated var symbol = SymbolTable.DefinedSymbol(param); context.Variables.Add(symbol, paramSpace); } } // Now we can compile the body Visit(proc.Body); // Add a return, if there's none and the return-type is unit if (!Builder.CurrentBasicBlock.EndsInBranch && returnType.Equals(Semantic.Types.Type.Unit)) { Builder.Ret(); } }); Debug.Assert(procVal != null); return(procVal); }