https://github.com/akkartik/mu/blob/master/043space.cc
  1 //: Spaces help isolate recipes from each other. You can create them at will,
  2 //: and all addresses in arguments are implicitly based on the 'default-space'
  3 //: (unless they have the /raw property)
  4 //:
  5 //: Spaces are often called 'scopes' in other languages. Stack frames are a
  6 //: limited form of space that can't outlive callers.
  7 //:
  8 //: Warning: messing with 'default-space' can corrupt memory. Don't share
  9 //: default-space between recipes. Later we'll see how to chain spaces safely.
 10 //:
 11 //: Tests in this layer can write to a location as part of one type, and read
 12 //: it as part of another. This is unsafe and insecure, and we'll stop doing
 13 //: this once we switch to variable names.
 14 
 15 //: Under the hood, a space is an array of locations in memory.
 16 :(before "End Mu Types Initialization")
 17 put(Type_abbreviations, "space", new_type_tree("address:array:location"));
 18 
 19 :(scenario set_default_space)
 20 def main [
 21   # prepare default-space address
 22   10:num/alloc-id, 11:num <- copy 0, 1000
 23   # prepare default-space payload
 24   1000:num <- copy 0  # alloc id of payload
 25   1001:num <- copy 5  # length
 26   # actual start of this recipe
 27   default-space:space <- copy 10:&:@:location
 28   # if default-space is 1000, then:
 29   #   1000: alloc id
 30   #   1001: array size
 31   #   1002: location 0 (space for the chaining slot; described later; often unused)
 32   #   1003: location 1 (space for the chaining slot; described later; often unused)
 33   #   1004: local 2 (assuming it is a scalar)
 34   2:num <- copy 93
 35 ]
 36 +mem: storing 93 in location 1004
 37 
 38 :(scenario lookup_sidesteps_default_space)
 39 def main [
 40   # prepare default-space address
 41   10:num/alloc-id, 11:num <- copy 0, 1000
 42   # prepare default-space payload
 43   1000:num <- copy 0  # alloc id of payload
 44   1001:num <- copy 5  # length
 45   # prepare payload outside the local scope
 46   2000:num/alloc-id, 2001:num <- copy 0, 34
 47   # actual start of this recipe
 48   default-space:space <- copy 10:&:@:location
 49   # a local address
 50   2:num, 3:num <- copy 0, 2000
 51   20:num/raw <- copy *2:&:num
 52 ]
 53 +mem: storing 2000 in location 1005
 54 +mem: storing 34 in location 20
 55 
 56 //: precondition: disable name conversion for 'default-space'
 57 
 58 :(scenarios transform)
 59 :(scenario convert_names_passes_default_space)
 60 % Hide_errors = true;
 61 def main [
 62   default-space:num <- copy 0
 63   x:num <- copy 1
 64 ]
 65 +name: assign x 2
 66 -name: assign default-space 1
 67 -name: assign default-space 2
 68 :(scenarios run)
 69 
 70 :(before "End is_disqualified Special-cases")
 71 if (x.name == "default-space")
 72   x.initialized = true;
 73 :(before "End is_special_name Special-cases")
 74 if (s == "default-space") return true;
 75 
 76 //: core implementation
 77 
 78 :(before "End call Fields")
 79 int default_space;
 80 :(before "End call Constructor")
 81 default_space = 0;
 82 
 83 :(before "Begin canonize(x) Lookups")
 84 absolutize(x);
 85 :(code)
 86 void absolutize(reagent& x) {
 87   if (is_raw(x) || is_dummy(x)) return;
 88   if (x.name == "default-space") return;
 89   if (!x.initialized)
 90     raise << to_original_string(current_instruction()) << ": reagent not initialized: '" << x.original_string << "'\n" << end();
 91   x.set_value(address(x.value, space_base(x)));
 92   x.properties.push_back(pair<string, string_tree*>("raw", NULL));
 93   assert(is_raw(x));
 94 }
 95 
 96 //: hook replaced in a later layer
 97 int space_base(const reagent& x) {
 98   return current_call().default_space ? (current_call().default_space + /*skip alloc id*/1) : 0;
 99 }
