1 lobby ensureNamespace: #Shell.
3 Shell define: #MaskPattern &parents: {Cloneable} &slots: {#components}.
4 Shell define: #MaskPatternMatcher &parents: {Cloneable} &slots: {#reader. #maskPattern}.
6 Shell define: #MaskPatternFailure.
8 Shell define: #MaskPatternComponent &parents: {Cloneable}.
9 Shell define: #MaskPatternLiteral &parents: {Shell MaskPatternComponent} &slots: {#string}.
10 Shell define: #MaskPatternRange &parents: {Shell MaskPatternComponent} &slots: {#ranges. #negate}.
11 Shell define: #MaskPatternAny &parents: {Shell MaskPatternComponent}.
12 Shell define: #MaskPatternAnyOne &parents: {Shell MaskPatternComponent}.
14 mp@(Shell MaskPattern traits) newOn: s@(String traits)
16 mp components: ExtensibleArray new.
17 mp readFrom: s reader.
21 mp@(Shell MaskPattern traits) readFrom: s@(ReadStream traits)
24 matcher: mp components writer.
26 [|:token| ({$*. $?. $\[. } includes: token) /\ [prev contents isEmpty not]
27 ifTrue: [matcher nextPut: (Shell MaskPatternLiteral new `>> [string: prev contents. ]).
30 $* -> [matcher nextPut: Shell MaskPatternAny].
31 $? -> [matcher nextPut: Shell MaskPatternAnyOne].
32 $\[ -> [matcher nextPut: (mp readRange: (s upTo: $\]))].
33 } otherwise: [prev nextPut: token]].
35 prev contents isEmpty ifFalse: [matcher nextPut: (Shell MaskPatternLiteral new `>> [string: prev contents. ])].
36 mp components: matcher contents.
39 mp@(Shell MaskPattern traits) readRange: str@(String traits)
42 p: Shell MaskPatternRange new.
43 p ranges: ExtensibleArray new.
46 char2 = $^ \/ [char2 = $!] ifTrue: [p negate: True] ifFalse: [p negate: False].
52 ifTrue: [s next. p ranges addLast: char -> s next]
53 ifFalse: [p ranges addLast: char]].
57 mp@(Shell MaskPattern traits) match: str@(String traits) from: pos
59 (Shell MaskPatternMatcher new `>> [maskPattern: mp. reader: mp components reader. ]) match: str from: pos
62 mp@(Shell MaskPatternMatcher traits) match: str@(String traits) from: pos
64 "inform: 'match reader: ' ; mp reader printString ; ' pos: ' ; pos printString."
66 [|:token| (token isSameAs: Shell MaskPatternAny)
67 ifTrue: [str size downTo: pos do:
68 [|:start | ((mp new `>> [reader: mp reader clone. ]) match: str from: start) = str size
69 ifTrue: [^ str size]]]
70 ifFalse: [pos: (token match: str from: pos).
71 pos == Shell MaskPatternFailure ifTrue: [^ pos]]].
75 mp@(Shell MaskPattern traits) matches: str@(String traits)
77 match: (mp match: str from: 0).
78 match ~== Shell MaskPatternFailure /\ [match = str size]
81 p@(Shell MaskPatternAny traits) match: str@(String traits) from: pos
83 (pos to: str size - pos)
86 p@(Shell MaskPatternAnyOne traits) match: str@(String traits) from: pos
88 pos >= str size ifTrue: [Shell MaskPatternFailure] ifFalse: [pos + 1]
91 p@(Shell MaskPatternRange traits) match: str@(String traits) from: pos
93 pos >= str size \/ [p matches: (str at: pos)] ifTrue: [Shell MaskPatternFailure] ifFalse: [pos + 1]
96 p@(Shell MaskPatternLiteral traits) match: str@(String traits) from: pos
98 pos + p string size > str size ifTrue: [^ Shell MaskPatternFailure].
99 (str copyFrom: pos to: pos + p string size - 1) = p string ifTrue: [pos + p string size] ifFalse: [Shell MaskPatternFailure]
102 p@(Shell MaskPatternRange traits) matches: c@(String Character traits)
105 [| :range | ((range isSameAs: c) /\ [range = c]) \/
106 [c code between: range key code and: c code]]