summaryrefslogtreecommitdiff
path: root/appl/cmd/mash/expr.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/cmd/mash/expr.b')
-rw-r--r--appl/cmd/mash/expr.b158
1 files changed, 158 insertions, 0 deletions
diff --git a/appl/cmd/mash/expr.b b/appl/cmd/mash/expr.b
new file mode 100644
index 00000000..00e45069
--- /dev/null
+++ b/appl/cmd/mash/expr.b
@@ -0,0 +1,158 @@
+#
+# Expression evaluation.
+#
+
+#
+# Filename pattern matching.
+#
+glob(e: ref Env, s: string): (string, list of string)
+{
+ if (filepat == nil) {
+ filepat = load Filepat Filepat->PATH;
+ if (filepat == nil)
+ e.couldnot("load", Filepat->PATH);
+ }
+ l := filepat->expand(s);
+ if (l != nil)
+ return (nil, l);
+ return (s, nil);
+}
+
+#
+# RE pattern matching.
+#
+match(s1, s2: string): int
+{
+ (re, nil) := regex->compile(s2, 0);
+ return regex->execute(re, s1) != nil;
+}
+
+#
+# RE match of two lists. Two non-singleton lists never match.
+#
+match2(e: ref Env, s1: string, l1: list of string, s2: string, l2: list of string): int
+{
+ if (regex == nil) {
+ regex = load Regex Regex->PATH;
+ if (regex == nil)
+ e.couldnot("load", Regex->PATH);
+ }
+ if (s1 != nil) {
+ if (s2 != nil)
+ return match(s1, s2);
+ while (l2 != nil) {
+ if (match(s1, hd l2))
+ return 1;
+ l2 = tl l2;
+ }
+ } else if (l1 != nil) {
+ if (s2 == nil)
+ return 0;
+ while (l1 != nil) {
+ if (match(hd l1, s2))
+ return 1;
+ l1 = tl l1;
+ }
+ } else if (s2 != nil)
+ return match(nil, s2);
+ else if (l2 != nil) {
+ while (l2 != nil) {
+ if (match(nil, hd l2))
+ return 1;
+ l2 = tl l2;
+ }
+ } else
+ return 1;
+ return 0;
+}
+
+#
+# Test list equality. Same length and identical members.
+#
+eqlist(l1, l2: list of string): int
+{
+ while (l1 != nil && l2 != nil) {
+ if (hd l1 != hd l2)
+ return 0;
+ l1 = tl l1;
+ l2 = tl l2;
+ }
+ return l1 == nil && l2 == nil;
+}
+
+#
+# Equality operator.
+#
+Cmd.evaleq(c: self ref Cmd, e: ref Env): int
+{
+ (s1, l1, nil) := c.left.eeval2(e);
+ (s2, l2, nil) := c.right.eeval2(e);
+ if (s1 != nil)
+ return s1 == s2;
+ if (l1 != nil)
+ return eqlist(l1, l2);
+ return s2 == nil && l2 == nil;
+}
+
+#
+# Match operator.
+#
+Cmd.evalmatch(c: self ref Cmd, e: ref Env): int
+{
+ (s1, l1, nil) := c.left.eeval2(e);
+ (s2, l2, nil) := c.right.eeval2(e);
+ return match2(e, s1, l1, s2, l2);
+}
+
+#
+# Catenation operator.
+#
+Item.caret(i: self ref Item, e: ref Env): (string, list of string, int)
+{
+ (s1, l1, x1) := i.left.ieval2(e);
+ (s2, l2, x2) := i.right.ieval2(e);
+ return caret(s1, l1, x1, s2, l2, x2);
+}
+
+#
+# Caret of lists. A singleton distributes. Otherwise pairwise, padded with nils.
+#
+caret(s1: string, l1: list of string, x1: int, s2: string, l2: list of string, x2: int): (string, list of string, int)
+{
+ l: list of string;
+ if (s1 != nil) {
+ if (s2 != nil)
+ return (s1 + s2, nil, x1 | x2);
+ if (l2 == nil)
+ return (s1, nil, x1);
+ while (l2 != nil) {
+ l = (s1 + hd l2) :: l;
+ l2 = tl l2;
+ }
+ } else if (s2 != nil) {
+ if (l1 == nil)
+ return (s2, nil, x2);
+ while (l1 != nil) {
+ l = (hd l1 + s2) :: l;
+ l1 = tl l1;
+ }
+ } else if (l1 != nil) {
+ if (l2 == nil)
+ return (nil, l1, 0);
+ while (l1 != nil || l2 != nil) {
+ if (l1 != nil) {
+ s1 = hd l1;
+ l1 = tl l1;
+ } else
+ s1 = nil;
+ if (l2 != nil) {
+ s2 = hd l2;
+ l2 = tl l2;
+ } else
+ s2 = nil;
+ l = (s1 + s2) :: l;
+ }
+ } else if (l2 != nil)
+ return (nil, l2, 0);
+ return (nil, revstrs(l), 0);
+}