| // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | 
 |  | 
 | // Copyright 2015 The Go Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style | 
 | // license that can be found in the LICENSE file. | 
 |  | 
 | package bidi | 
 |  | 
 | import "log" | 
 |  | 
 | // This implementation is a port based on the reference implementation found at: | 
 | // http://www.unicode.org/Public/PROGRAMS/BidiReferenceJava/ | 
 | // | 
 | // described in Unicode Bidirectional Algorithm (UAX #9). | 
 | // | 
 | // Input: | 
 | // There are two levels of input to the algorithm, since clients may prefer to | 
 | // supply some information from out-of-band sources rather than relying on the | 
 | // default behavior. | 
 | // | 
 | // - Bidi class array | 
 | // - Bidi class array, with externally supplied base line direction | 
 | // | 
 | // Output: | 
 | // Output is separated into several stages: | 
 | // | 
 | //  - levels array over entire paragraph | 
 | //  - reordering array over entire paragraph | 
 | //  - levels array over line | 
 | //  - reordering array over line | 
 | // | 
 | // Note that for conformance to the Unicode Bidirectional Algorithm, | 
 | // implementations are only required to generate correct reordering and | 
 | // character directionality (odd or even levels) over a line. Generating | 
 | // identical level arrays over a line is not required. Bidi explicit format | 
 | // codes (LRE, RLE, LRO, RLO, PDF) and BN can be assigned arbitrary levels and | 
 | // positions as long as the rest of the input is properly reordered. | 
 | // | 
 | // As the algorithm is defined to operate on a single paragraph at a time, this | 
 | // implementation is written to handle single paragraphs. Thus rule P1 is | 
 | // presumed by this implementation-- the data provided to the implementation is | 
 | // assumed to be a single paragraph, and either contains no 'B' codes, or a | 
 | // single 'B' code at the end of the input. 'B' is allowed as input to | 
 | // illustrate how the algorithm assigns it a level. | 
 | // | 
 | // Also note that rules L3 and L4 depend on the rendering engine that uses the | 
 | // result of the bidi algorithm. This implementation assumes that the rendering | 
 | // engine expects combining marks in visual order (e.g. to the left of their | 
 | // base character in RTL runs) and that it adjusts the glyphs used to render | 
 | // mirrored characters that are in RTL runs so that they render appropriately. | 
 |  | 
 | // level is the embedding level of a character. Even embedding levels indicate | 
 | // left-to-right order and odd levels indicate right-to-left order. The special | 
 | // level of -1 is reserved for undefined order. | 
 | type level int8 | 
 |  | 
 | const implicitLevel level = -1 | 
 |  | 
 | // in returns if x is equal to any of the values in set. | 
 | func (c Class) in(set ...Class) bool { | 
 | 	for _, s := range set { | 
 | 		if c == s { | 
 | 			return true | 
 | 		} | 
 | 	} | 
 | 	return false | 
 | } | 
 |  | 
 | // A paragraph contains the state of a paragraph. | 
 | type paragraph struct { | 
 | 	initialTypes []Class | 
 |  | 
 | 	// Arrays of properties needed for paired bracket evaluation in N0 | 
 | 	pairTypes  []bracketType // paired Bracket types for paragraph | 
 | 	pairValues []rune        // rune for opening bracket or pbOpen and pbClose; 0 for pbNone | 
 |  | 
 | 	embeddingLevel level // default: = implicitLevel; | 
 |  | 
 | 	// at the paragraph levels | 
 | 	resultTypes  []Class | 
 | 	resultLevels []level | 
 |  | 
 | 	// Index of matching PDI for isolate initiator characters. For other | 
 | 	// characters, the value of matchingPDI will be set to -1. For isolate | 
 | 	// initiators with no matching PDI, matchingPDI will be set to the length of | 
 | 	// the input string. | 
 | 	matchingPDI []int | 
 |  | 
 | 	// Index of matching isolate initiator for PDI characters. For other | 
 | 	// characters, and for PDIs with no matching isolate initiator, the value of | 
 | 	// matchingIsolateInitiator will be set to -1. | 
 | 	matchingIsolateInitiator []int | 
 | } | 
 |  | 
 | // newParagraph initializes a paragraph. The user needs to supply a few arrays | 
 | // corresponding to the preprocessed text input. The types correspond to the | 
 | // Unicode BiDi classes for each rune. pairTypes indicates the bracket type for | 
 | // each rune. pairValues provides a unique bracket class identifier for each | 
 | // rune (suggested is the rune of the open bracket for opening and matching | 
 | // close brackets, after normalization). The embedding levels are optional, but | 
 | // may be supplied to encode embedding levels of styled text. | 
 | // | 
 | // TODO: return an error. | 
 | func newParagraph(types []Class, pairTypes []bracketType, pairValues []rune, levels level) *paragraph { | 
 | 	validateTypes(types) | 
 | 	validatePbTypes(pairTypes) | 
 | 	validatePbValues(pairValues, pairTypes) | 
 | 	validateParagraphEmbeddingLevel(levels) | 
 |  | 
 | 	p := ¶graph{ | 
 | 		initialTypes:   append([]Class(nil), types...), | 
 | 		embeddingLevel: levels, | 
 |  | 
 | 		pairTypes:  pairTypes, | 
 | 		pairValues: pairValues, | 
 |  | 
 | 		resultTypes: append([]Class(nil), types...), | 
 | 	} | 
 | 	p.run() | 
 | 	return p | 
 | } | 
 |  | 
 | func (p *paragraph) Len() int { return len(p.initialTypes) } | 
 |  | 
 | // The algorithm. Does not include line-based processing (Rules L1, L2). | 
 | // These are applied later in the line-based phase of the algorithm. | 
 | func (p *paragraph) run() { | 
 | 	p.determineMatchingIsolates() | 
 |  | 
 | 	// 1) determining the paragraph level | 
 | 	// Rule P1 is the requirement for entering this algorithm. | 
 | 	// Rules P2, P3. | 
 | 	// If no externally supplied paragraph embedding level, use default. | 
 | 	if p.embeddingLevel == implicitLevel { | 
 | 		p.embeddingLevel = p.determineParagraphEmbeddingLevel(0, p.Len()) | 
 | 	} | 
 |  | 
 | 	// Initialize result levels to paragraph embedding level. | 
 | 	p.resultLevels = make([]level, p.Len()) | 
 | 	setLevels(p.resultLevels, p.embeddingLevel) | 
 |  | 
 | 	// 2) Explicit levels and directions | 
 | 	// Rules X1-X8. | 
 | 	p.determineExplicitEmbeddingLevels() | 
 |  | 
 | 	// Rule X9. | 
 | 	// We do not remove the embeddings, the overrides, the PDFs, and the BNs | 
 | 	// from the string explicitly. But they are not copied into isolating run | 
 | 	// sequences when they are created, so they are removed for all | 
 | 	// practical purposes. | 
 |  | 
 | 	// Rule X10. | 
 | 	// Run remainder of algorithm one isolating run sequence at a time | 
 | 	for _, seq := range p.determineIsolatingRunSequences() { | 
 | 		// 3) resolving weak types | 
 | 		// Rules W1-W7. | 
 | 		seq.resolveWeakTypes() | 
 |  | 
 | 		// 4a) resolving paired brackets | 
 | 		// Rule N0 | 
 | 		resolvePairedBrackets(seq) | 
 |  | 
 | 		// 4b) resolving neutral types | 
 | 		// Rules N1-N3. | 
 | 		seq.resolveNeutralTypes() | 
 |  | 
 | 		// 5) resolving implicit embedding levels | 
 | 		// Rules I1, I2. | 
 | 		seq.resolveImplicitLevels() | 
 |  | 
 | 		// Apply the computed levels and types | 
 | 		seq.applyLevelsAndTypes() | 
 | 	} | 
 |  | 
 | 	// Assign appropriate levels to 'hide' LREs, RLEs, LROs, RLOs, PDFs, and | 
 | 	// BNs. This is for convenience, so the resulting level array will have | 
 | 	// a value for every character. | 
 | 	p.assignLevelsToCharactersRemovedByX9() | 
 | } | 
 |  | 
 | // determineMatchingIsolates determines the matching PDI for each isolate | 
 | // initiator and vice versa. | 
 | // | 
 | // Definition BD9. | 
 | // | 
 | // At the end of this function: | 
 | // | 
 | //  - The member variable matchingPDI is set to point to the index of the | 
 | //    matching PDI character for each isolate initiator character. If there is | 
 | //    no matching PDI, it is set to the length of the input text. For other | 
 | //    characters, it is set to -1. | 
 | //  - The member variable matchingIsolateInitiator is set to point to the | 
 | //    index of the matching isolate initiator character for each PDI character. | 
 | //    If there is no matching isolate initiator, or the character is not a PDI, | 
 | //    it is set to -1. | 
 | func (p *paragraph) determineMatchingIsolates() { | 
 | 	p.matchingPDI = make([]int, p.Len()) | 
 | 	p.matchingIsolateInitiator = make([]int, p.Len()) | 
 |  | 
 | 	for i := range p.matchingIsolateInitiator { | 
 | 		p.matchingIsolateInitiator[i] = -1 | 
 | 	} | 
 |  | 
 | 	for i := range p.matchingPDI { | 
 | 		p.matchingPDI[i] = -1 | 
 |  | 
 | 		if t := p.resultTypes[i]; t.in(LRI, RLI, FSI) { | 
 | 			depthCounter := 1 | 
 | 			for j := i + 1; j < p.Len(); j++ { | 
 | 				if u := p.resultTypes[j]; u.in(LRI, RLI, FSI) { | 
 | 					depthCounter++ | 
 | 				} else if u == PDI { | 
 | 					if depthCounter--; depthCounter == 0 { | 
 | 						p.matchingPDI[i] = j | 
 | 						p.matchingIsolateInitiator[j] = i | 
 | 						break | 
 | 					} | 
 | 				} | 
 | 			} | 
 | 			if p.matchingPDI[i] == -1 { | 
 | 				p.matchingPDI[i] = p.Len() | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // determineParagraphEmbeddingLevel reports the resolved paragraph direction of | 
 | // the substring limited by the given range [start, end). | 
 | // | 
 | // Determines the paragraph level based on rules P2, P3. This is also used | 
 | // in rule X5c to find if an FSI should resolve to LRI or RLI. | 
 | func (p *paragraph) determineParagraphEmbeddingLevel(start, end int) level { | 
 | 	var strongType Class = unknownClass | 
 |  | 
 | 	// Rule P2. | 
 | 	for i := start; i < end; i++ { | 
 | 		if t := p.resultTypes[i]; t.in(L, AL, R) { | 
 | 			strongType = t | 
 | 			break | 
 | 		} else if t.in(FSI, LRI, RLI) { | 
 | 			i = p.matchingPDI[i] // skip over to the matching PDI | 
 | 			if i > end { | 
 | 				log.Panic("assert (i <= end)") | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	// Rule P3. | 
 | 	switch strongType { | 
 | 	case unknownClass: // none found | 
 | 		// default embedding level when no strong types found is 0. | 
 | 		return 0 | 
 | 	case L: | 
 | 		return 0 | 
 | 	default: // AL, R | 
 | 		return 1 | 
 | 	} | 
 | } | 
 |  | 
 | const maxDepth = 125 | 
 |  | 
 | // This stack will store the embedding levels and override and isolated | 
 | // statuses | 
 | type directionalStatusStack struct { | 
 | 	stackCounter        int | 
 | 	embeddingLevelStack [maxDepth + 1]level | 
 | 	overrideStatusStack [maxDepth + 1]Class | 
 | 	isolateStatusStack  [maxDepth + 1]bool | 
 | } | 
 |  | 
 | func (s *directionalStatusStack) empty()     { s.stackCounter = 0 } | 
 | func (s *directionalStatusStack) pop()       { s.stackCounter-- } | 
 | func (s *directionalStatusStack) depth() int { return s.stackCounter } | 
 |  | 
 | func (s *directionalStatusStack) push(level level, overrideStatus Class, isolateStatus bool) { | 
 | 	s.embeddingLevelStack[s.stackCounter] = level | 
 | 	s.overrideStatusStack[s.stackCounter] = overrideStatus | 
 | 	s.isolateStatusStack[s.stackCounter] = isolateStatus | 
 | 	s.stackCounter++ | 
 | } | 
 |  | 
 | func (s *directionalStatusStack) lastEmbeddingLevel() level { | 
 | 	return s.embeddingLevelStack[s.stackCounter-1] | 
 | } | 
 |  | 
 | func (s *directionalStatusStack) lastDirectionalOverrideStatus() Class { | 
 | 	return s.overrideStatusStack[s.stackCounter-1] | 
 | } | 
 |  | 
 | func (s *directionalStatusStack) lastDirectionalIsolateStatus() bool { | 
 | 	return s.isolateStatusStack[s.stackCounter-1] | 
 | } | 
 |  | 
 | // Determine explicit levels using rules X1 - X8 | 
 | func (p *paragraph) determineExplicitEmbeddingLevels() { | 
 | 	var stack directionalStatusStack | 
 | 	var overflowIsolateCount, overflowEmbeddingCount, validIsolateCount int | 
 |  | 
 | 	// Rule X1. | 
 | 	stack.push(p.embeddingLevel, ON, false) | 
 |  | 
 | 	for i, t := range p.resultTypes { | 
 | 		// Rules X2, X3, X4, X5, X5a, X5b, X5c | 
 | 		switch t { | 
 | 		case RLE, LRE, RLO, LRO, RLI, LRI, FSI: | 
 | 			isIsolate := t.in(RLI, LRI, FSI) | 
 | 			isRTL := t.in(RLE, RLO, RLI) | 
 |  | 
 | 			// override if this is an FSI that resolves to RLI | 
 | 			if t == FSI { | 
 | 				isRTL = (p.determineParagraphEmbeddingLevel(i+1, p.matchingPDI[i]) == 1) | 
 | 			} | 
 | 			if isIsolate { | 
 | 				p.resultLevels[i] = stack.lastEmbeddingLevel() | 
 | 				if stack.lastDirectionalOverrideStatus() != ON { | 
 | 					p.resultTypes[i] = stack.lastDirectionalOverrideStatus() | 
 | 				} | 
 | 			} | 
 |  | 
 | 			var newLevel level | 
 | 			if isRTL { | 
 | 				// least greater odd | 
 | 				newLevel = (stack.lastEmbeddingLevel() + 1) | 1 | 
 | 			} else { | 
 | 				// least greater even | 
 | 				newLevel = (stack.lastEmbeddingLevel() + 2) &^ 1 | 
 | 			} | 
 |  | 
 | 			if newLevel <= maxDepth && overflowIsolateCount == 0 && overflowEmbeddingCount == 0 { | 
 | 				if isIsolate { | 
 | 					validIsolateCount++ | 
 | 				} | 
 | 				// Push new embedding level, override status, and isolated | 
 | 				// status. | 
 | 				// No check for valid stack counter, since the level check | 
 | 				// suffices. | 
 | 				switch t { | 
 | 				case LRO: | 
 | 					stack.push(newLevel, L, isIsolate) | 
 | 				case RLO: | 
 | 					stack.push(newLevel, R, isIsolate) | 
 | 				default: | 
 | 					stack.push(newLevel, ON, isIsolate) | 
 | 				} | 
 | 				// Not really part of the spec | 
 | 				if !isIsolate { | 
 | 					p.resultLevels[i] = newLevel | 
 | 				} | 
 | 			} else { | 
 | 				// This is an invalid explicit formatting character, | 
 | 				// so apply the "Otherwise" part of rules X2-X5b. | 
 | 				if isIsolate { | 
 | 					overflowIsolateCount++ | 
 | 				} else { // !isIsolate | 
 | 					if overflowIsolateCount == 0 { | 
 | 						overflowEmbeddingCount++ | 
 | 					} | 
 | 				} | 
 | 			} | 
 |  | 
 | 		// Rule X6a | 
 | 		case PDI: | 
 | 			if overflowIsolateCount > 0 { | 
 | 				overflowIsolateCount-- | 
 | 			} else if validIsolateCount == 0 { | 
 | 				// do nothing | 
 | 			} else { | 
 | 				overflowEmbeddingCount = 0 | 
 | 				for !stack.lastDirectionalIsolateStatus() { | 
 | 					stack.pop() | 
 | 				} | 
 | 				stack.pop() | 
 | 				validIsolateCount-- | 
 | 			} | 
 | 			p.resultLevels[i] = stack.lastEmbeddingLevel() | 
 |  | 
 | 		// Rule X7 | 
 | 		case PDF: | 
 | 			// Not really part of the spec | 
 | 			p.resultLevels[i] = stack.lastEmbeddingLevel() | 
 |  | 
 | 			if overflowIsolateCount > 0 { | 
 | 				// do nothing | 
 | 			} else if overflowEmbeddingCount > 0 { | 
 | 				overflowEmbeddingCount-- | 
 | 			} else if !stack.lastDirectionalIsolateStatus() && stack.depth() >= 2 { | 
 | 				stack.pop() | 
 | 			} | 
 |  | 
 | 		case B: // paragraph separator. | 
 | 			// Rule X8. | 
 |  | 
 | 			// These values are reset for clarity, in this implementation B | 
 | 			// can only occur as the last code in the array. | 
 | 			stack.empty() | 
 | 			overflowIsolateCount = 0 | 
 | 			overflowEmbeddingCount = 0 | 
 | 			validIsolateCount = 0 | 
 | 			p.resultLevels[i] = p.embeddingLevel | 
 |  | 
 | 		default: | 
 | 			p.resultLevels[i] = stack.lastEmbeddingLevel() | 
 | 			if stack.lastDirectionalOverrideStatus() != ON { | 
 | 				p.resultTypes[i] = stack.lastDirectionalOverrideStatus() | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | type isolatingRunSequence struct { | 
 | 	p *paragraph | 
 |  | 
 | 	indexes []int // indexes to the original string | 
 |  | 
 | 	types          []Class // type of each character using the index | 
 | 	resolvedLevels []level // resolved levels after application of rules | 
 | 	level          level | 
 | 	sos, eos       Class | 
 | } | 
 |  | 
 | func (i *isolatingRunSequence) Len() int { return len(i.indexes) } | 
 |  | 
 | func maxLevel(a, b level) level { | 
 | 	if a > b { | 
 | 		return a | 
 | 	} | 
 | 	return b | 
 | } | 
 |  | 
 | // Rule X10, second bullet: Determine the start-of-sequence (sos) and end-of-sequence (eos) types, | 
 | // 			 either L or R, for each isolating run sequence. | 
 | func (p *paragraph) isolatingRunSequence(indexes []int) *isolatingRunSequence { | 
 | 	length := len(indexes) | 
 | 	types := make([]Class, length) | 
 | 	for i, x := range indexes { | 
 | 		types[i] = p.resultTypes[x] | 
 | 	} | 
 |  | 
 | 	// assign level, sos and eos | 
 | 	prevChar := indexes[0] - 1 | 
 | 	for prevChar >= 0 && isRemovedByX9(p.initialTypes[prevChar]) { | 
 | 		prevChar-- | 
 | 	} | 
 | 	prevLevel := p.embeddingLevel | 
 | 	if prevChar >= 0 { | 
 | 		prevLevel = p.resultLevels[prevChar] | 
 | 	} | 
 |  | 
 | 	var succLevel level | 
 | 	lastType := types[length-1] | 
 | 	if lastType.in(LRI, RLI, FSI) { | 
 | 		succLevel = p.embeddingLevel | 
 | 	} else { | 
 | 		// the first character after the end of run sequence | 
 | 		limit := indexes[length-1] + 1 | 
 | 		for ; limit < p.Len() && isRemovedByX9(p.initialTypes[limit]); limit++ { | 
 |  | 
 | 		} | 
 | 		succLevel = p.embeddingLevel | 
 | 		if limit < p.Len() { | 
 | 			succLevel = p.resultLevels[limit] | 
 | 		} | 
 | 	} | 
 | 	level := p.resultLevels[indexes[0]] | 
 | 	return &isolatingRunSequence{ | 
 | 		p:       p, | 
 | 		indexes: indexes, | 
 | 		types:   types, | 
 | 		level:   level, | 
 | 		sos:     typeForLevel(maxLevel(prevLevel, level)), | 
 | 		eos:     typeForLevel(maxLevel(succLevel, level)), | 
 | 	} | 
 | } | 
 |  | 
 | // Resolving weak types Rules W1-W7. | 
 | // | 
 | // Note that some weak types (EN, AN) remain after this processing is | 
 | // complete. | 
 | func (s *isolatingRunSequence) resolveWeakTypes() { | 
 |  | 
 | 	// on entry, only these types remain | 
 | 	s.assertOnly(L, R, AL, EN, ES, ET, AN, CS, B, S, WS, ON, NSM, LRI, RLI, FSI, PDI) | 
 |  | 
 | 	// Rule W1. | 
 | 	// Changes all NSMs. | 
 | 	preceedingCharacterType := s.sos | 
 | 	for i, t := range s.types { | 
 | 		if t == NSM { | 
 | 			s.types[i] = preceedingCharacterType | 
 | 		} else { | 
 | 			if t.in(LRI, RLI, FSI, PDI) { | 
 | 				preceedingCharacterType = ON | 
 | 			} | 
 | 			preceedingCharacterType = t | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Rule W2. | 
 | 	// EN does not change at the start of the run, because sos != AL. | 
 | 	for i, t := range s.types { | 
 | 		if t == EN { | 
 | 			for j := i - 1; j >= 0; j-- { | 
 | 				if t := s.types[j]; t.in(L, R, AL) { | 
 | 					if t == AL { | 
 | 						s.types[i] = AN | 
 | 					} | 
 | 					break | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Rule W3. | 
 | 	for i, t := range s.types { | 
 | 		if t == AL { | 
 | 			s.types[i] = R | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Rule W4. | 
 | 	// Since there must be values on both sides for this rule to have an | 
 | 	// effect, the scan skips the first and last value. | 
 | 	// | 
 | 	// Although the scan proceeds left to right, and changes the type | 
 | 	// values in a way that would appear to affect the computations | 
 | 	// later in the scan, there is actually no problem. A change in the | 
 | 	// current value can only affect the value to its immediate right, | 
 | 	// and only affect it if it is ES or CS. But the current value can | 
 | 	// only change if the value to its right is not ES or CS. Thus | 
 | 	// either the current value will not change, or its change will have | 
 | 	// no effect on the remainder of the analysis. | 
 |  | 
 | 	for i := 1; i < s.Len()-1; i++ { | 
 | 		t := s.types[i] | 
 | 		if t == ES || t == CS { | 
 | 			prevSepType := s.types[i-1] | 
 | 			succSepType := s.types[i+1] | 
 | 			if prevSepType == EN && succSepType == EN { | 
 | 				s.types[i] = EN | 
 | 			} else if s.types[i] == CS && prevSepType == AN && succSepType == AN { | 
 | 				s.types[i] = AN | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Rule W5. | 
 | 	for i, t := range s.types { | 
 | 		if t == ET { | 
 | 			// locate end of sequence | 
 | 			runStart := i | 
 | 			runEnd := s.findRunLimit(runStart, ET) | 
 |  | 
 | 			// check values at ends of sequence | 
 | 			t := s.sos | 
 | 			if runStart > 0 { | 
 | 				t = s.types[runStart-1] | 
 | 			} | 
 | 			if t != EN { | 
 | 				t = s.eos | 
 | 				if runEnd < len(s.types) { | 
 | 					t = s.types[runEnd] | 
 | 				} | 
 | 			} | 
 | 			if t == EN { | 
 | 				setTypes(s.types[runStart:runEnd], EN) | 
 | 			} | 
 | 			// continue at end of sequence | 
 | 			i = runEnd | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Rule W6. | 
 | 	for i, t := range s.types { | 
 | 		if t.in(ES, ET, CS) { | 
 | 			s.types[i] = ON | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Rule W7. | 
 | 	for i, t := range s.types { | 
 | 		if t == EN { | 
 | 			// set default if we reach start of run | 
 | 			prevStrongType := s.sos | 
 | 			for j := i - 1; j >= 0; j-- { | 
 | 				t = s.types[j] | 
 | 				if t == L || t == R { // AL's have been changed to R | 
 | 					prevStrongType = t | 
 | 					break | 
 | 				} | 
 | 			} | 
 | 			if prevStrongType == L { | 
 | 				s.types[i] = L | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // 6) resolving neutral types Rules N1-N2. | 
 | func (s *isolatingRunSequence) resolveNeutralTypes() { | 
 |  | 
 | 	// on entry, only these types can be in resultTypes | 
 | 	s.assertOnly(L, R, EN, AN, B, S, WS, ON, RLI, LRI, FSI, PDI) | 
 |  | 
 | 	for i, t := range s.types { | 
 | 		switch t { | 
 | 		case WS, ON, B, S, RLI, LRI, FSI, PDI: | 
 | 			// find bounds of run of neutrals | 
 | 			runStart := i | 
 | 			runEnd := s.findRunLimit(runStart, B, S, WS, ON, RLI, LRI, FSI, PDI) | 
 |  | 
 | 			// determine effective types at ends of run | 
 | 			var leadType, trailType Class | 
 |  | 
 | 			// Note that the character found can only be L, R, AN, or | 
 | 			// EN. | 
 | 			if runStart == 0 { | 
 | 				leadType = s.sos | 
 | 			} else { | 
 | 				leadType = s.types[runStart-1] | 
 | 				if leadType.in(AN, EN) { | 
 | 					leadType = R | 
 | 				} | 
 | 			} | 
 | 			if runEnd == len(s.types) { | 
 | 				trailType = s.eos | 
 | 			} else { | 
 | 				trailType = s.types[runEnd] | 
 | 				if trailType.in(AN, EN) { | 
 | 					trailType = R | 
 | 				} | 
 | 			} | 
 |  | 
 | 			var resolvedType Class | 
 | 			if leadType == trailType { | 
 | 				// Rule N1. | 
 | 				resolvedType = leadType | 
 | 			} else { | 
 | 				// Rule N2. | 
 | 				// Notice the embedding level of the run is used, not | 
 | 				// the paragraph embedding level. | 
 | 				resolvedType = typeForLevel(s.level) | 
 | 			} | 
 |  | 
 | 			setTypes(s.types[runStart:runEnd], resolvedType) | 
 |  | 
 | 			// skip over run of (former) neutrals | 
 | 			i = runEnd | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func setLevels(levels []level, newLevel level) { | 
 | 	for i := range levels { | 
 | 		levels[i] = newLevel | 
 | 	} | 
 | } | 
 |  | 
 | func setTypes(types []Class, newType Class) { | 
 | 	for i := range types { | 
 | 		types[i] = newType | 
 | 	} | 
 | } | 
 |  | 
 | // 7) resolving implicit embedding levels Rules I1, I2. | 
 | func (s *isolatingRunSequence) resolveImplicitLevels() { | 
 |  | 
 | 	// on entry, only these types can be in resultTypes | 
 | 	s.assertOnly(L, R, EN, AN) | 
 |  | 
 | 	s.resolvedLevels = make([]level, len(s.types)) | 
 | 	setLevels(s.resolvedLevels, s.level) | 
 |  | 
 | 	if (s.level & 1) == 0 { // even level | 
 | 		for i, t := range s.types { | 
 | 			// Rule I1. | 
 | 			if t == L { | 
 | 				// no change | 
 | 			} else if t == R { | 
 | 				s.resolvedLevels[i] += 1 | 
 | 			} else { // t == AN || t == EN | 
 | 				s.resolvedLevels[i] += 2 | 
 | 			} | 
 | 		} | 
 | 	} else { // odd level | 
 | 		for i, t := range s.types { | 
 | 			// Rule I2. | 
 | 			if t == R { | 
 | 				// no change | 
 | 			} else { // t == L || t == AN || t == EN | 
 | 				s.resolvedLevels[i] += 1 | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | // Applies the levels and types resolved in rules W1-I2 to the | 
 | // resultLevels array. | 
 | func (s *isolatingRunSequence) applyLevelsAndTypes() { | 
 | 	for i, x := range s.indexes { | 
 | 		s.p.resultTypes[x] = s.types[i] | 
 | 		s.p.resultLevels[x] = s.resolvedLevels[i] | 
 | 	} | 
 | } | 
 |  | 
 | // Return the limit of the run consisting only of the types in validSet | 
 | // starting at index. This checks the value at index, and will return | 
 | // index if that value is not in validSet. | 
 | func (s *isolatingRunSequence) findRunLimit(index int, validSet ...Class) int { | 
 | loop: | 
 | 	for ; index < len(s.types); index++ { | 
 | 		t := s.types[index] | 
 | 		for _, valid := range validSet { | 
 | 			if t == valid { | 
 | 				continue loop | 
 | 			} | 
 | 		} | 
 | 		return index // didn't find a match in validSet | 
 | 	} | 
 | 	return len(s.types) | 
 | } | 
 |  | 
 | // Algorithm validation. Assert that all values in types are in the | 
 | // provided set. | 
 | func (s *isolatingRunSequence) assertOnly(codes ...Class) { | 
 | loop: | 
 | 	for i, t := range s.types { | 
 | 		for _, c := range codes { | 
 | 			if t == c { | 
 | 				continue loop | 
 | 			} | 
 | 		} | 
 | 		log.Panicf("invalid bidi code %v present in assertOnly at position %d", t, s.indexes[i]) | 
 | 	} | 
 | } | 
 |  | 
 | // determineLevelRuns returns an array of level runs. Each level run is | 
 | // described as an array of indexes into the input string. | 
 | // | 
 | // Determines the level runs. Rule X9 will be applied in determining the | 
 | // runs, in the way that makes sure the characters that are supposed to be | 
 | // removed are not included in the runs. | 
 | func (p *paragraph) determineLevelRuns() [][]int { | 
 | 	run := []int{} | 
 | 	allRuns := [][]int{} | 
 | 	currentLevel := implicitLevel | 
 |  | 
 | 	for i := range p.initialTypes { | 
 | 		if !isRemovedByX9(p.initialTypes[i]) { | 
 | 			if p.resultLevels[i] != currentLevel { | 
 | 				// we just encountered a new run; wrap up last run | 
 | 				if currentLevel >= 0 { // only wrap it up if there was a run | 
 | 					allRuns = append(allRuns, run) | 
 | 					run = nil | 
 | 				} | 
 | 				// Start new run | 
 | 				currentLevel = p.resultLevels[i] | 
 | 			} | 
 | 			run = append(run, i) | 
 | 		} | 
 | 	} | 
 | 	// Wrap up the final run, if any | 
 | 	if len(run) > 0 { | 
 | 		allRuns = append(allRuns, run) | 
 | 	} | 
 | 	return allRuns | 
 | } | 
 |  | 
 | // Definition BD13. Determine isolating run sequences. | 
 | func (p *paragraph) determineIsolatingRunSequences() []*isolatingRunSequence { | 
 | 	levelRuns := p.determineLevelRuns() | 
 |  | 
 | 	// Compute the run that each character belongs to | 
 | 	runForCharacter := make([]int, p.Len()) | 
 | 	for i, run := range levelRuns { | 
 | 		for _, index := range run { | 
 | 			runForCharacter[index] = i | 
 | 		} | 
 | 	} | 
 |  | 
 | 	sequences := []*isolatingRunSequence{} | 
 |  | 
 | 	var currentRunSequence []int | 
 |  | 
 | 	for _, run := range levelRuns { | 
 | 		first := run[0] | 
 | 		if p.initialTypes[first] != PDI || p.matchingIsolateInitiator[first] == -1 { | 
 | 			currentRunSequence = nil | 
 | 			// int run = i; | 
 | 			for { | 
 | 				// Copy this level run into currentRunSequence | 
 | 				currentRunSequence = append(currentRunSequence, run...) | 
 |  | 
 | 				last := currentRunSequence[len(currentRunSequence)-1] | 
 | 				lastT := p.initialTypes[last] | 
 | 				if lastT.in(LRI, RLI, FSI) && p.matchingPDI[last] != p.Len() { | 
 | 					run = levelRuns[runForCharacter[p.matchingPDI[last]]] | 
 | 				} else { | 
 | 					break | 
 | 				} | 
 | 			} | 
 | 			sequences = append(sequences, p.isolatingRunSequence(currentRunSequence)) | 
 | 		} | 
 | 	} | 
 | 	return sequences | 
 | } | 
 |  | 
 | // Assign level information to characters removed by rule X9. This is for | 
 | // ease of relating the level information to the original input data. Note | 
 | // that the levels assigned to these codes are arbitrary, they're chosen so | 
 | // as to avoid breaking level runs. | 
 | func (p *paragraph) assignLevelsToCharactersRemovedByX9() { | 
 | 	for i, t := range p.initialTypes { | 
 | 		if t.in(LRE, RLE, LRO, RLO, PDF, BN) { | 
 | 			p.resultTypes[i] = t | 
 | 			p.resultLevels[i] = -1 | 
 | 		} | 
 | 	} | 
 | 	// now propagate forward the levels information (could have | 
 | 	// propagated backward, the main thing is not to introduce a level | 
 | 	// break where one doesn't already exist). | 
 |  | 
 | 	if p.resultLevels[0] == -1 { | 
 | 		p.resultLevels[0] = p.embeddingLevel | 
 | 	} | 
 | 	for i := 1; i < len(p.initialTypes); i++ { | 
 | 		if p.resultLevels[i] == -1 { | 
 | 			p.resultLevels[i] = p.resultLevels[i-1] | 
 | 		} | 
 | 	} | 
 | 	// Embedding information is for informational purposes only so need not be | 
 | 	// adjusted. | 
 | } | 
 |  | 
 | // | 
 | // Output | 
 | // | 
 |  | 
 | // getLevels computes levels array breaking lines at offsets in linebreaks. | 
 | // Rule L1. | 
 | // | 
 | // The linebreaks array must include at least one value. The values must be | 
 | // in strictly increasing order (no duplicates) between 1 and the length of | 
 | // the text, inclusive. The last value must be the length of the text. | 
 | func (p *paragraph) getLevels(linebreaks []int) []level { | 
 | 	// Note that since the previous processing has removed all | 
 | 	// P, S, and WS values from resultTypes, the values referred to | 
 | 	// in these rules are the initial types, before any processing | 
 | 	// has been applied (including processing of overrides). | 
 | 	// | 
 | 	// This example implementation has reinserted explicit format codes | 
 | 	// and BN, in order that the levels array correspond to the | 
 | 	// initial text. Their final placement is not normative. | 
 | 	// These codes are treated like WS in this implementation, | 
 | 	// so they don't interrupt sequences of WS. | 
 |  | 
 | 	validateLineBreaks(linebreaks, p.Len()) | 
 |  | 
 | 	result := append([]level(nil), p.resultLevels...) | 
 |  | 
 | 	// don't worry about linebreaks since if there is a break within | 
 | 	// a series of WS values preceding S, the linebreak itself | 
 | 	// causes the reset. | 
 | 	for i, t := range p.initialTypes { | 
 | 		if t.in(B, S) { | 
 | 			// Rule L1, clauses one and two. | 
 | 			result[i] = p.embeddingLevel | 
 |  | 
 | 			// Rule L1, clause three. | 
 | 			for j := i - 1; j >= 0; j-- { | 
 | 				if isWhitespace(p.initialTypes[j]) { // including format codes | 
 | 					result[j] = p.embeddingLevel | 
 | 				} else { | 
 | 					break | 
 | 				} | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	// Rule L1, clause four. | 
 | 	start := 0 | 
 | 	for _, limit := range linebreaks { | 
 | 		for j := limit - 1; j >= start; j-- { | 
 | 			if isWhitespace(p.initialTypes[j]) { // including format codes | 
 | 				result[j] = p.embeddingLevel | 
 | 			} else { | 
 | 				break | 
 | 			} | 
 | 		} | 
 | 		start = limit | 
 | 	} | 
 |  | 
 | 	return result | 
 | } | 
 |  | 
 | // getReordering returns the reordering of lines from a visual index to a | 
 | // logical index for line breaks at the given offsets. | 
 | // | 
 | // Lines are concatenated from left to right. So for example, the fifth | 
 | // character from the left on the third line is | 
 | // | 
 | // 		getReordering(linebreaks)[linebreaks[1] + 4] | 
 | // | 
 | // (linebreaks[1] is the position after the last character of the second | 
 | // line, which is also the index of the first character on the third line, | 
 | // and adding four gets the fifth character from the left). | 
 | // | 
 | // The linebreaks array must include at least one value. The values must be | 
 | // in strictly increasing order (no duplicates) between 1 and the length of | 
 | // the text, inclusive. The last value must be the length of the text. | 
 | func (p *paragraph) getReordering(linebreaks []int) []int { | 
 | 	validateLineBreaks(linebreaks, p.Len()) | 
 |  | 
 | 	return computeMultilineReordering(p.getLevels(linebreaks), linebreaks) | 
 | } | 
 |  | 
 | // Return multiline reordering array for a given level array. Reordering | 
 | // does not occur across a line break. | 
 | func computeMultilineReordering(levels []level, linebreaks []int) []int { | 
 | 	result := make([]int, len(levels)) | 
 |  | 
 | 	start := 0 | 
 | 	for _, limit := range linebreaks { | 
 | 		tempLevels := make([]level, limit-start) | 
 | 		copy(tempLevels, levels[start:]) | 
 |  | 
 | 		for j, order := range computeReordering(tempLevels) { | 
 | 			result[start+j] = order + start | 
 | 		} | 
 | 		start = limit | 
 | 	} | 
 | 	return result | 
 | } | 
 |  | 
 | // Return reordering array for a given level array. This reorders a single | 
 | // line. The reordering is a visual to logical map. For example, the | 
 | // leftmost char is string.charAt(order[0]). Rule L2. | 
 | func computeReordering(levels []level) []int { | 
 | 	result := make([]int, len(levels)) | 
 | 	// initialize order | 
 | 	for i := range result { | 
 | 		result[i] = i | 
 | 	} | 
 |  | 
 | 	// locate highest level found on line. | 
 | 	// Note the rules say text, but no reordering across line bounds is | 
 | 	// performed, so this is sufficient. | 
 | 	highestLevel := level(0) | 
 | 	lowestOddLevel := level(maxDepth + 2) | 
 | 	for _, level := range levels { | 
 | 		if level > highestLevel { | 
 | 			highestLevel = level | 
 | 		} | 
 | 		if level&1 != 0 && level < lowestOddLevel { | 
 | 			lowestOddLevel = level | 
 | 		} | 
 | 	} | 
 |  | 
 | 	for level := highestLevel; level >= lowestOddLevel; level-- { | 
 | 		for i := 0; i < len(levels); i++ { | 
 | 			if levels[i] >= level { | 
 | 				// find range of text at or above this level | 
 | 				start := i | 
 | 				limit := i + 1 | 
 | 				for limit < len(levels) && levels[limit] >= level { | 
 | 					limit++ | 
 | 				} | 
 |  | 
 | 				for j, k := start, limit-1; j < k; j, k = j+1, k-1 { | 
 | 					result[j], result[k] = result[k], result[j] | 
 | 				} | 
 | 				// skip to end of level run | 
 | 				i = limit | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return result | 
 | } | 
 |  | 
 | // isWhitespace reports whether the type is considered a whitespace type for the | 
 | // line break rules. | 
 | func isWhitespace(c Class) bool { | 
 | 	switch c { | 
 | 	case LRE, RLE, LRO, RLO, PDF, LRI, RLI, FSI, PDI, BN, WS: | 
 | 		return true | 
 | 	} | 
 | 	return false | 
 | } | 
 |  | 
 | // isRemovedByX9 reports whether the type is one of the types removed in X9. | 
 | func isRemovedByX9(c Class) bool { | 
 | 	switch c { | 
 | 	case LRE, RLE, LRO, RLO, PDF, BN: | 
 | 		return true | 
 | 	} | 
 | 	return false | 
 | } | 
 |  | 
 | // typeForLevel reports the strong type (L or R) corresponding to the level. | 
 | func typeForLevel(level level) Class { | 
 | 	if (level & 0x1) == 0 { | 
 | 		return L | 
 | 	} | 
 | 	return R | 
 | } | 
 |  | 
 | // TODO: change validation to not panic | 
 |  | 
 | func validateTypes(types []Class) { | 
 | 	if len(types) == 0 { | 
 | 		log.Panic("types is null") | 
 | 	} | 
 | 	for i, t := range types[:len(types)-1] { | 
 | 		if t == B { | 
 | 			log.Panicf("B type before end of paragraph at index: %d", i) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func validateParagraphEmbeddingLevel(embeddingLevel level) { | 
 | 	if embeddingLevel != implicitLevel && | 
 | 		embeddingLevel != 0 && | 
 | 		embeddingLevel != 1 { | 
 | 		log.Panicf("illegal paragraph embedding level: %d", embeddingLevel) | 
 | 	} | 
 | } | 
 |  | 
 | func validateLineBreaks(linebreaks []int, textLength int) { | 
 | 	prev := 0 | 
 | 	for i, next := range linebreaks { | 
 | 		if next <= prev { | 
 | 			log.Panicf("bad linebreak: %d at index: %d", next, i) | 
 | 		} | 
 | 		prev = next | 
 | 	} | 
 | 	if prev != textLength { | 
 | 		log.Panicf("last linebreak was %d, want %d", prev, textLength) | 
 | 	} | 
 | } | 
 |  | 
 | func validatePbTypes(pairTypes []bracketType) { | 
 | 	if len(pairTypes) == 0 { | 
 | 		log.Panic("pairTypes is null") | 
 | 	} | 
 | 	for i, pt := range pairTypes { | 
 | 		switch pt { | 
 | 		case bpNone, bpOpen, bpClose: | 
 | 		default: | 
 | 			log.Panicf("illegal pairType value at %d: %v", i, pairTypes[i]) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func validatePbValues(pairValues []rune, pairTypes []bracketType) { | 
 | 	if pairValues == nil { | 
 | 		log.Panic("pairValues is null") | 
 | 	} | 
 | 	if len(pairTypes) != len(pairValues) { | 
 | 		log.Panic("pairTypes is different length from pairValues") | 
 | 	} | 
 | } |