 				
 			case "concatenation":
 				if children.count == 2 {
-					let lhsProduction = try makeProductions(from: children[0], named: name)
-					let rhsProduction = try makeProductions(from: children[1], named: name)
-					assert(lhsProduction.count == 1)
-					assert(rhsProduction.count == 1)
-					return [Production(pattern: NonTerminal(name: name), production: lhsProduction[0].production + rhsProduction[0].production)]
+					let lhsProductions = try makeProductions(from: children[0], named: name)
+					let rhsProductions = try makeProductions(from: children[1], named: name)
+					
+					return crossProduct(lhsProductions, rhsProductions).map { arg -> Production in
+						let (lhs, rhs) = arg
+						return Production(pattern: NonTerminal(name: name), production: lhs.production + rhs.production)
+					}
 				} else if children.count == 1 {
 					return try makeProductions(from: children[0], named: name)
 				} else {

					let nonTerminalName = ruleName(from: children[0])
					return [Production(pattern: NonTerminal(name: name), production: [n(nonTerminalName)])]
					
				default:
					fatalError()
				}

	productions.append(alternation)
	productions.append(contentsOf: concatenation)
	productions.append(contentsOf: expressionElement)
	productions.append(expressionGroup)
	productions.append(contentsOf: literal)
	productions.append(contentsOf: string1)
	productions.append(contentsOf: string2)
