commit 84bfbcb

shrub  ·  2026-10-15 21:03:34 +0000 UTC
parent b34769b
handle variables
4 files changed,  +115, -13
+27, -5
 1@@ -5,6 +5,15 @@ staload "parse.sats"
 2 
 3 exception ParseErr of ()
 4 
 5+fun parts_free(p: List0_vt(stringpart)): void =
 6+    case+ p of
 7+    | ~nil_vt ()           => ()
 8+    | ~cons_vt(part, rest) => (
 9+        (case+ part of
10+        | ~Literal (text) => strptr_free(text)
11+        | ~Variable(text) => strptr_free(text) );
12+        parts_free(rest) )
13+
14 fun bindings_free(b: List0_vt(binding)): void =
15     case+ b of 
16     (* tilde means destroy the list wrapper*)
17@@ -16,7 +25,7 @@ fun bindings_free(b: List0_vt(binding)): void =
18         val @{key = k, value = v} = entry
19     in
20         strptr_free  (k);
21-        strptr_free  (v);
22+        parts_free   (v);
23         bindings_free(rest)
24     end
25 
26@@ -61,7 +70,7 @@ in
27     bindings_free(v)
28 end
29 
30-fun binding_val(s: &scanner): Strptr1 = 
31+fun binding_val(s: &scanner): List0_vt(stringpart) = 
32 let
33     val ()   = skipspace(s)
34     val ()   = scanchar(s, char2int0('='))
35@@ -71,7 +80,7 @@ in
36         next(s);
37         text)
38     else(
39-        strptr_free(text);
40+        parts_free(text);
41         prerrln!("expected newline after value at", s.line,":",s.col );
42         $raise ParseErr )
43 end
44@@ -104,7 +113,7 @@ fun hascommand(bindings: !List0_vt(binding)): bool =
45     | nil_vt() => false
46     | @cons_vt(entry, rest) =>
47     let 
48-        val found = if strptr_length(entry.value) >0 && entry.key = "command" then true
49+        val found = if list_vt_length(entry.value) > 0 && entry.key = "command" then true
50         else hascommand(rest)
51     in
52         fold@(bindings);
53@@ -219,11 +228,24 @@ fun hasrule(rules: !List0_vt(rule), name: !Strptr1): bool =
54         found
55     end
56 
57+fun printparts(parts: !List0_vt(stringpart)): void =
58+    case+ parts of
59+    | nil_vt()             => ()
60+    | @cons_vt(part, rest) => (
61+        (case+ part of
62+         | @Literal(text) => (print!(text); fold@(part))
63+         | @Variable(name) => (print!("${", name, "}"); fold@(part)));
64+        printparts(rest);
65+        fold@(parts)
66+    )
67+
68 fun printbindings(bindings: !List0_vt(binding)): void =
69     case+ bindings of 
70     | nil_vt() => ()
71     | @cons_vt(entry, rest) => (
72-    println!("  binding: ", entry.key," = ",entry.value);
73+    print!("  binding: ", entry.key," = ");
74+    printparts(entry.value);
75+    println!();
76     printbindings(rest);
77     fold@(bindings) )
78  
+1, -1
1@@ -2,7 +2,7 @@ staload "scan.sats"
2 
3 vtypedef binding = @{
4      key   = Strptr1, 
5-     value = Strptr1
6+     value = List0_vt(stringpart)
7 }
8 
9 vtypedef rule = @{
+86, -6
  1@@ -20,6 +20,10 @@ fun isnamec(c: int): bool =
  2 fun isvaluec(c: int): bool = 
  3     (c != char2int0('\n'))
  4 
  5+fun isliteralc(c: int): bool = 
  6+    (c != char2int0('\n')) &&
  7+    (c != char2int0 ('$'))
  8+
  9 fun ispathc(c: int): bool = 
 10     (c != char2int0('\n')) &&
 11     (c != char2int0 (' ')) &&
 12@@ -52,7 +56,87 @@ fun read(s: &scanner, allowed: (int) -<fun1> bool): void =
 13         end
 14     else ()
 15 
 16+fun readliteral(s: &scanner): Strptr1 = 
 17+let
 18+    val () = read(s, isliteralc)
 19+in
 20+    stringbuf_takeout_all(s.buf)
 21+end
 22 
 23+fun isvarc(c: int): bool =
 24+    isnamec(c) &&
 25+    c != char2int0('.')
 26+
 27+fun dollar(s: &scanner): stringpart = 
 28+let 
 29+    (* assume the scanner is sitting on $ *)
 30+    val () = next(s)
 31+in  
 32+    if s.cur < 0 then ( 
 33+        prerrln!("unexpected EOF after '$'");
 34+        $raise ScanErr()
 35+    ) else 
 36+        case+ int2char0(s.cur) of 
 37+        | '$' => (
 38+            let val inserted = stringbuf_insert_char(s.buf, '$')
 39+            in if inserted = 1 then (next(s); Literal(stringbuf_takeout_all(s.buf)) ) else $raise ScanErr 
 40+            end )
 41+        | ':' => (
 42+            let val inserted = stringbuf_insert_char(s.buf, ':')
 43+            in if inserted = 1 then (next(s); Literal(stringbuf_takeout_all(s.buf)) ) else $raise ScanErr 
 44+            end )
 45+        | '\{' => 
 46+            let
 47+               val () = next(s)
 48+               val () = read(s, isnamec)
 49+            in
 50+                if stringbuf_get_size(s.buf) = 0 then (
 51+                    prerrln!("expected variable name");
 52+                    $raise ScanErr()
 53+                ) else (
 54+                    if s.cur = char2int0('}') then (
 55+                        next(s);
 56+                        Variable(stringbuf_takeout_all(s.buf))
 57+                    ) else ( 
 58+                        prerrln!("unclosed variable brace");
 59+                        $raise ScanErr() )
 60+                )
 61+            end 
 62+        | _ =>
 63+            let
 64+               val () = read(s, isvarc)
 65+            in
 66+                if stringbuf_get_size(s.buf) = 0 then (
 67+                    prerrln!("expected variable name");
 68+                    $raise ScanErr
 69+                ) else
 70+                    Variable(stringbuf_takeout_all(s.buf))
 71+            end
 72+
 73+end
 74+
 75+fun parts (s: &scanner, collected: List0_vt(stringpart)): List0_vt(stringpart) = 
 76+    if s.cur < 0 then
 77+        list_vt_reverse(collected)
 78+    else
 79+        case+ int2char0(s.cur) of 
 80+        | '\n' => list_vt_reverse(collected)
 81+        | '$'  => 
 82+            let 
 83+                val newpart = dollar(s);
 84+                val more    = cons_vt(newpart, collected)
 85+            in
 86+                parts(s, more)  
 87+            end
 88+        | _   => 
 89+            let
 90+               val newpart = readliteral(s)
 91+               val litpart = Literal(newpart)
 92+               val more    = cons_vt(litpart, collected)
 93+            in 
 94+               parts(s, more)
 95+            end
 96+    
 97 implement scanname(s) (*Strptr1*)= 
 98 let
 99     val () = read(s, isnamec)
100@@ -118,12 +202,8 @@ implement scankeyword(s) =
101     else (prerrln!("expected name at ",s.line, ":", s.col);
102           $raise ScanErr())
103 
104-implement scanvalue(s) (*Strptr1*) = 
105-let
106-    val () = read(s, isvaluec)
107-in
108-    stringbuf_takeout_all(s.buf)
109-end
110+implement scanvalue(s) (*List0_vt(stringpart)*) = 
111+    parts(s, nil_vt())
112 
113 implement scanpath(s) = 
114 let
+1, -1
1@@ -28,6 +28,6 @@ fun mktok      (text: Strptr1,
2 fun scanchar   (s: &scanner, wanted: int): void 
3 fun scanindent (s: &scanner): bool
4 fun scankeyword(s: &scanner): tok
5-fun scanvalue  (s: &scanner): Strptr1
6+fun scanvalue  (s: &scanner): List0_vt(stringpart)
7 fun scanpath  (s: &scanner): Strptr1
8