Home | History | Annotate | Download | only in parser
      1 package parser
      2 
      3 import (
      4 	"strings"
      5 	"text/scanner"
      6 	"unicode"
      7 )
      8 
      9 // A MakeString is a string that may contain variable substitutions in it.
     10 // It can be considered as an alternating list of raw Strings and variable
     11 // substitutions, where the first and last entries in the list must be raw
     12 // Strings (possibly empty).  A MakeString that starts with a variable
     13 // will have an empty first raw string, and a MakeString that ends with a
     14 // variable will have an empty last raw string.  Two sequential Variables
     15 // will have an empty raw string between them.
     16 //
     17 // The MakeString is stored as two lists, a list of raw Strings and a list
     18 // of Variables.  The raw string list is always one longer than the variable
     19 // list.
     20 type MakeString struct {
     21 	Pos       scanner.Position
     22 	Strings   []string
     23 	Variables []Variable
     24 }
     25 
     26 func SimpleMakeString(s string, pos scanner.Position) *MakeString {
     27 	return &MakeString{
     28 		Pos:     pos,
     29 		Strings: []string{s},
     30 	}
     31 }
     32 
     33 func (ms *MakeString) appendString(s string) {
     34 	if len(ms.Strings) == 0 {
     35 		ms.Strings = []string{s}
     36 		return
     37 	} else {
     38 		ms.Strings[len(ms.Strings)-1] += s
     39 	}
     40 }
     41 
     42 func (ms *MakeString) appendVariable(v Variable) {
     43 	if len(ms.Strings) == 0 {
     44 		ms.Strings = []string{"", ""}
     45 		ms.Variables = []Variable{v}
     46 	} else {
     47 		ms.Strings = append(ms.Strings, "")
     48 		ms.Variables = append(ms.Variables, v)
     49 	}
     50 }
     51 
     52 func (ms *MakeString) appendMakeString(other *MakeString) {
     53 	last := len(ms.Strings) - 1
     54 	ms.Strings[last] += other.Strings[0]
     55 	ms.Strings = append(ms.Strings, other.Strings[1:]...)
     56 	ms.Variables = append(ms.Variables, other.Variables...)
     57 }
     58 
     59 func (ms *MakeString) Value(scope Scope) string {
     60 	if len(ms.Strings) == 0 {
     61 		return ""
     62 	} else {
     63 		ret := ms.Strings[0]
     64 		for i := range ms.Strings[1:] {
     65 			ret += ms.Variables[i].Value(scope)
     66 			ret += ms.Strings[i+1]
     67 		}
     68 		return ret
     69 	}
     70 }
     71 
     72 func (ms *MakeString) Dump() string {
     73 	if len(ms.Strings) == 0 {
     74 		return ""
     75 	} else {
     76 		ret := ms.Strings[0]
     77 		for i := range ms.Strings[1:] {
     78 			ret += ms.Variables[i].Dump()
     79 			ret += ms.Strings[i+1]
     80 		}
     81 		return ret
     82 	}
     83 }
     84 
     85 func (ms *MakeString) Const() bool {
     86 	return len(ms.Strings) <= 1
     87 }
     88 
     89 func (ms *MakeString) Empty() bool {
     90 	return len(ms.Strings) == 0 || (len(ms.Strings) == 1 && ms.Strings[0] == "")
     91 }
     92 
     93 func (ms *MakeString) Split(sep string) []*MakeString {
     94 	return ms.SplitN(sep, -1)
     95 }
     96 
     97 func (ms *MakeString) SplitN(sep string, n int) []*MakeString {
     98 	ret := []*MakeString{}
     99 
    100 	curMs := SimpleMakeString("", ms.Pos)
    101 
    102 	var i int
    103 	var s string
    104 	for i, s = range ms.Strings {
    105 		if n != 0 {
    106 			split := splitAnyN(s, sep, n)
    107 			if n != -1 {
    108 				if len(split) > n {
    109 					panic("oops!")
    110 				} else {
    111 					n -= len(split)
    112 				}
    113 			}
    114 			curMs.appendString(split[0])
    115 
    116 			for _, r := range split[1:] {
    117 				ret = append(ret, curMs)
    118 				curMs = SimpleMakeString(r, ms.Pos)
    119 			}
    120 		} else {
    121 			curMs.appendString(s)
    122 		}
    123 
    124 		if i < len(ms.Strings)-1 {
    125 			curMs.appendVariable(ms.Variables[i])
    126 		}
    127 	}
    128 
    129 	ret = append(ret, curMs)
    130 	return ret
    131 }
    132 
    133 func (ms *MakeString) TrimLeftSpaces() {
    134 	ms.Strings[0] = strings.TrimLeftFunc(ms.Strings[0], unicode.IsSpace)
    135 }
    136 
    137 func (ms *MakeString) TrimRightSpaces() {
    138 	last := len(ms.Strings) - 1
    139 	ms.Strings[last] = strings.TrimRightFunc(ms.Strings[last], unicode.IsSpace)
    140 }
    141 
    142 func (ms *MakeString) TrimRightOne() {
    143 	last := len(ms.Strings) - 1
    144 	if len(ms.Strings[last]) > 1 {
    145 		ms.Strings[last] = ms.Strings[last][0 : len(ms.Strings[last])-1]
    146 	}
    147 }
    148 
    149 func (ms *MakeString) EndsWith(ch rune) bool {
    150 	s := ms.Strings[len(ms.Strings)-1]
    151 	return s[len(s)-1] == uint8(ch)
    152 }
    153 
    154 func splitAnyN(s, sep string, n int) []string {
    155 	ret := []string{}
    156 	for n == -1 || n > 1 {
    157 		index := strings.IndexAny(s, sep)
    158 		if index >= 0 {
    159 			ret = append(ret, s[0:index])
    160 			s = s[index+1:]
    161 			if n > 0 {
    162 				n--
    163 			}
    164 		} else {
    165 			break
    166 		}
    167 	}
    168 	ret = append(ret, s)
    169 	return ret
    170 }
    171