all repos — searchix @ main

Search engine for NixOS, nix-darwin, home-manager and NUR users

internal/index/nixattr/states.go (view raw)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//  Copyright (c) 2016 Couchbase, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// 		http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package nixattr

import (
	"unicode"
)

// States codify the classes that the parser recognizes.
type State interface {
	// is _sym_ the start character
	StartSym(sym rune) bool

	// is _sym_ a member of a class.
	// peek, the next sym on the tape, can also be used to determine a class.
	Member(sym rune, peek *rune) bool
}

func IsNonSplittingSymbolCase(sym rune) bool {
	return unicode.IsPunct(sym) && sym != '.'
}

type LowerCaseState struct{}

func (s *LowerCaseState) Member(sym rune, _ *rune) bool {
	return unicode.IsLower(sym) || IsNonSplittingSymbolCase(sym) || unicode.IsNumber(sym)
}

func (s *LowerCaseState) StartSym(sym rune) bool {
	return s.Member(sym, nil)
}

type UpperCaseState struct {
	startedCollecting bool // denotes that the start character has been read
	collectingUpper   bool // denotes if this is a class of all upper case letters
}

func (s *UpperCaseState) Member(sym rune, peek *rune) bool {
	if !unicode.IsLower(sym) && !unicode.IsUpper(sym) {
		return false
	}

	if peek != nil && unicode.IsUpper(sym) && unicode.IsLower(*peek) {
		return false
	}

	if !s.startedCollecting {
		// now we have to determine if upper-case letters are collected.
		s.startedCollecting = true
		s.collectingUpper = unicode.IsUpper(sym)

		return true
	}

	return s.collectingUpper == unicode.IsUpper(sym)
}

func (s *UpperCaseState) StartSym(sym rune) bool {
	return unicode.IsUpper(sym)
}

type NumberCaseState struct{}

func (s *NumberCaseState) Member(sym rune, _ *rune) bool {
	return unicode.IsNumber(sym) || IsNonSplittingSymbolCase(sym) || unicode.IsLower(sym)
}

func (s *NumberCaseState) StartSym(sym rune) bool {
	return s.Member(sym, nil)
}

type NonAlphaNumericCaseState struct{}

func (s *NonAlphaNumericCaseState) Member(sym rune, _ *rune) bool {
	return !unicode.IsLower(sym) && !unicode.IsUpper(sym) && !unicode.IsNumber(sym) &&
		!IsNonSplittingSymbolCase(sym)
}

func (s *NonAlphaNumericCaseState) StartSym(sym rune) bool {
	return s.Member(sym, nil)
}