import [type]

procedure shift (
	input command : shiftCom;
	input i : word;
	output o : word
) is
begin
	select command then
		local
			procedure shift_n (
				parameter distanceBit : byte;
				parameter distance : byte;
				input i : word;
				output o : word
			) is
			local
				type pairLeft is record
					lsw : distance bits;
					msw : 32 - distance bits
				end
				function PackWordLeft (lsw : distance bits; msw : 32 - distance bits) =
					(pairLeft {lsw, msw} as word)

				type pairRight is record
					lsw : 32 - distance bits;
					msw : distance bits
				end
				function PackWordRight (lsw : 32 - distance bits; msw : distance bits) =
					(pairRight {lsw, msw} as word)

				channel c : word

				procedure shift_body (
					output o : word
				) is 
				begin
					select i then
						local
							function i_lswLeft = (i as pairRight).lsw
							function i_mswLeft = (i as pairRight).msw
							function i_lswRight = (i as pairLeft).lsw
							function i_mswRight = (i as pairLeft).msw

							shared srl is begin o <- PackWordRight (i_mswRight (), 0) end
							shared sra is begin o <- PackWordRight (i_mswRight (), ( -1 as distance bits)) end
							shared sll is begin o <- PackWordLeft (0, i_lswLeft ()) end

						begin
							if #(command.shiftDist)[distanceBit] then
								case command.shiftType of
								  SRL then srl ()
								| SLL then sll ()
								| SRA then if #i[31] then sra () else srl () end
								end
							else o <- i
							end
						end
					end
				end
			begin
				if distance > 1 then
					shift_n (distanceBit - 1, distance / 2, c, o) ||
					shift_body (c)
				else
					shift_body (o)
				end
			end
		begin
			shift_n (4, 16, i, o)
		end
	end
end
