OSDN Git Service

Thanos did someting
[bytom/vapor.git] / vendor / golang.org / x / text / unicode / bidi / core.go
diff --git a/vendor/golang.org/x/text/unicode/bidi/core.go b/vendor/golang.org/x/text/unicode/bidi/core.go
deleted file mode 100644 (file)
index d4c1399..0000000
+++ /dev/null
@@ -1,1058 +0,0 @@
-// 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 := &paragraph{
-               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")
-       }
-}