xref: /inferno-os/appl/cmd/mash/expr.b (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1#
2#	Expression evaluation.
3#
4
5#
6#	Filename pattern matching.
7#
8glob(e: ref Env, s: string): (string, list of string)
9{
10	if (filepat == nil) {
11		filepat = load Filepat Filepat->PATH;
12		if (filepat == nil)
13			e.couldnot("load", Filepat->PATH);
14	}
15	l := filepat->expand(s);
16	if (l != nil)
17		return (nil, l);
18	return (s, nil);
19}
20
21#
22#	RE pattern matching.
23#
24match(s1, s2: string): int
25{
26	(re, nil) := regex->compile(s2, 0);
27	return regex->execute(re, s1) != nil;
28}
29
30#
31#	RE match of two lists.  Two non-singleton lists never match.
32#
33match2(e: ref Env, s1: string, l1: list of string, s2: string, l2: list of string): int
34{
35	if (regex == nil) {
36		regex = load Regex Regex->PATH;
37		if (regex == nil)
38			e.couldnot("load", Regex->PATH);
39	}
40	if (s1 != nil) {
41		if (s2 != nil)
42			return match(s1, s2);
43		while (l2 != nil) {
44			if (match(s1, hd l2))
45				return 1;
46			l2 = tl l2;
47		}
48	} else if (l1 != nil) {
49		if (s2 == nil)
50			return 0;
51		while (l1 != nil) {
52			if (match(hd l1, s2))
53				return 1;
54			l1 = tl l1;
55		}
56	} else if (s2 != nil)
57		return match(nil, s2);
58	else if (l2 != nil) {
59		while (l2 != nil) {
60			if (match(nil, hd l2))
61				return 1;
62			l2 = tl l2;
63		}
64	} else
65		return 1;
66	return 0;
67}
68
69#
70#	Test list equality.  Same length and identical members.
71#
72eqlist(l1, l2: list of string): int
73{
74	while (l1 != nil && l2 != nil) {
75		if (hd l1 != hd l2)
76			return 0;
77		l1 = tl l1;
78		l2 = tl l2;
79	}
80	return l1 == nil && l2 == nil;
81}
82
83#
84#	Equality operator.
85#
86Cmd.evaleq(c: self ref Cmd, e: ref Env): int
87{
88	(s1, l1, nil) := c.left.eeval2(e);
89	(s2, l2, nil) := c.right.eeval2(e);
90	if (s1 != nil)
91		return s1 == s2;
92	if (l1 != nil)
93		return eqlist(l1, l2);
94	return s2 == nil && l2 == nil;
95}
96
97#
98#	Match operator.
99#
100Cmd.evalmatch(c: self ref Cmd, e: ref Env): int
101{
102	(s1, l1, nil) := c.left.eeval2(e);
103	(s2, l2, nil) := c.right.eeval2(e);
104	return match2(e, s1, l1, s2, l2);
105}
106
107#
108#	Catenation operator.
109#
110Item.caret(i: self ref Item, e: ref Env): (string, list of string, int)
111{
112	(s1, l1, x1) := i.left.ieval2(e);
113	(s2, l2, x2) := i.right.ieval2(e);
114	return caret(s1, l1, x1, s2, l2, x2);
115}
116
117#
118#	Caret of lists.  A singleton distributes.  Otherwise pairwise, padded with nils.
119#
120caret(s1: string, l1: list of string, x1: int, s2: string, l2: list of string, x2: int): (string, list of string, int)
121{
122	l: list of string;
123	if (s1 != nil) {
124		if (s2 != nil)
125			return (s1 + s2, nil, x1 | x2);
126		if (l2 == nil)
127			return (s1, nil, x1);
128		while (l2 != nil) {
129			l = (s1 + hd l2) :: l;
130			l2 = tl l2;
131		}
132	} else if (s2 != nil) {
133		if (l1 == nil)
134			return (s2, nil, x2);
135		while (l1 != nil) {
136			l = (hd l1 + s2) :: l;
137			l1 = tl l1;
138		}
139	} else if (l1 != nil) {
140		if (l2 == nil)
141			return (nil, l1, 0);
142		while (l1 != nil || l2 != nil) {
143			if (l1 != nil) {
144				s1 = hd l1;
145				l1 = tl l1;
146			} else
147				s1 = nil;
148			if (l2 != nil) {
149				s2 = hd l2;
150				l2 = tl l2;
151			} else
152				s2 = nil;
153			l = (s1 + s2) :: l;
154		}
155	} else if (l2 != nil)
156		return (nil, l2, 0);
157	return (nil, revstrs(l), 0);
158}
159