structure FileString = struct fun findLastChr (str, pos, findChr) = if pos < 0 then ~1 else if String.sub (str, pos) = findChr then pos else findLastChr (str, pos - 1, findChr) fun extractFileName str = let val lastSlash = findLastChr (str, String.size str - 1, #"/") val strStart = lastSlash + 1 in if lastSlash = ~1 then str else String.substring (str, strStart, String.size str - strStart) end fun removeFileExtension str = let val lastDot = findLastChr (str, String.size str - 1, #".") in if lastDot = ~1 then str else String.substring (str, 0, lastDot) end local fun finish acc = let val acc = List.rev acc in String.implode acc end (* convert from kebab-case or snake_case to PascalCase *) fun loop (#"-" :: chr :: tl, acc) = let val acc = Char.toUpper chr :: acc in loop (tl, acc) end | loop (#"_" :: chr :: tl, acc) = let val acc = Char.toUpper chr :: acc in loop (tl, acc) end | loop ([#"-"], acc) = finish acc | loop ([#"_"], acc) = finish acc | loop (chr :: tl, acc) = loop (tl, chr :: acc) | loop ([], acc) = finish acc in fun filenameToStructureName str = let val str = removeFileExtension str val str = extractFileName str in (* capitalise first character in string *) case String.explode str of chr :: tl => let val chr = Char.toUpper chr in loop (tl, [chr]) end | [] => "" end end fun getCollisionFilename str = let val str = removeFileExtension str in str ^ "-collisions.sml" end end