Generate a Rectangle from a Specification Introduction

This challenge is inspired by Grime, my 2D pattern matching language.
Basically, you are given a "grammar" that describes two-dimensional grids of characters, and your job is to generate a grid according to the grammar.
In addition, the grid should be as small as possible in a certain weak sense.

Input

Your input is a string containing lowercase ASCII characters and the symbols | and -.
For simplicity, the input does not contain repeated lowercase characters.
The string is a specification for a class of rectangular grids of characters, and it is parsed from left to right using a stack as follows.


Given a lowercase character c, push to the stack an m&times;n grid of the character c, for any m, n &ge; 1.
Given a pipe |, pop two grids A and B from the stack (B was on top), and push the grid AB obtained by concatenating B to the right of A. This requires that A and B have equal height.
Given a hyphen -, pop two grids A and B from the stack (B was on top), and push the grid A/B obtained by concatenating B to the bottom of A. This requires that A and B have equal width.


It is guaranteed that for some choices of m and n made during the parsing process (which may be different for each letter), the input specification correctly describes some rectangle, which is left on the stack at the end.

Output

Your output is a rectangular grid of characters specified by the input.
The grid must be minimal in the sense that removing any row or column would make it invalid.
You can return a newline-separated string (with or without a trailing newline), a 2D array of characters, or an array of strings, whichever is the most convenient format.

Note that you are not required to process the input exactly as described above; the only important thing is that your output is correct.

Example

Consider the specification

par-s||e-


First, we choose to push a 1&times;2 rectangle of p, and 1&times;1 rectangles of a and r (the reason for this will be clear later).
Then, we pop the a and r rectangles, and push their vertical concatenation

a
r


Next, we push a 1&times;2 rectangle of s, pop it and the above rectangle, and push their horizontal concatenation

as
rs


Then we pop that rectangle and the p rectangle, and push their concatenation

pas
prs


Finally, we push a 3&times;1 rectangle of e, pop it and the above rectangle, and push the vertical concatenation

pas
prs
eee


This is the output of the program, or at least one of the possibilities. Notice that even though

ppas
ppas
pprs
eeee


is also generated by the specification, it is not a valid output, since many of the rows and columns could be removed.

As a more subtle example, consider

co|m|p|il|e|r|-


This specification generates the rectangle

comp
iler


which is a valid output. However, it also generates

commp
iiler


which is valid too, since no single row or column can be removed without invalidating it.

Rules

You can give a full program or a function.
The lowest byte count wins, and standard loopholes are disallowed.

Extra Test Cases

You can use these to test your program.

Input:
a
Output:
a

Input:
co|mp|l|-ex|i|f|-y|
Example output:
cccoy
mplly
exify

Input:
ja-r|g-o|ni-|ze|d-|
Example output:
jronze
arondd
ggoidd

Input:
un|co|p-yr|i|gh-t-ab|-|le-||-
Example output:
unnnnnnn
coyriggl
ppyrihhe
ppyritte
ppyriabe
K, 123 110 bytes

I used a similar approach to cardboard_box's solution.

r:{y,x#,*|y};h:{t:(#x)|#y;r[t-#x;x],'r[t-#y]y};a:{(,x .|2#y),2_ y};*(){(a[{+h[+x;+y]}]x;a[h]x;(,,y),x)"-|"?y}/


This program is a series of helper definitions followed by a tacit function which takes a string as a right argument. Reformatting for readability and assigning the final function as f:

r: {y,x#,*|y};                           / repeat last row x times
h: {t:(#x)|#y;r[t-#x;x],'r[t-#y;y]};     / append horizontal
v: {+h[+x;+y]};                          / append vertical
a: {(,x[y@1;y@0]),2_ y};                 / pop two values, concat

f: *(){:[y="-";a[v;x]; y="|";a[h;x]; (,,y),x]}/;


Use example:

  f "ja-r|g-o|ni-|ze|d-|"
("jronze"
 "aroidd"
 "ggoidd")


Tested using Kona, but it will also work in oK if you replace the : in the definition of f with a $- k5 changed the syntax of "cond".

A key point is recognizing that doing a vertical append is the transpose of the horizontal append of the transpose of both matrices. (See definition v.) I think there's still room to squeeze out a few characters here and there. If anyone is interested in a more detailed explanation I can provide one.

edit:

Updated the program at the top of this entry. Ungolfed version:

r: {y,x#,*|y};                           / repeat row x times
h: {t:(#x)|#y;r[t-#x;x],'r[t-#y;y]};     / append horizontal
v: {+h[+x;+y]};                          / append vertical
a: {(,x .|2#y),2_ y};                    / apply a concat
f: *(){(a[v]x;a[h]x;(,,y),x)"-|"?y}/;


Notable length optimizations include the use of "dot apply" in a, replacing the "cond" with list indexing in f (less efficient, but shorter) and replacing terms of the form a[b;c] into a[b]c where permitted by grouping. Since I'm no longer using "cond" or any primitives which are different between k3 and k5 this version now works in oK without modification.