
SourceFile.pudu
Pudu52 lines1.6 KB
1/** @Domain.Code.SourceFile.Module — maps module names to source paths */2module PuduLangMcp.Domain.Code.SourceFile34import Std.Char as Char5import Std.Text as Text678const EXTENSION: Str = ".pudu"91011export fn moduleNameOf(source: Str) -> Option[Str] {12 for raw in source.split("\n") {13 let line = raw.trim()14 let comment = line.startsWith("//") || (line.startsWith("/*") && line.endsWith("*/"))15 if !line.isEmpty() && !comment {16 if !line.startsWith("module ") { return None }17 let name = line.drop(7).trim()18 return if isModuleName(name) { Some(name) } else { None }19 }20 }21 None22}232425export fn fileOf(moduleName: Str) -> Str {26 moduleName.replace(".", "/") + EXTENSION27}282930export fn moduleOfFile(relative: Str) -> Option[Str] {31 if !relative.endsWith(EXTENSION) { return None }32 let name = Text.stripSuffix(relative, EXTENSION).replace("/", ".")33 if isModuleName(name) { Some(name) } else { None }34}353637export fn isModuleName(name: Str) -> Bool {38 if name.isEmpty() { return false }39 for segment in name.split(".") {40 if !isSegment(segment) { return false }41 }42 true43}444546fn isSegment(segment: Str) -> Bool {47 match Text.uncons(segment) {48 case None => false49 case Some((first, rest)) => Char.isLetter(first) && Text.allChars(rest, |c: Char| Char.isAlphanumeric(c) || c == '_')50 }51}52