file.ha (4417B)
1 use fmt; 2 3 use util; 4 5 export type lines = struct { 6 next: nullable *lines, 7 prev: nullable *lines, 8 s: str 9 }; 10 11 // returns a new allocated line, the caller should free this value 12 export fn newline(s: str) *lines = alloc(lines{next = null, prev = null, s = s})!; 13 @test fn newline() void = assert(newline("hello world").s == "hello world"); 14 15 // returns the last line of [[lines]] 16 export fn getend(ls: *lines) *lines = { 17 let current = ls; 18 for (let i = 0; true; i += 1) 19 current = match (current.next) { 20 case let ls: *lines => yield ls; 21 case null => return current; 22 }; 23 }; 24 @test fn getend() void = { 25 let line = newline("hello world"); 26 assert(getend(line) == line); 27 }; 28 @test fn getend() void = { 29 let line = newline("hello world"); 30 line.next = newline("bye world"); 31 assert(getend(line) == line.next); 32 }; 33 34 // inserts [[l]] at [[where]] into [[ls]], and returns a new value for [[ls]], 35 // the caller should override [[ls]], with the return value 36 export fn insertline(ls: *lines, l: *lines, where: size) *lines = { 37 if (where == 0) { 38 l.next = ls; //todo, make this work for multiple lines in l 39 ls.prev = l; 40 return l; 41 }; 42 43 let current = getline(ls, where - 1); 44 45 let tmp = match (current.next) { 46 case let ls: *lines => yield ls; 47 case null => 48 current.next = l; 49 l.prev = current; 50 return ls; 51 }; 52 let end = getend(l); 53 54 current.next = l; 55 l.prev = current; 56 end.next = tmp; 57 tmp.prev = end; 58 59 return ls; 60 }; 61 @test fn insertline() void = { 62 let ls = newline("file"); 63 let line = newline("hello world"); 64 ls = insertline(ls, line, 1); 65 assert((ls.next as *lines).s == "hello world"); 66 assert(ls.s == "file"); 67 }; 68 @test fn insertline() void = { 69 let ls = newline("file"); 70 let line = newline("hello world"); 71 ls = insertline(ls, line, 0); 72 assert(ls.s == "hello world"); 73 assert((ls.next as *lines).s == "file"); 74 }; 75 76 // gets the [[where]]'th line from [[ls]] 77 export fn getline(ls: *lines, where: size) *lines = { 78 let current = ls; 79 for (let i = 0z; i < where; i += 1) 80 current = match (current.next) { 81 case let ls: *lines => yield ls; 82 case null => abort(); 83 }; 84 85 return current; 86 }; 87 @test fn getline() void = { 88 let ls = newline("file"); 89 let line = newline("hello world"); 90 ls = insertline(ls, line, 1); 91 assert(getline(ls, 0).s == "file"); 92 }; 93 @test fn getline() void = { 94 let ls = newline("file"); 95 let line = newline("hello world"); 96 ls = insertline(ls, line, 1); 97 assert(getline(ls, 1).s == "hello world"); 98 }; 99 @test fn getline() void = { 100 let ls = newline("file"); 101 let line = newline("hello world"); 102 ls = insertline(ls, line, 0); 103 assert(getline(ls, 0).s == "hello world"); 104 }; 105 @test fn getline() void = { 106 let ls = newline("file"); 107 let line = newline("hello world"); 108 ls = insertline(ls, line, 0); 109 assert(getline(ls, 1).s == "file"); 110 }; 111 112 // counts how many lines are in [[ls]] 113 export fn countlines(ls: *lines) size = { 114 let current = ls; 115 for (let i = 0z; true; i += 1) 116 current = match (current.next) { 117 case let ls: *lines => yield ls; 118 case null => return i + 1; 119 }; 120 }; 121 @test fn countlines() void = { 122 let ls = newline("file"); 123 let line = newline("hello world"); 124 ls = insertline(ls, line, 0); 125 assert(countlines(ls) == 2); 126 }; 127 128 // deletes line at [[where]] from [[ls]], the caller should override [[ls]] with 129 // the return value 130 export fn deleteline(ls: *lines, where: size) *lines = { 131 if (where == 0) return ls.next as *lines; 132 133 let current = getline(ls, where); 134 135 (current.prev as *lines).next = current.next; 136 if (where != countlines(ls)) 137 (current.next as *lines).prev = current.prev; 138 139 free(current); 140 return ls; 141 }; 142 @test fn deleteline() void = { 143 let ls = newline("file"); 144 let line = newline("hello world"); 145 let line2 = newline("fuck"); 146 ls = insertline(ls, line, 1); 147 ls = insertline(ls, line2, 2); 148 ls = deleteline(ls, 0); 149 assert(ls.s == "hello world"); 150 assert((ls.next as *lines).s == "fuck"); 151 }; 152 @test fn deleteline() void = { 153 let ls = newline("file"); 154 let line = newline("hello world"); 155 let line2 = newline("fuck"); 156 ls = insertline(ls, line, 1); 157 ls = insertline(ls, line2, 2); 158 ls = deleteline(ls, 1); 159 assert(ls.s == "file"); 160 assert((ls.next as *lines).s == "fuck"); 161 }; 162 @test fn deleteline() void = { 163 let ls = newline("file"); 164 let line = newline("hello world"); 165 let line2 = newline("fuck"); 166 ls = insertline(ls, line, 1); 167 ls = insertline(ls, line2, 2); 168 ls = deleteline(ls, 2); 169 assert(ls.s == "file"); 170 assert((ls.next as *lines).s == "hello world"); 171 };