-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathregularExpression.grace
92 lines (83 loc) · 3.65 KB
/
regularExpression.grace
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
dialect "standard"
// A regular exprsssion module for Grace. Implemented with JS regular expressions
method fromString(regExString) {
// Returns a new regular expression based on regEx with no modifiers
fromString(regExString) modifiers ""
}
def RegExError is public = ProgrammingError.refine "RegExError"
def SyntaxError is public = RegExError.refine "SyntaxError"
class fromString(regExString:String) modifiers(modifiers:String) {
native "js" code ‹
try {
this._value = new RegExp(var_regExString._value, var_modifiers._value);
} catch (ex) {
if (ex.name == "SyntaxError") raiseException(var_SyntaxError, ex.message);
else raiseException(var_RegExError, ex.toString());
}
›
def asString is public = "regular expression {regExString}"
method matches(text:String) {
// answers true if I match text, and false if I do not
native "js" code
‹this._value.lastIndex = 0;
return (this._value.test(var_text._value) ? GraceTrue : GraceFalse)›
}
method firstMatchingPosition(text:String) ifNone(noMatchBlock) {
// answers the index of the first substring of text that matches me
def matchPosn = native "js" code
‹this._value.lastIndex = 0;
result = new GraceNum(var_text._value.search(this._value) + 1)›
if (matchPosn == 0) then {
noMatchBlock.apply
} else {
matchPosn
}
}
method firstMatchingString(text:String) ifNone(noMatchBlock) {
// answers the first substring of text that matches me
native "js" code
‹this._value.lastIndex = 0;
const matchStr = this._value.exec(var_text._value);
if (matchStr) { return new GraceString(matchStr[0]); }›
noMatchBlock.apply
}
method allMatches(text:String) {
// answers a collection containing all the substrings of text that match me
// Each element is a matchResult(_)at(_) object that describes one match
// apb: my first implementation used the String.matchAll method, but in Chrome
// this appeared not to work.
def matchList = list.empty
native "js" code
‹const patt = this._value;
patt.lastIndex = 0; // start at the beginning
var res;
while(res = patt.exec(var_text._value)) {
request(var_matchList, "add(1)", [1],
selfRequest(this, "matchResult(1)at(1)", [1, 1],
new GraceList(res.map(elt =>
elt ? new GraceString(elt) : new GraceString(""))),
new GraceNum(res.index + 1)));
if (! patt.global) break; // not global regex, so we are done.
patt.lastIndex = res.index + 1 // otherwise, overlapping matches are missed
}›
matchList
}
class matchResult(strings) at (index) is confidential {
def stringSeq = strings
def position is public = index // the index at which the matching text starts
method group(i) {
// returns the i_th matching group, or raises BoundsError if there is none
stringSeq.at(i + 1)
}
method whole {
// returns the whole of the matching text
stringSeq.first
}
}
}
type MatchResult = interface {
position // the index at which the matching text starts
group(i) // i is an integer; returns the text matching the i_th parenthesized matching group,
// or raises BoundsError if there is no such group.
whole // returns the whole of the matching text
}