100 
101 int address(int offset, int base) {
102   assert(offset >= 0);
103   if (base == 0) return offset;  // raw
104   int size = get_or_insert(Memory, base);
105   if (offset >= size) {
106     // todo: test
107     raise << current_recipe_name() << ": location " << offset << " is out of bounds " << size << " at " << base << '\n' << end();
108     DUMP("");
109     exit(1);
110     return 0;
111   }
112   return base + /*skip length*/1 + offset;
113 }
114 
115 //: reads and writes to the 'default-space' variable have special behavior
116 
117 :(after "Begin Preprocess write_memory(x, data)")
118 if (x.name == "default-space") {
119   if (!is_mu_space(x))
120     raise << maybe(current_recipe_name()) << "'default-space' should be of type address:array:location, but is " << to_string(x.type) << '\n' << end();
121   if (SIZE(data) != 2)
122     raise << maybe(current_recipe_name()) << "'default-space' getting data from non-address\n" << end();
123   current_call().default_space = data.at(/*skip alloc id*/1);
124   return;
125 }
126 :(code)
127 bool is_mu_space(reagent/*copy*/ x) {
128   canonize_type(x);
129   if (!is_compound_type_starting_with(x.type, "add
package imap

import (
	"github.com/emersion/go-imap"

	"git.sr.ht/~rjarry/aerc/models"
	"git.sr.ht/~rjarry/aerc/worker/types"
)

func (imapw *IMAPWorker) handleListDirectories(msg *types.ListDirectories) {
	mailboxes := make(chan *imap.MailboxInfo)
	imapw.worker.Logger.Println("Listing mailboxes")
	done := make(chan interface{})

	go func() {
		for mbox := range mailboxes {
			if !canOpen(mbox) {
				// no need to pass this to handlers if it can't be opened
				continue
			}
			imapw.worker.PostMessage(&types.Directory{
				Message: types.RespondTo(msg),
				Dir: &models.Directory{
					Name:       mbox.Name,
					Attributes: mbox.Attributes,
				},
			}, nil)
		}
		done <- nil
	}()

	if err := imapw.client.List("", "*", mailboxes); err != nil {
		<-done
		imapw.worker.PostMessage(&types.Error{
			Message: types.RespondTo(msg),
			Error:   err,
		}, nil)
	} else {
		<-done
		imapw.worker.PostMessage(
			&types.Done{types.RespondTo(msg)}, nil)
	}
}

func canOpen(mbox *imap.MailboxInfo) bool {
	for _, attr := range mbox.Attributes {
		if attr == imap.NoSelectAttr {
			return false
		}
	}
	return true
}

func (imapw *IMAPWorker) handleSearchDirectory(msg *types.SearchDirectory) {
	emitError := func(err error) {
		imapw.worker.PostMessage(&types.Error{
			Message: types.RespondTo(msg),
			Error:   err,
		}, nil)
	}

	imapw.worker.Logger.Println("Executing search")
	criteria, err := parseSearch(msg.Argv)
	if err != nil {
		emitError(err)
		return
	}

	uids, err := imapw.client.UidSearch(criteria)
	if err != nil {
		emitError(err)
		return
	}

	imapw.worker.PostMessage(&types.SearchResults{
		Message: types.RespondTo(msg),
		Uids:    uids,
	}, nil)

}
e allocated for default-space in recipe " << current_recipe_name() << "; are you using names?\n" << end(); 246 return result; 247 } 248 :(after "Begin Preprocess write_memory(x, data)") 249 if (x.name == "number-of-locals") { 250 raise << maybe(current_recipe_name()) << "can't write to special name 'number-of-locals'\n" << end(); 251 return; 252 } 253 254 //:: all recipes must set default-space one way or another 255 256 :(before "End Globals") 257 bool Hide_missing_default_space_errors = true; 258 :(before "End Checks") 259 Transform.push_back(check_default_space); // idempotent 260 :(code) 261 void check_default_space(const recipe_ordinal r) { 262 if (Hide_missing_default_space_errors) return; // skip previous core tests; this is only for Mu code 263 const recipe& caller = get(Recipe, r); 264 // End check_default_space Special-cases 265 // assume recipes with only numeric addresses know what they're doing (usually tests) 266 if (!contains_non_special_name(r)) return; 267 trace(9991, "transform") << "--- check that recipe " << caller.name << " sets default-space" << end(); 268 if (caller.steps.empty()) return; 269 if (!starts_by_setting_default_space(caller)) 270 raise << caller.name << " does not seem to start with 'local-scope' or 'default-space'\n" << end(); 271 } 272 bool starts_by_setting_default_space(const recipe& r) { 273 return !r.steps.empty() 274 && !r.steps.at(0).products.empty() 275 && r.steps.at(0).products.at(0).name == "default-space"; 276 } 277 278 :(after "Load Mu Prelude") 279 Hide_missing_default_space_errors = false; 280 :(after "Test Runs") 281 Hide_missing_default_space_errors = true; 282 :(after "Running Main") 283 Hide_missing_default_space_errors = false; 284 285 :(code) 286 bool contains_non_special_name(const recipe_ordinal r) { 287 for (map<string, int>::iterator p = Name[r].begin(); p != Name[r].end(); ++p) { 288 if (p->first.empty()) continue; 289 if (p->first.find("stash_") == 0) continue; // generated by rewrite_stashes_to_text (cross-layer) 290 if (!is_special_name(p->first)) 291 return true; 292 } 293 return false; 294 }