aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2025-04-01 15:15:28 -0400
committerBruce Hill <bruce@bruce-hill.com>2025-04-01 15:15:28 -0400
commitd888bec4095170d159c488292ba098b243c0a44e (patch)
tree0d0ff7c2e2c4ed75519ee32ec6482e04b1e68b3d /examples
parent354ed77535d17f2fc71780f1aaeb7ebfb80307d4 (diff)
Clean up and improve patterns
Diffstat (limited to 'examples')
-rw-r--r--examples/colorful/colorful.tm15
-rw-r--r--examples/commands/commands.tm2
-rw-r--r--examples/ini/ini.tm15
-rw-r--r--examples/patterns/patterns.tm36
-rw-r--r--examples/time/time.tm2
-rw-r--r--examples/tomo-install/tomo-install.tm9
-rw-r--r--examples/tomodeps/tomodeps.tm14
7 files changed, 48 insertions, 45 deletions
diff --git a/examples/colorful/colorful.tm b/examples/colorful/colorful.tm
index e138e037..7b265ecb 100644
--- a/examples/colorful/colorful.tm
+++ b/examples/colorful/colorful.tm
@@ -1,4 +1,5 @@
# Colorful language
+
HELP := "
colorful: A domain-specific language for writing colored text to the terminal
Usage: colorful [args...] [--by-line] [--files files...]
@@ -6,6 +7,8 @@ HELP := "
CSI := "$\033["
+use patterns
+
lang Colorful:
convert(text:Text -> Colorful):
text = text:translate({"@"="@(at)", "("="@(lparen)", ")"="@(rparen)"})
@@ -42,18 +45,18 @@ func main(texts:[Text], files=[:Path], by_line=no):
func _for_terminal(c:Colorful, state:_TermState -> Text):
- return c.text:map(recursive=no, $/@(?)/, func(m:Match): _add_ansi_sequences(m.captures[1], state))
+ return c.text:map_pattern(recursive=no, $Pat/@(?)/, func(m:PatternMatch): _add_ansi_sequences(m.captures[1], state))
enum _Color(Default, Bright(color:Int16), Color8Bit(color:Int16), Color24Bit(color:Int32)):
func from_text(text:Text -> _Color?):
- if text:matches($/#{3-6 hex}/):
+ if text:matches_pattern($Pat/#{3-6 hex}/):
hex := text:from(2)
return none unless hex.length == 3 or hex.length == 6
if hex.length == 3:
hex = hex[1]++hex[1]++hex[2]++hex[2]++hex[3]++hex[3]
n := Int32.parse("0x" ++ hex) or return none
return Color24Bit(n)
- else if text:matches($/{1-3 digit}/):
+ else if text:matches_pattern($Pat/{1-3 digit}/):
n := Int16.parse(text) or return none
if n >= 0 and n <= 255: return Color8Bit(n)
else if text == "black": return _Color.Color8Bit(0)
@@ -168,10 +171,10 @@ func _add_ansi_sequences(text:Text, prev_state:_TermState -> Text):
else if text == "rparen": return ")"
else if text == "@" or text == "at": return "@"
parts := (
- text:matches($/{0+..}:{0+..}/) or
+ text:matches_pattern($Pat/{0+..}:{0+..}/) or
return "@("++_for_terminal(Colorful.from_text(text), prev_state)++")"
)
- attributes := parts[1]:split($/{0+space},{0+space}/)
+ attributes := parts[1]:split_pattern($Pat/{0+space},{0+space}/)
new_state := prev_state
for attr in attributes:
if attr:starts_with("fg="):
@@ -210,6 +213,6 @@ func _add_ansi_sequences(text:Text, prev_state:_TermState -> Text):
fail("Invalid attribute: '$attr'")
result := prev_state:apply(new_state)
- result ++= parts[2]:map(recursive=no, $/@(?)/, func(m:Match): _add_ansi_sequences(m.captures[1], new_state))
+ result ++= parts[2]:map_pattern(recursive=no, $Pat/@(?)/, func(m:PatternMatch): _add_ansi_sequences(m.captures[1], new_state))
result ++= new_state:apply(prev_state)
return result
diff --git a/examples/commands/commands.tm b/examples/commands/commands.tm
index 70a2303b..26b82790 100644
--- a/examples/commands/commands.tm
+++ b/examples/commands/commands.tm
@@ -28,7 +28,7 @@ struct ProgramResult(stdout:[Byte], stderr:[Byte], exit_type:ExitType):
if status == 0:
if text := Text.from_bytes(r.stdout):
if trim_newline:
- text = text:trim($/{1 nl}/, trim_left=no, trim_right=yes)
+ text = text:without_suffix(\n)
return text
else: return none
return none
diff --git a/examples/ini/ini.tm b/examples/ini/ini.tm
index 1c50ac37..1c90b715 100644
--- a/examples/ini/ini.tm
+++ b/examples/ini/ini.tm
@@ -1,3 +1,6 @@
+
+use patterns
+
_USAGE := "
Usage: ini <filename> "[section[/key]]"
"
@@ -12,18 +15,18 @@ func parse_ini(path:Path -> {Text,{Text,Text}}):
current_section := @{:Text,Text}
# Line wraps:
- text = text:replace($/\{1 nl}{0+space}/, " ")
+ text = text:replace_pattern($Pat/\{1 nl}{0+space}/, " ")
for line in text:lines():
line = line:trim()
skip if line:starts_with(";") or line:starts_with("#")
- if line:matches($/[?]/):
- section_name := line:replace($/[?]/, "\1"):trim():lower()
+ if line:matches_pattern($Pat/[?]/):
+ section_name := line:replace($Pat/[?]/, "\1"):trim():lower()
current_section = @{:Text,Text}
sections[section_name] = current_section
- else if line:matches($/{..}={..}/):
- key := line:replace($/{..}={..}/, "\1"):trim():lower()
- value := line:replace($/{..}={..}/, "\2"):trim()
+ else if line:matches_pattern($Pat/{..}={..}/):
+ key := line:replace_pattern($Pat/{..}={..}/, "\1"):trim():lower()
+ value := line:replace_pattern($Pat/{..}={..}/, "\2"):trim()
current_section[key] = value
return {k=v[] for k,v in sections[]}
diff --git a/examples/patterns/patterns.tm b/examples/patterns/patterns.tm
index 5e9ebe69..8ca5faa2 100644
--- a/examples/patterns/patterns.tm
+++ b/examples/patterns/patterns.tm
@@ -10,49 +10,43 @@ lang Pat:
return Pat.from_text("$n")
extend Text:
- func matches(text:Text, pattern:Pat -> [Text]?):
+ func matches_pattern(text:Text, pattern:Pat -> [Text]?):
return inline C : [Text]? { Pattern$matches(_$text, _$pattern); }
- func pat_replace(text:Text, pattern:Pat, replacement:Text, backref="@", recursive=yes -> Text):
+ func replace_pattern(text:Text, pattern:Pat, replacement:Text, backref="@", recursive=yes -> Text):
return inline C : Text { Pattern$replace(_$text, _$pattern, _$replacement, _$backref, _$recursive); }
- func pat_replace_all(text:Text, replacements:{Pat,Text}, backref="@", recursive=yes -> Text):
+ func translate_patterns(text:Text, replacements:{Pat,Text}, backref="@", recursive=yes -> Text):
return inline C : Text { Pattern$replace_all(_$text, _$replacements, _$backref, _$recursive); }
- func has(text:Text, pattern:Pat -> Bool):
+ func has_pattern(text:Text, pattern:Pat -> Bool):
return inline C : Bool { Pattern$has(_$text, _$pattern); }
- func find_all(text:Text, pattern:Pat -> [PatternMatch]):
+ func find_patterns(text:Text, pattern:Pat -> [PatternMatch]):
return inline C : [PatternMatch] { Pattern$find_all(_$text, _$pattern); }
- func by_match(text:Text, pattern:Pat -> func(->PatternMatch?)):
+ func by_pattern(text:Text, pattern:Pat -> func(->PatternMatch?)):
return inline C : func(->PatternMatch?) { Pattern$by_match(_$text, _$pattern); }
- func each(text:Text, pattern:Pat, fn:func(m:PatternMatch), recursive=yes):
+ func each_pattern(text:Text, pattern:Pat, fn:func(m:PatternMatch), recursive=yes):
inline C { Pattern$each(_$text, _$pattern, _$fn, _$recursive); }
- func map(text:Text, pattern:Pat, fn:func(m:PatternMatch -> Text), recursive=yes -> Text):
+ func map_pattern(text:Text, pattern:Pat, fn:func(m:PatternMatch -> Text), recursive=yes -> Text):
return inline C : Text { Pattern$map(_$text, _$pattern, _$fn, _$recursive); }
- func split(text:Text, pattern:Pat -> [Text]):
+ func split_pattern(text:Text, pattern:Pat -> [Text]):
return inline C : [Text] { Pattern$split(_$text, _$pattern); }
- func by_split(text:Text, pattern:Pat -> func(->Text?)):
+ func by_pattern_split(text:Text, pattern:Pat -> func(->Text?)):
return inline C : func(->Text?) { Pattern$by_split(_$text, _$pattern); }
- func trim(text:Text, pattern:Pat, trim_left=yes, trim_right=yes -> Text):
- return inline C : Text { Pattern$trim(_$text, _$pattern, _$trim_left, _$trim_right); }
-
- func trim_left(text:Text, pattern:Pat -> Text):
- return text:trim(pattern, trim_left=yes, trim_right=no)
-
- func trim_right(text:Text, pattern:Pat -> Text):
- return text:trim(pattern, trim_left=no, trim_right=yes)
+ func trim_pattern(text:Text, pattern=$Pat"{space}", left=yes, right=yes -> Text):
+ return inline C : Text { Pattern$trim(_$text, _$pattern, _$left, _$right); }
func main():
- >> "hello world":pat_replace($Pat/{id}/, "XXX")
- >> "hello world":find_all($Pat/l/)
+ >> "hello world":replace_pattern($Pat/{id}/, "XXX")
+ >> "hello world":find_patterns($Pat/l/)
- for m in "hello one two three":by_match($Pat/{id}/):
+ for m in "hello one two three":by_pattern($Pat/{id}/):
>> m
diff --git a/examples/time/time.tm b/examples/time/time.tm
index 909c24ec..8664f2e4 100644
--- a/examples/time/time.tm
+++ b/examples/time/time.tm
@@ -123,7 +123,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern):
t:format("%l:%M%P")
else:
t:format("%H:%M")
- return time:trim($/ /, trim_left=yes, trim_right=yes)
+ return time:trim()
func date(t:Time, timezone=Time.local_timezone() -> Text):
return t:format("%F")
diff --git a/examples/tomo-install/tomo-install.tm b/examples/tomo-install/tomo-install.tm
index 0a6c608d..3be23a81 100644
--- a/examples/tomo-install/tomo-install.tm
+++ b/examples/tomo-install/tomo-install.tm
@@ -1,4 +1,5 @@
use shell
+use patterns
_USAGE := "
tomo-install file.tm...
@@ -16,7 +17,7 @@ func find_urls(path:Path -> [Text]):
urls:insert_all(find_urls(f))
else if path:is_file() and path:extension() == ".tm":
for line in path:by_line()!:
- if m := line:matches($/use{space}{url}/) or line:matches($/{id}{space}:={space}use{space}{url}/):
+ if m := line:matches_pattern($Pat/use{space}{url}/) or line:matches_pattern($Pat/{id}{space}:={space}use{space}{url}/):
urls:insert(m[-1])
return urls
@@ -33,7 +34,7 @@ func main(paths:[Path]):
for url in urls:
original_url := url
- url_without_protocol := url:trim($|http{0-1 s}://|, trim_right=no)
+ url_without_protocol := url:trim_pattern($Pat"http{0-1 s}://", right=no)
hash := $Shell@(echo -n @url_without_protocol | sha256sum):get_output()!:slice(to=32)
if (~/.local/share/tomo/installed/$hash):is_directory():
say("Already installed: $url")
@@ -41,12 +42,12 @@ func main(paths:[Path]):
alias := none:Text
curl_flags := ["-L"]
- if github := url_without_protocol:matches($|github.com/{!/}/{!/}#{..}|):
+ if github := url_without_protocol:matches_pattern($Pat"github.com/{!/}/{!/}#{..}"):
user := github[1]
repo := github[2]
tag := github[3]
url = "https://api.github.com/repos/$user/$repo/tarball/$tag"
- alias = "$(repo:trim($/tomo-/, trim_right=no)).$(tag).$(user)"
+ alias = "$(repo:without_prefix("tomo-")).$(tag).$(user)"
if github_token:
curl_flags ++= ["-H", "Authorization: Bearer $github_token"]
curl_flags ++= [
diff --git a/examples/tomodeps/tomodeps.tm b/examples/tomodeps/tomodeps.tm
index 8149ff88..96838a66 100644
--- a/examples/tomodeps/tomodeps.tm
+++ b/examples/tomodeps/tomodeps.tm
@@ -1,5 +1,7 @@
# Show a Tomo dependency graph
+use patterns
+
_USAGE := "Usage: tomodeps <files...>"
_HELP := "
@@ -17,11 +19,11 @@ func _get_file_dependencies(file:Path -> {Dependency}):
deps := @{:Dependency}
if lines := file:by_line():
for line in lines:
- if line:matches($/use {..}.tm/):
- file_import := Path.from_text(line:replace($/use {..}/, "\1")):resolved(relative_to=file)
+ if line:matches_pattern($Pat/use {..}.tm/):
+ file_import := Path.from_text(line:replace_pattern($Pat/use {..}/, "\1")):resolved(relative_to=file)
deps:add(Dependency.File(file_import))
- else if line:matches($/use {id}/):
- module_name := line:replace($/use {..}/, "\1")
+ else if line:matches_pattern($Pat/use {id}/):
+ module_name := line:replace_pattern($Pat/use {..}/, "\1")
deps:add(Dependency.Module(module_name))
return deps[]
@@ -102,11 +104,11 @@ func main(files:[Text]):
")
for arg in files:
- if arg:matches($/{..}.tm/):
+ if arg:matches_pattern($Pat/{..}.tm/):
path := Path.from_text(arg):resolved()
dependencies := get_dependency_graph(File(path))
draw_tree(File(path), dependencies)
- else if arg:matches($/{id}/):
+ else if arg:matches_pattern($Pat/{id}/):
dependencies := get_dependency_graph(Module(arg))
draw_tree(Module(arg), dependencies)
else: