or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

character-parsing.mdcombinators.mdcore-primitives.mdindex.mdparser-generation.mdparser-operators.md

combinators.mddocs/

0

# Parser Combinators

1

2

Higher-order functions for combining and repeating parsers. These combinators enable building complex parsers from simple building blocks through composition and repetition patterns, forming the foundation of parser combinator methodology.

3

4

## Capabilities

5

6

### Repetition Combinators

7

8

Control how many times a parser should be applied, with various bounds and greedy matching behavior.

9

10

```python { .api }

11

def times(p, mint, maxt=None):

12

"""

13

Repeat a parser between mint and maxt times (greedy).

14

15

Args:

16

p (Parser): Parser to repeat

17

mint (int): Minimum number of repetitions

18

maxt (int, optional): Maximum repetitions. Defaults to mint if not specified

19

20

Returns:

21

Parser: Parser that returns list of values from p

22

23

Note:

24

Does as much matching as possible within bounds.

25

"""

26

27

def count(p, n):

28

"""

29

Parse exactly n occurrences of parser p.

30

31

Args:

32

p (Parser): Parser to repeat

33

n (int): Exact number of repetitions required

34

35

Returns:

36

Parser: Parser that returns list of exactly n values

37

38

Note:

39

If n <= 0, returns parser that succeeds with empty list.

40

"""

41

42

def many(p):

43

"""

44

Repeat a parser 0 to infinity times (greedy).

45

46

Args:

47

p (Parser): Parser to repeat

48

49

Returns:

50

Parser: Parser that returns list of values (possibly empty)

51

52

Note:

53

Always succeeds, returns empty list if no matches.

54

"""

55

56

def many1(p):

57

"""

58

Repeat a parser 1 to infinity times (greedy).

59

60

Args:

61

p (Parser): Parser to repeat

62

63

Returns:

64

Parser: Parser that returns non-empty list of values

65

66

Raises:

67

ParseError: If parser p fails on first attempt

68

"""

69

```

70

71

## Usage Examples

72

73

### Basic Repetition

74

75

```python

76

from parsec import times, count, many, many1, letter, digit, string

77

78

# Parse exactly 3 letters

79

three_letters = count(letter(), 3)

80

result = three_letters.parse("abcdef") # Returns ['a', 'b', 'c']

81

82

# Parse 2-4 letters

83

some_letters = times(letter(), 2, 4)

84

result = some_letters.parse("abcdef") # Returns ['a', 'b', 'c', 'd']

85

86

# Parse zero or more digits

87

digits = many(digit())

88

result = digits.parse("123abc") # Returns ['1', '2', '3']

89

result = digits.parse("abc") # Returns [] (empty list)

90

91

# Parse one or more letters

92

letters = many1(letter())

93

result = letters.parse("abc123") # Returns ['a', 'b', 'c']

94

try:

95

result = letters.parse("123") # Raises ParseError

96

except ParseError:

97

print("No letters found")

98

```

99

100

### Combining with Other Parsers

101

102

```python

103

from parsec import times, many, string, letter, digit

104

105

# Parse word followed by number

106

word_num = many1(letter()) + many1(digit())

107

result = word_num.parse("abc123") # Returns "abc123"

108

109

# Parse 3 letters followed by a digit

110

pattern = times(letter(), 3) >> digit()

111

result = pattern.parse("xyz1abc") # Returns '1'

112

113

# Parse comma-separated letters

114

@generate

115

def csv_letters():

116

first = yield letter()

117

rest = yield many(string(",") >> letter())

118

return [first] + rest

119

120

result = csv_letters.parse("a,b,c") # Returns ['a', 'b', 'c']

121

```

122

123

### Flexible Repetition Bounds

124

125

```python

126

from parsec import times, letter

127

128

# Minimum only - parse at least 2 letters

129

at_least_two = times(letter(), 2, float('inf'))

130

result = at_least_two.parse("abcdefgh") # Returns ['a','b','c','d','e','f','g','h']

131

132

# Zero repetitions allowed

133

zero_or_more = times(letter(), 0, 3)

134

result = zero_or_more.parse("12345") # Returns [] (empty list)

135

result = zero_or_more.parse("ab12") # Returns ['a', 'b']

136

137

# Fixed range

138

bounded = times(letter(), 2, 4)

139

result = bounded.parse("a") # ParseError - not enough matches

140

result = bounded.parse("abcd") # Returns ['a', 'b', 'c', 'd']

141

result = bounded.parse("abcdefg") # Returns ['a', 'b', 'c', 'd'] (stops at max)

142

```

143

144

### Greedy Behavior

145

146

```python

147

from parsec import many, letter, digit, string

148

149

# Greedy matching - takes as much as possible

150

parser = many(letter()) >> digit()

151

152

# This works - many() stops when it can't match more letters

153

result = parser.parse("abc1") # Returns '1'

154

155

# This also works - many() consumes all letters it can

156

result = parser.parse("abcdefg1") # Returns '1'

157

158

# many() is greedy but will backtrack to allow overall success

159

parser = many(string("ab")) >> string("ab")

160

result = parser.parse("ababab") # many() takes "abab", leaves "ab" for final parser

161

```