diff --git a/examples/dependencies.tm b/examples/dependencies.tm index e13e362..6a5fdea 100644 --- a/examples/dependencies.tm +++ b/examples/dependencies.tm @@ -1,24 +1,50 @@ -# Show dependency graph +# Show a Tomo dependency graph use file -func build_dependency_graph(filename:Text, dependencies:&{Text:@{Text}}): +USAGE := "Usage: dependencies " + +HELP := " + dependencies: Show a file dependency graph for Tomo source files. + $USAGE +" + +func build_dependency_graph(filename:Text, dependencies:&{Text:@{Text}}, module=""): reader := when LineReader.from_file(filename) is Failure(msg): + !! Failed: $msg return is Open(reader): reader + key := if module: module else: filename + if not dependencies:has(key): + dependencies:set(key, @{:Text}) + while when reader:next_line() is Success(line): - if line:matches($/{start}use {..}.tm/): - import := line:replace($/{start}use {..}/, "\2") + if line:matches($/use {..}.tm/): + import := line:replace($/use {..}/, "\1") resolved := relative_path(resolve_path(import, filename)) if resolved != "": import = resolved - if not dependencies:has(filename): - dependencies:set(filename, @{:Text}) + dependencies:get(key):add(import) - dependencies:get(filename):add(import) if not dependencies:has(import): build_dependency_graph(import, dependencies) + else if line:matches($/use {id}/): + import := line:replace($/use {..}/, "\1") + + dependencies:get(key):add(import) + files_path := resolve_path("~/.local/src/tomo/$import/lib$(import).files") + if files_path == "": + !! couldn't resolve: $files_path + skip if files_path == "" + when read(files_path) is Failure(msg): + !! couldn't read: $files_path $msg + skip + is Success(files_content): + for line in files_content:lines(): + line_resolved := resolve_path(line, relative_to="~/.local/src/tomo/$import/") + skip if line_resolved == "" + build_dependency_graph(line_resolved, dependencies, module=import) func get_dependency_graph(file:Text)->{Text:{Text}}: graph := {:Text:@{Text}} @@ -27,8 +53,12 @@ func get_dependency_graph(file:Text)->{Text:{Text}}: return {f:deps[] for f,deps in graph} func draw_tree(file:Text, dependencies:{Text:{Text}}, already_printed:&{Text}, prefix="", is_last=yes): - color_file := if resolve_path(file): file else: "$\x1b[31;1m$file$\x1b[m" - + color_file := if file:matches($/{id}/): + "$\x1b[34;1m$file$\x1b[m" + else if resolve_path(file) != "": + file + else: + "$\x1b[31;1m$file (could not resolve)$\x1b[m" if already_printed:has(file): say(prefix ++ (if is_last: "└── " else: "├── ") ++ color_file ++ " $\x1b[2m(recursive)$\x1b[m") diff --git a/examples/file.tm b/examples/file.tm index 7def418..9d4197b 100644 --- a/examples/file.tm +++ b/examples/file.tm @@ -38,6 +38,7 @@ func read(path:Text)->FileReadResult: char *gc_mem = GC_MALLOC_ATOMIC(sb.st_size+1); memcpy(gc_mem, mem, sb.st_size); gc_mem[sb.st_size] = '\0'; + close(fd); return file$FileReadResult$tagged$Success(Text$from_strn(gc_mem, sb.st_size)); } else { const int chunk_size = 256; @@ -130,7 +131,10 @@ struct LineReader(_file:@Memory): char *buf = NULL; size_t space = 0; ssize_t len = getline(&buf, &space, *(FILE**)$r.$_file); - if (len < 0) return (file$FileReadResult_t){1, .$Failure={Text("End of file")}}; + if (len < 0) { + file$_close_file($r.$_file); + return (file$FileReadResult_t){1, .$Failure={Text("End of file")}}; + } if (len > 0 && buf[len-1] == '\n') --len; char *line = GC_MALLOC_ATOMIC(len + 1); memcpy(line, buf, len); @@ -185,6 +189,7 @@ func command(cmd:Text)->FileReadResult: buf = GC_MALLOC_ATOMIC(chunk_size); } } while (just_read > 0); + pclose($f); contents; }) ):Text