diff --git a/notes.txt b/notes.txt index 5c1fef7..bdd63c0 100644 --- a/notes.txt +++ b/notes.txt @@ -33,6 +33,7 @@ go through the tests for docs test all docs warn nows usage in docs, e.g. spaces in symbol = [a-z]+ test error report on invalid flag +report unused definitions [optimization] try preallocate larger store chunks diff --git a/sequence.go b/sequence.go index 5e7e633..98c22b4 100644 --- a/sequence.go +++ b/sequence.go @@ -181,119 +181,7 @@ func (d *sequenceDefinition) parser() parser { return d.sparser } -func (d *sequenceDefinition) builder() builder { return d.sbuilder } - -func (d *sequenceDefinition) isCharSequence(r *registry) bool { - for i := range d.originalItems { - item := normalizeItemRange(d.originalItems[i]) - if item.Min != 1 || item.Max != 1 { - return false - } - - itemDef, _ := r.definition(d.originalItems[i].Name) - c, ok := itemDef.(*charParser) - if !ok || !c.isSingleChar() { - return false - } - } - - return true -} - -func (d *sequenceDefinition) format(r *registry, f formatFlags) string { - if d.isCharSequence(r) { - if len(d.originalItems) == 1 { - itemDef, _ := r.definition(d.originalItems[0].Name) - c, _ := itemDef.(*charParser) - return c.format(r, f) - } - - var chars []rune - for i := range d.originalItems { - itemDef, _ := r.definition(d.originalItems[i].Name) - c, _ := itemDef.(*charParser) - chars = append(chars, c.chars[0]) - } - - chars = escape(charClassEscape, []rune(charClassBanned), chars) - return string(append([]rune{'"'}, append(chars, '"')...)) - } - - var chars []rune - for i := range d.originalItems { - if len(chars) > 0 { - chars = append(chars, ' ') - } - - item := normalizeItemRange(d.originalItems[i]) - needsQuantifier := item.Min != 1 || item.Max != 1 - - itemDef, _ := r.definition(item.Name) - isSymbol := itemDef.commitType()&userDefined != 0 - - ch, isChoice := itemDef.(*choiceDefinition) - isChoiceOfMultiple := isChoice && len(ch.options) > 1 - - seq, isSequence := itemDef.(*sequenceDefinition) - isSequenceOfMultiple := isSequence && len(seq.originalItems) > 1 && !seq.isCharSequence(r) - - needsGrouping := isChoiceOfMultiple || isSequenceOfMultiple - - if isSymbol { - chars = append(chars, []rune(itemDef.nodeName())...) - } else { - if needsGrouping { - chars = append(chars, '(') - } - - chars = append(chars, []rune(itemDef.format(r, f))...) - - if needsGrouping { - chars = append(chars, ')') - } - } - - if !needsQuantifier { - continue - } - - if item.Min == 0 && item.Max == 1 { - chars = append(chars, '?') - continue - } - - if item.Min == 0 && item.Max < 0 { - chars = append(chars, '*') - continue - } - - if item.Min == 1 && item.Max < 0 { - chars = append(chars, '+') - continue - } - - chars = append(chars, '{') - - if item.Min == item.Max { - chars = append(chars, []rune(strconv.Itoa(item.Min))...) - } else { - if item.Min > 0 { - chars = append(chars, []rune(strconv.Itoa(item.Min))...) - } - - chars = append(chars, ',') - - if item.Max >= 0 { - chars = append(chars, []rune(strconv.Itoa(item.Max))...) - } - } - - chars = append(chars, '}') - } - - return string(chars) -} - +func (d *sequenceDefinition) builder() builder { return d.sbuilder } func (p *sequenceParser) nodeName() string { return p.name } func (p *sequenceParser) nodeID() int { return p.id } func (p *sequenceParser) commitType() CommitType { return p.commit } @@ -456,3 +344,114 @@ func (b *sequenceBuilder) build(c *context) ([]*Node, bool) { tokens: c.tokens, }}, true } + +func (d *sequenceDefinition) isCharSequence(r *registry) bool { + for i := range d.originalItems { + item := normalizeItemRange(d.originalItems[i]) + if item.Min != 1 || item.Max != 1 { + return false + } + + itemDef, _ := r.definition(d.originalItems[i].Name) + c, ok := itemDef.(*charParser) + if !ok || !c.isSingleChar() { + return false + } + } + + return true +} + +func (d *sequenceDefinition) format(r *registry, f formatFlags) string { + if d.isCharSequence(r) { + if len(d.originalItems) == 1 { + itemDef, _ := r.definition(d.originalItems[0].Name) + c, _ := itemDef.(*charParser) + return c.format(r, f) + } + + var chars []rune + for i := range d.originalItems { + itemDef, _ := r.definition(d.originalItems[i].Name) + c, _ := itemDef.(*charParser) + chars = append(chars, c.chars[0]) + } + + chars = escape(charClassEscape, []rune(charClassBanned), chars) + return string(append([]rune{'"'}, append(chars, '"')...)) + } + + var chars []rune + for i := range d.originalItems { + if len(chars) > 0 { + chars = append(chars, ' ') + } + + item := normalizeItemRange(d.originalItems[i]) + needsQuantifier := item.Min != 1 || item.Max != 1 + + itemDef, _ := r.definition(item.Name) + isSymbol := itemDef.commitType()&userDefined != 0 + + ch, isChoice := itemDef.(*choiceDefinition) + isChoiceOfMultiple := isChoice && len(ch.options) > 1 + + seq, isSequence := itemDef.(*sequenceDefinition) + isSequenceOfMultiple := isSequence && len(seq.originalItems) > 1 && !seq.isCharSequence(r) + + needsGrouping := isChoiceOfMultiple || isSequenceOfMultiple + + if isSymbol { + chars = append(chars, []rune(itemDef.nodeName())...) + } else { + if needsGrouping { + chars = append(chars, '(') + } + + chars = append(chars, []rune(itemDef.format(r, f))...) + + if needsGrouping { + chars = append(chars, ')') + } + } + + if !needsQuantifier { + continue + } + + if item.Min == 0 && item.Max == 1 { + chars = append(chars, '?') + continue + } + + if item.Min == 0 && item.Max < 0 { + chars = append(chars, '*') + continue + } + + if item.Min == 1 && item.Max < 0 { + chars = append(chars, '+') + continue + } + + chars = append(chars, '{') + + if item.Min == item.Max { + chars = append(chars, []rune(strconv.Itoa(item.Min))...) + } else { + if item.Min > 0 { + chars = append(chars, []rune(strconv.Itoa(item.Min))...) + } + + chars = append(chars, ',') + + if item.Max >= 0 { + chars = append(chars, []rune(strconv.Itoa(item.Max))...) + } + } + + chars = append(chars, '}') + } + + return string(chars) +}