Files @ b4a9c41d70da
Branch filter:

Location: CSY/reowolf/testdata/parser/positive/tarry.pdl

MH
Initial casting implementation

Explicit casts can be performed with the syntax 'cast<type>(input)'
and implicit casts can be performed with the syntax 'cast(input)'
where the output type is determined by inference.

To prevent casting shenanigans we only allow casting of primitive
types and of types to themselves (essentially creating a copy).
#version 100

/*
Example distributed algorithm: Tarry's algorithm.

A token passes around the network, starting at some initiator. The initiator
starts the algorithm, and when the algorithm ends the token is back again at
the initiator. The non-initiators are signaled when they receive the token
for the first time; when the token is handled traversal continues.

The network topology is defined by applications: they create an initiator or
non-initiator component, and establish bidirectional channels in between.
In this example, the whole network is created statically for simulation
purposes: there are 4 processes and some channels in between.

Ports: initiator start, initiator end, three pairs of signals.
*/

import std.reo;

composite main(in start, out end, out s1o, in s1i, out s2o, in s2i, out s3o, in s3i) {
	// Processes: p, q, r, s
	// Channels: pq, pr, qr, rs
	channel p_pq -> pq_q;
	channel q_pq -> pq_p;
	channel p_pr -> pr_r;
	channel r_pr -> pr_p;
	channel q_qr -> qr_r;
	channel r_qr -> qr_q;
	channel r_rs -> rs_s;
	channel s_rs -> rs_r;
	
	new initiator(start, end, {pq_p, pr_p}, {p_pq, p_pr});
	new noninitiator(s1o, s1i, {pq_q, qr_q}, {q_pq, q_qr});
	new noninitiator(s2o, s2i, {pr_r, rs_r}, {r_pr, r_rs});
	new noninitiator(s3o, s3i, {rs_s}, {s_rs});
}
primitive initiator(in start, out end, in[] peeri, out[] peero) {
	msg token = null;
	in[] neighbori = {};
	out[] neighboro = {};
	assert peeri.length == peero.length;
	while (true) {
		// Step 1. Initiator waits for token
		while (token == null) {
			synchronous {
				if (fires(start)) {
					token = get(start);
				}
			}
		}
		// Reset neighbors
		neighbori = peeri;
		peeri = {};
		neighboro = peero;
		peero = {};
		// Step 2. Keep sending token to processes
		while (neighbori.length > 0) {
			int idx = 0;
			// Select first channel that accepts our token
			while (token != null) {
				synchronous {
					int i = 0;
					while (i < neighboro.length) {
						if (fires(neighboro[i])) {
							put(neighboro[i], token);
							idx = i;
							token = null;
							break;
						} else i++;
					}
				}
			}
			// Eliminate from neighbor set
			peeri = {neighbori[idx]} @ peeri;
			peero = {neighboro[idx]} @ peero;
			neighbori = neighbori[0:idx] @ neighbori[idx:neighbori.length];
			neighboro = neighboro[0:idx] @ neighboro[idx:neighboro.length];
			// Step 3. Await return of token
			while (token == null) {
				synchronous {
					int i = 0;
					while (i < peeri.length + neighbori.length) {
						if (fires(peeri@neighbori[i])) {
							token = get(peeri@neighbori[i]);
							break;
						} else i++;
					}
				}
			}
		}
		// Step 4. Token is back and all neighbors visited
		while (token != null) {
			synchronous {
				if (fires(end)) {
					put(end, token);
					token = null;
				}
			}
		}
	}
}
primitive noninitiator(out start, in end, in[] peeri, out[] peero) {
	msg token = null;
	in[] neighbori = {};
	out[] neighboro = {};
	in[] parenti = {};
	out[] parento = {};
	assert peeri.length == peero.length;
	while (true) {
		int idx = 0;
		// Step 1. Await token for first time
		while (token == null) {
			synchronous {
				int i = 0;
				while (i < peeri.length) {
					if (fires(peeri[i])) {
						token = get(peeri[i]);
						idx = i;
						break;
					} else i++;
				}
			}
		}
		// Reset neighbors
		neighbori = peeri[0:idx] @ peeri[idx:peeri.length];
		neighboro = peero[0:idx] @ peero[idx:peero.length];
		parenti = {peeri[idx]};
		parento = {peero[idx]};
		peeri = {};
		peero = {};
		// Step 2. Non-initiator signals
		while (token != null) {
			synchronous {
				if (fires(end)) {
					put(end, token);
					token = null;
				}
			}
		}
		while (token == null) {
			synchronous {
				if (fires(start)) {
					token = get(start);
				}
			}
		}
		// Step 3. Keep sending token to processes
		while (neighbori.length > 0) {
			idx = 0;
			// Select first channel that accepts our token
			while (token != null) {
				synchronous {
					int i = 0;
					while (i < neighboro.length) {
						if (fires(neighboro[i])) {
							put(neighboro[i], token);
							idx = i;
							token = null;
							break;
						} else i++;
					}
				}
			}
			// Eliminate from neighbor set
			peeri = {neighbori[idx]} @ peeri;
			peero = {neighboro[idx]} @ peero;
			neighbori = neighbori[0:idx] @ neighbori[idx:neighbori.length];
			neighboro = neighboro[0:idx] @ neighboro[idx:neighboro.length];
			// Step 4. Await return of token
			while (token == null) {
				synchronous {
					int i = 0;
					while (i < peeri.length + neighbori.length) {
						if (fires(peeri@neighbori[i])) {
							token = get(peeri@neighbori[i]);
							break;
						} else i++;
					}
				}
			}
		}
		// Step 5. Token is back, pass to parent
		while (token != null) {
			synchronous {
				if (fires(parento[0])) {
					put(parento[0], token);
					token = null;
				}
			}
		}
		peeri = {parenti[0]} @ peeri;
		peero = {parento[0]} @ peero;
		parenti = {};
		parento = {};
	}
}