aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/base64/base64.tm26
-rw-r--r--examples/colorful/colorful.tm202
-rw-r--r--examples/commands/commands.tm78
-rw-r--r--examples/game/box.tm4
-rw-r--r--examples/game/game.tm4
-rw-r--r--examples/game/player.tm6
-rw-r--r--examples/game/raylib.tm36
-rw-r--r--examples/game/world.tm50
-rw-r--r--examples/http-server/connection-queue.tm10
-rw-r--r--examples/http-server/http-server.tm66
-rwxr-xr-xexamples/http-server/sample-site/random.tm2
-rw-r--r--examples/http/http.tm36
-rw-r--r--examples/ini/ini.tm16
-rw-r--r--examples/learnxiny.tm60
-rw-r--r--examples/log/log.tm24
-rw-r--r--examples/patterns/patterns.tm32
-rw-r--r--examples/pthreads/pthreads.tm66
-rw-r--r--examples/random/random.tm48
-rw-r--r--examples/shell/shell.tm40
-rw-r--r--examples/time/time.tm46
-rw-r--r--examples/tomo-install/tomo-install.tm26
-rw-r--r--examples/tomodeps/tomodeps.tm70
-rw-r--r--examples/vectors/vectors.tm108
-rw-r--r--examples/wrap/wrap.tm54
-rw-r--r--src/parse.c57
-rw-r--r--test/arrays.tm52
-rw-r--r--test/bytes.tm2
-rw-r--r--test/corecursive_func.tm14
-rw-r--r--test/defer.tm42
-rw-r--r--test/enums.tm28
-rw-r--r--test/extern.tm2
-rw-r--r--test/for.tm26
-rw-r--r--test/functions.tm6
-rw-r--r--test/import.tm6
-rw-r--r--test/inline_c.tm2
-rw-r--r--test/integers.tm12
-rw-r--r--test/iterators.tm18
-rw-r--r--test/lambdas.tm28
-rw-r--r--test/lang.tm14
-rw-r--r--test/metamethods.tm34
-rw-r--r--test/minmax.tm6
-rw-r--r--test/nums.tm2
-rw-r--r--test/optionals.tm202
-rw-r--r--test/paths.tm10
-rw-r--r--test/reductions.tm2
-rw-r--r--test/serialization.tm32
-rw-r--r--test/sets.tm2
-rw-r--r--test/structs.tm10
-rw-r--r--test/tables.tm14
-rw-r--r--test/text.tm6
-rw-r--r--test/use_import.tm4
-rw-r--r--test/when.tm14
52 files changed, 874 insertions, 883 deletions
diff --git a/examples/base64/base64.tm b/examples/base64/base64.tm
index 714e223b..bf512a83 100644
--- a/examples/base64/base64.tm
+++ b/examples/base64/base64.tm
@@ -23,15 +23,15 @@ _dec : [Byte] = [
49, 50, 51, 255, 255, 255, 255, 255,
]
-lang Base64:
- func parse(text:Text -> Base64?):
+lang Base64
+ func parse(text:Text -> Base64?)
return Base64.from_bytes(text.bytes())
- func from_bytes(bytes:[Byte] -> Base64?):
+ func from_bytes(bytes:[Byte] -> Base64?)
output := &[Byte(0) for _ in bytes.length * 4 / 3 + 4]
src := Int64(1)
dest := Int64(1)
- while src + 2 <= Int64(bytes.length):
+ while src + 2 <= Int64(bytes.length)
chunk24 := (
(Int32(bytes[src]) <<< 16) or (Int32(bytes[src+1]) <<< 8) or Int32(bytes[src+2])
)
@@ -43,7 +43,7 @@ lang Base64:
output[dest+3] = _enc[1 + (chunk24 and 0b111111)]
dest += 4
- if src + 1 == bytes.length:
+ if src + 1 == bytes.length
chunk16 := (
(Int32(bytes[src]) <<< 8) or Int32(bytes[src+1])
)
@@ -51,7 +51,7 @@ lang Base64:
output[dest+1] = _enc[1 + ((chunk16 >>> 4) and 0b111111)]
output[dest+2] = _enc[1 + ((chunk16 <<< 2)and 0b111111)]
output[dest+3] = _EQUAL_BYTE
- else if src == bytes.length:
+ else if src == bytes.length
chunk8 := Int32(bytes[src])
output[dest] = _enc[1 + ((chunk8 >>> 2) and 0b111111)]
output[dest+1] = _enc[1 + ((chunk8 <<< 4) and 0b111111)]
@@ -60,15 +60,15 @@ lang Base64:
return Base64.from_text(Text.from_bytes(output[]) or return none)
- func decode_text(b64:Base64 -> Text?):
+ func decode_text(b64:Base64 -> Text?)
return Text.from_bytes(b64.decode_bytes() or return none)
- func decode_bytes(b64:Base64 -> [Byte]?):
+ func decode_bytes(b64:Base64 -> [Byte]?)
bytes := b64.text.bytes()
output := &[Byte(0) for _ in bytes.length/4 * 3]
src := Int64(1)
dest := Int64(1)
- while src + 3 <= Int64(bytes.length):
+ while src + 3 <= Int64(bytes.length)
chunk24 := (
(Int32(_dec[1+bytes[src]]) <<< 18) or
(Int32(_dec[1+bytes[src+1]]) <<< 12) or
@@ -82,15 +82,15 @@ lang Base64:
output[dest+2] = Byte(chunk24 and 0xFF)
dest += 3
- while output[-1] == 0xFF:
+ while output[-1] == 0xFF
output[] = output.to(-2)
return output[]
-func main(input=(/dev/stdin), decode=no):
- if decode:
+func main(input=(/dev/stdin), decode=no)
+ if decode
b := Base64.from_text(input.read()!)
say(b.decode_text()!)
- else:
+ else
text := input.read()!
say(Base64.parse(text)!.text)
diff --git a/examples/colorful/colorful.tm b/examples/colorful/colorful.tm
index 6769841d..d64afe6e 100644
--- a/examples/colorful/colorful.tm
+++ b/examples/colorful/colorful.tm
@@ -9,128 +9,128 @@ CSI := "$\033["
use patterns
-lang Colorful:
- convert(text:Text -> Colorful):
+lang Colorful
+ convert(text:Text -> Colorful)
text = text.translate({"@"="@(at)", "("="@(lparen)", ")"="@(rparen)"})
return Colorful.from_text(text)
- convert(i:Int -> Colorful): return Colorful.from_text("$i")
- convert(n:Num -> Colorful): return Colorful.from_text("$n")
+ convert(i:Int -> Colorful) return Colorful.from_text("$i")
+ convert(n:Num -> Colorful) return Colorful.from_text("$n")
- func for_terminal(c:Colorful -> Text):
+ func for_terminal(c:Colorful -> Text)
return CSI ++ "m" ++ _for_terminal(c, _TermState())
- func print(c:Colorful, newline=yes):
+ func print(c:Colorful, newline=yes)
say(c.for_terminal(), newline=newline)
-func main(texts:[Text], files:[Path]=[], by_line=no):
- for i,text in texts:
+func main(texts:[Text], files:[Path]=[], by_line=no)
+ for i,text in texts
colorful := Colorful.from_text(text)
colorful.print(newline=no)
- if i == texts.length: say("")
- else: say(" ", newline=no)
+ if i == texts.length say("")
+ else say(" ", newline=no)
- if texts.length == 0 and files.length == 0:
+ if texts.length == 0 and files.length == 0
files = [(/dev/stdin)]
- for file in files:
- if by_line:
- for line in file.by_line() or exit("Could not read file: $file"):
+ for file in files
+ if by_line
+ for line in file.by_line() or exit("Could not read file: $file")
colorful := Colorful.from_text(line)
colorful.print()
- else:
+ else
colorful := Colorful.from_text(file.read() or exit("Could not read file: $file"))
colorful.print(newline=no)
-func _for_terminal(c:Colorful, state:_TermState -> Text):
- return c.text.map_pattern(recursive=no, $Pat/@(?)/, func(m:PatternMatch): _add_ansi_sequences(m.captures[1], state))
+func _for_terminal(c:Colorful, state:_TermState -> Text)
+ 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_pattern($Pat/#{3-6 hex}/):
+enum _Color(Default, Bright(color:Int16), Color8Bit(color:Int16), Color24Bit(color:Int32))
+ func from_text(text:Text -> _Color?)
+ 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:
+ 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_pattern($Pat/{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)
- else if text == "red": return _Color.Color8Bit(1)
- else if text == "green": return _Color.Color8Bit(2)
- else if text == "yellow": return _Color.Color8Bit(3)
- else if text == "blue": return _Color.Color8Bit(4)
- else if text == "magenta": return _Color.Color8Bit(5)
- else if text == "cyan": return _Color.Color8Bit(6)
- else if text == "white": return _Color.Color8Bit(7)
- else if text == "default": return _Color.Default
- else if text == "BLACK": return _Color.Bright(0)
- else if text == "RED": return _Color.Bright(1)
- else if text == "GREEN": return _Color.Bright(2)
- else if text == "YELLOW": return _Color.Bright(3)
- else if text == "BLUE": return _Color.Bright(4)
- else if text == "MAGENTA": return _Color.Bright(5)
- else if text == "CYAN": return _Color.Bright(6)
- else if text == "WHITE": return _Color.Bright(7)
+ if n >= 0 and n <= 255 return Color8Bit(n)
+ else if text == "black" return _Color.Color8Bit(0)
+ else if text == "red" return _Color.Color8Bit(1)
+ else if text == "green" return _Color.Color8Bit(2)
+ else if text == "yellow" return _Color.Color8Bit(3)
+ else if text == "blue" return _Color.Color8Bit(4)
+ else if text == "magenta" return _Color.Color8Bit(5)
+ else if text == "cyan" return _Color.Color8Bit(6)
+ else if text == "white" return _Color.Color8Bit(7)
+ else if text == "default" return _Color.Default
+ else if text == "BLACK" return _Color.Bright(0)
+ else if text == "RED" return _Color.Bright(1)
+ else if text == "GREEN" return _Color.Bright(2)
+ else if text == "YELLOW" return _Color.Bright(3)
+ else if text == "BLUE" return _Color.Bright(4)
+ else if text == "MAGENTA" return _Color.Bright(5)
+ else if text == "CYAN" return _Color.Bright(6)
+ else if text == "WHITE" return _Color.Bright(7)
return none
- func fg(c:_Color -> Text):
- when c is Color8Bit(color):
- if color >= 0 and color <= 7: return "$(30+color)"
- else if color >= 0 and color <= 255: return "38;5;$color"
- is Color24Bit(hex):
- if hex >= 0 and hex <= 0xFFFFFF:
+ func fg(c:_Color -> Text)
+ when c is Color8Bit(color)
+ if color >= 0 and color <= 7 return "$(30+color)"
+ else if color >= 0 and color <= 255 return "38;5;$color"
+ is Color24Bit(hex)
+ if hex >= 0 and hex <= 0xFFFFFF
return "38;2;$((hex >> 16) and 0xFF);$((hex >> 8) and 0xFF);$((hex >> 0) and 0xFF)"
- is Bright(color):
- if color <= 7: return "$(90+color)"
- is Default:
+ is Bright(color)
+ if color <= 7 return "$(90+color)"
+ is Default
return "39"
fail("Invalid foreground color: '$c'")
- func bg(c:_Color -> Text):
- when c is Color8Bit(color):
- if color >= 0 and color <= 7: return "$(40+color)"
- else if color >= 0 and color <= 255: return "48;5;$color"
- is Color24Bit(hex):
- if hex >= 0 and hex <= 0xFFFFFF:
+ func bg(c:_Color -> Text)
+ when c is Color8Bit(color)
+ if color >= 0 and color <= 7 return "$(40+color)"
+ else if color >= 0 and color <= 255 return "48;5;$color"
+ is Color24Bit(hex)
+ if hex >= 0 and hex <= 0xFFFFFF
return "48;2;$((hex >> 16) and 0xFF);$((hex >> 8) and 0xFF);$((hex >> 0) and 0xFF)"
- is Bright(color):
- if color <= 7: return "$(90+color)"
- is Default:
+ is Bright(color)
+ if color <= 7 return "$(90+color)"
+ is Default
return "49"
fail("Invalid background color: '$c'")
- func underline(c:_Color -> Text):
- when c is Color8Bit(color):
- if color >= 0 and color <= 255: return "58;5;$color"
- is Color24Bit(hex):
- if hex >= 0 and hex <= 0xFFFFFF:
+ func underline(c:_Color -> Text)
+ when c is Color8Bit(color)
+ if color >= 0 and color <= 255 return "58;5;$color"
+ is Color24Bit(hex)
+ if hex >= 0 and hex <= 0xFFFFFF
return "58;2;$((hex >> 16) and 0xFF);$((hex >> 8) and 0xFF);$((hex >> 0) and 0xFF)"
- is Default:
+ is Default
return "59"
- is Bright(color):
+ is Bright(color)
pass
fail("Invalid underline color: '$c'")
-func _toggle(sequences:&[Text], cur,new:Bool, apply,unapply:Text; inline):
- if new and not cur:
+func _toggle(sequences:&[Text], cur,new:Bool, apply,unapply:Text; inline)
+ if new and not cur
sequences.insert(apply)
- else if cur and not new:
+ else if cur and not new
sequences.insert(unapply)
-func _toggle2(sequences:&[Text], cur1,cur2,new1,new2:Bool, apply1,apply2,unapply:Text; inline):
+func _toggle2(sequences:&[Text], cur1,cur2,new1,new2:Bool, apply1,apply2,unapply:Text; inline)
return if new1 == cur1 and new2 == cur2
- if (cur1 and not new1) or (cur2 and not new2): # Gotta wipe at least one
+ if (cur1 and not new1) or (cur2 and not new2) # Gotta wipe at least one
sequences.insert(unapply)
cur1, cur2 = no, no # Wiped out
- if new1 and not cur1:
+ if new1 and not cur1
sequences.insert(apply1)
- if new2 and not cur2:
+ if new2 and not cur2
sequences.insert(apply2)
struct _TermState(
@@ -138,9 +138,9 @@ struct _TermState(
reverse=no, conceal=no, strikethrough=no, fraktur=no, frame=no,
encircle=no, overline=no, superscript=no, subscript=no,
bg=_Color.Default, fg=_Color.Default, underline_color=_Color.Default,
-):
+)
- func apply(old,new:_TermState -> Text):
+ func apply(old,new:_TermState -> Text)
sequences : &[Text] = &[]
_toggle2(sequences, old.bold, old.dim, new.bold, new.dim, "1", "2", "22")
_toggle2(sequences, old.italic, old.fraktur, new.italic, new.fraktur, "3", "20", "23")
@@ -153,66 +153,66 @@ struct _TermState(
_toggle(sequences, old.overline, new.overline, "53", "55")
_toggle2(sequences, old.subscript, old.subscript, new.superscript, new.superscript, "73", "74", "75")
- if new.bg != old.bg:
+ if new.bg != old.bg
sequences.insert(new.bg.bg())
- if new.fg != old.fg:
+ if new.fg != old.fg
sequences.insert(new.fg.fg())
- if new.underline_color != old.underline_color:
+ if new.underline_color != old.underline_color
sequences.insert(new.underline_color.underline())
- if sequences.length == 0:
+ if sequences.length == 0
return ""
return CSI ++ ";".join(sequences) ++ "m"
-func _add_ansi_sequences(text:Text, prev_state:_TermState -> Text):
- if text == "lparen": return "("
- else if text == "rparen": return ")"
- else if text == "@" or text == "at": return "@"
+func _add_ansi_sequences(text:Text, prev_state:_TermState -> Text)
+ if text == "lparen" return "("
+ else if text == "rparen" return ")"
+ else if text == "@" or text == "at" return "@"
parts := (
text.pattern_captures($Pat/{0+..}:{0+..}/) or
return "@("++_for_terminal(Colorful.from_text(text), prev_state)++")"
)
attributes := parts[1].split_pattern($Pat/{0+space},{0+space}/)
new_state := prev_state
- for attr in attributes:
- if attr.starts_with("fg="):
+ for attr in attributes
+ if attr.starts_with("fg=")
new_state.fg = _Color.from_text(attr.from(4))!
- else if attr.starts_with("bg="):
+ else if attr.starts_with("bg=")
new_state.bg = _Color.from_text(attr.from(4))!
- else if attr.starts_with("ul="):
+ else if attr.starts_with("ul=")
new_state.underline_color = _Color.from_text(attr.from(4))!
- else if color := _Color.from_text(attr):
+ else if color := _Color.from_text(attr)
new_state.fg = color
- else if attr == "b" or attr == "bold":
+ else if attr == "b" or attr == "bold"
new_state.bold = yes
- else if attr == "d" or attr == "dim":
+ else if attr == "d" or attr == "dim"
new_state.dim = yes
- else if attr == "i" or attr == "italic":
+ else if attr == "i" or attr == "italic"
new_state.italic = yes
- else if attr == "u" or attr == "underline":
+ else if attr == "u" or attr == "underline"
new_state.underline = yes
- else if attr == "B" or attr == "blink":
+ else if attr == "B" or attr == "blink"
new_state.blink = yes
- else if attr == "r" or attr == "reverse":
+ else if attr == "r" or attr == "reverse"
new_state.reverse = yes
- else if attr == "fraktur":
+ else if attr == "fraktur"
new_state.fraktur = yes
- else if attr == "frame":
+ else if attr == "frame"
new_state.frame = yes
- else if attr == "encircle":
+ else if attr == "encircle"
new_state.encircle = yes
- else if attr == "overline":
+ else if attr == "overline"
new_state.overline = yes
- else if attr == "super" or attr == "superscript":
+ else if attr == "super" or attr == "superscript"
new_state.superscript = yes
- else if attr == "sub" or attr == "subscript":
+ else if attr == "sub" or attr == "subscript"
new_state.subscript = yes
- else:
+ else
fail("Invalid attribute: '$attr'")
result := prev_state.apply(new_state)
- result ++= parts[2].map_pattern(recursive=no, $Pat/@(?)/, func(m:PatternMatch): _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 6817fca1..2dd5aaf7 100644
--- a/examples/commands/commands.tm
+++ b/examples/commands/commands.tm
@@ -6,86 +6,86 @@ use -lunistring
extern run_command : func(exe:Text, args:[Text], env:{Text=Text}, input:[Byte]?, output:&[Byte]?, error:&[Byte]? -> Int32)
extern command_by_line : func(exe:Text, args:[Text], env:{Text=Text} -> func(->Text?)?)
-enum ExitType(Exited(status:Int32), Signaled(signal:Int32), Failed):
- func succeeded(e:ExitType -> Bool):
- when e is Exited(status): return (status == 0)
- else: return no
+enum ExitType(Exited(status:Int32), Signaled(signal:Int32), Failed)
+ func succeeded(e:ExitType -> Bool)
+ when e is Exited(status) return (status == 0)
+ else return no
- func or_fail(e:ExitType, message:Text?=none):
- if not e.succeeded():
+ func or_fail(e:ExitType, message:Text?=none)
+ if not e.succeeded()
fail(message or "Program failed: $e")
-struct ProgramResult(stdout:[Byte], stderr:[Byte], exit_type:ExitType):
- func or_fail(r:ProgramResult, message:Text?=none -> ProgramResult):
- when r.exit_type is Exited(status):
- if status == 0:
+struct ProgramResult(stdout:[Byte], stderr:[Byte], exit_type:ExitType)
+ func or_fail(r:ProgramResult, message:Text?=none -> ProgramResult)
+ when r.exit_type is Exited(status)
+ if status == 0
return r
- else: fail(message or "Program failed: $r")
+ else fail(message or "Program failed: $r")
fail(message or "Program failed: $r")
- func output_text(r:ProgramResult, trim_newline=yes -> Text?):
- when r.exit_type is Exited(status):
- if status == 0:
- if text := Text.from_bytes(r.stdout):
- if trim_newline:
+ func output_text(r:ProgramResult, trim_newline=yes -> Text?)
+ when r.exit_type is Exited(status)
+ if status == 0
+ if text := Text.from_bytes(r.stdout)
+ if trim_newline
text = text.without_suffix(\n)
return text
- else: return none
+ else return none
return none
- func error_text(r:ProgramResult -> Text?):
- when r.exit_type is Exited(status):
- if status == 0:
+ func error_text(r:ProgramResult -> Text?)
+ when r.exit_type is Exited(status)
+ if status == 0
return Text.from_bytes(r.stderr)
- else: return none
+ else return none
return none
- func succeeded(r:ProgramResult -> Bool):
- when r.exit_type is Exited(status):
+ func succeeded(r:ProgramResult -> Bool)
+ when r.exit_type is Exited(status)
return (status == 0)
- else:
+ else
return no
-struct Command(command:Text, args:[Text]=[], env:{Text=Text}={}):
- func from_path(path:Path, args:[Text]=[], env:{Text=Text}={} -> Command):
+struct Command(command:Text, args:[Text]=[], env:{Text=Text}={})
+ func from_path(path:Path, args:[Text]=[], env:{Text=Text}={} -> Command)
return Command(Text(path), args, env)
- func result(command:Command, input="", input_bytes:[Byte]=[] -> ProgramResult):
- if input.length > 0:
+ func result(command:Command, input="", input_bytes:[Byte]=[] -> ProgramResult)
+ if input.length > 0
(&input_bytes).insert_all(input.bytes())
stdout : [Byte] = []
stderr : [Byte] = []
status := run_command(command.command, command.args, command.env, input_bytes, &stdout, &stderr)
- if inline C : Bool { WIFEXITED(_$status) }:
+ if inline C : Bool { WIFEXITED(_$status) }
return ProgramResult(stdout, stderr, ExitType.Exited(inline C : Int32 { WEXITSTATUS(_$status) }))
- if inline C : Bool { WIFSIGNALED(_$status) }:
+ if inline C : Bool { WIFSIGNALED(_$status) }
return ProgramResult(stdout, stderr, ExitType.Signaled(inline C : Int32 { WTERMSIG(_$status) }))
return ProgramResult(stdout, stderr, ExitType.Failed)
- func run(command:Command, -> ExitType):
+ func run(command:Command, -> ExitType)
status := run_command(command.command, command.args, command.env, none, none, none)
- if inline C : Bool { WIFEXITED(_$status) }:
+ if inline C : Bool { WIFEXITED(_$status) }
return ExitType.Exited(inline C : Int32 { WEXITSTATUS(_$status) })
- if inline C : Bool { WIFSIGNALED(_$status) }:
+ if inline C : Bool { WIFSIGNALED(_$status) }
return ExitType.Signaled(inline C : Int32 { WTERMSIG(_$status) })
return ExitType.Failed
- func get_output(command:Command, input="", trim_newline=yes -> Text?):
+ func get_output(command:Command, input="", trim_newline=yes -> Text?)
return command.result(input=input).output_text(trim_newline=trim_newline)
- func get_output_bytes(command:Command, input="", input_bytes:[Byte]=[] -> [Byte]?):
+ func get_output_bytes(command:Command, input="", input_bytes:[Byte]=[] -> [Byte]?)
result := command.result(input=input, input_bytes=input_bytes)
- when result.exit_type is Exited(status):
- if status == 0: return result.stdout
+ when result.exit_type is Exited(status)
+ if status == 0 return result.stdout
return none
- else: return none
+ else return none
- func by_line(command:Command -> func(->Text?)?):
+ func by_line(command:Command -> func(->Text?)?)
return command_by_line(command.command, command.args, command.env)
diff --git a/examples/game/box.tm b/examples/game/box.tm
index dda3dd83..41ae10e5 100644
--- a/examples/game/box.tm
+++ b/examples/game/box.tm
@@ -2,6 +2,6 @@
use ./world.tm
use ./raylib.tm
-struct Box(pos:Vector2, size=Vector2(50, 50), color=Color(0x80,0x80,0x80)):
- func draw(b:Box):
+struct Box(pos:Vector2, size=Vector2(50, 50), color=Color(0x80,0x80,0x80))
+ func draw(b:Box)
DrawRectangleV(b.pos, b.size, b.color)
diff --git a/examples/game/game.tm b/examples/game/game.tm
index ce08c329..f82e4f40 100644
--- a/examples/game/game.tm
+++ b/examples/game/game.tm
@@ -2,7 +2,7 @@
use ./raylib.tm
use ./world.tm
-func main(map=(./map.txt)):
+func main(map=(./map.txt))
InitWindow(1600, 900, CString("raylib [core] example - 2d camera"))
map_contents := map.read() or exit("Could not find the game map: $map")
@@ -16,7 +16,7 @@ func main(map=(./map.txt)):
SetTargetFPS(60)
- while not WindowShouldClose():
+ while not WindowShouldClose()
dt := GetFrameTime()
world.update(dt)
diff --git a/examples/game/player.tm b/examples/game/player.tm
index 7f14f51e..9f166d9e 100644
--- a/examples/game/player.tm
+++ b/examples/game/player.tm
@@ -2,14 +2,14 @@
use ./world.tm
use ./raylib.tm
-struct Player(pos,prev_pos:Vector2):
+struct Player(pos,prev_pos:Vector2)
WALK_SPEED := Num32(500.)
ACCEL := Num32(0.3)
FRICTION := Num32(0.99)
SIZE := Vector2(30, 30)
COLOR := Color(0x60, 0x60, 0xbF)
- func update(p:@Player):
+ func update(p:@Player)
target_x := inline C:Num32 {
(Num32_t)((IsKeyDown(KEY_A) ? -1 : 0) + (IsKeyDown(KEY_D) ? 1 : 0))
}
@@ -24,5 +24,5 @@ struct Player(pos,prev_pos:Vector2):
p.prev_pos, p.pos = p.pos, p.pos + World.DT*vel
- func draw(p:Player):
+ func draw(p:Player)
DrawRectangleV(p.pos, Player.SIZE, Player.COLOR)
diff --git a/examples/game/raylib.tm b/examples/game/raylib.tm
index 5e58e996..b2ba53d7 100644
--- a/examples/game/raylib.tm
+++ b/examples/game/raylib.tm
@@ -4,44 +4,44 @@ use <raylib.h>
use <raymath.h>
struct Color(r,g,b:Byte,a=Byte(255); extern)
-struct Rectangle(x,y,width,height:Num32; extern):
- func draw(r:Rectangle, color:Color):
+struct Rectangle(x,y,width,height:Num32; extern)
+ func draw(r:Rectangle, color:Color)
DrawRectangleRec(r, color)
-struct Vector2(x,y:Num32; extern):
+struct Vector2(x,y:Num32; extern)
ZERO := Vector2(0, 0)
- func plus(a,b:Vector2->Vector2; inline):
+ func plus(a,b:Vector2->Vector2; inline)
return Vector2(a.x+b.x, a.y+b.y)
- func minus(a,b:Vector2->Vector2; inline):
+ func minus(a,b:Vector2->Vector2; inline)
return Vector2(a.x-b.x, a.y-b.y)
- func times(a,b:Vector2->Vector2; inline):
+ func times(a,b:Vector2->Vector2; inline)
return Vector2(a.x*b.x, a.y*b.y)
- func negative(v:Vector2->Vector2; inline):
+ func negative(v:Vector2->Vector2; inline)
return Vector2(-v.x, -v.y)
- func dot(a,b:Vector2->Num32; inline):
+ func dot(a,b:Vector2->Num32; inline)
return ((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y))
- func cross(a,b:Vector2->Num32; inline):
+ func cross(a,b:Vector2->Num32; inline)
return a.x*b.y - a.y*b.x
- func scaled_by(v:Vector2, k:Num32->Vector2; inline):
+ func scaled_by(v:Vector2, k:Num32->Vector2; inline)
return Vector2(v.x*k, v.y*k)
- func divided_by(v:Vector2, divisor:Num32->Vector2; inline):
+ func divided_by(v:Vector2, divisor:Num32->Vector2; inline)
return Vector2(v.x/divisor, v.y/divisor)
- func length(v:Vector2->Num32; inline):
+ func length(v:Vector2->Num32; inline)
return (v.x*v.x + v.y*v.y).sqrt()
- func dist(a,b:Vector2->Num32; inline):
+ func dist(a,b:Vector2->Num32; inline)
return a.minus(b).length()
- func angle(v:Vector2->Num32; inline):
+ func angle(v:Vector2->Num32; inline)
return Num32.atan2(v.y, v.x)
- func norm(v:Vector2->Vector2; inline):
- if v.x == 0 and v.y == 0:
+ func norm(v:Vector2->Vector2; inline)
+ if v.x == 0 and v.y == 0
return v
len := v.length()
return Vector2(v.x/len, v.y/len)
- func rotated(v:Vector2, radians:Num32 -> Vector2):
+ func rotated(v:Vector2, radians:Num32 -> Vector2)
cos := radians.cos() or return v
sin := radians.sin() or return v
return Vector2(cos*v.x - sin*v.y, sin*v.x + cos*v.y)
- func mix(a,b:Vector2, amount:Num32 -> Vector2):
+ func mix(a,b:Vector2, amount:Num32 -> Vector2)
return Vector2(
amount.mix(a.x, b.x),
amount.mix(a.y, b.y),
diff --git a/examples/game/world.tm b/examples/game/world.tm
index e8255ab8..0de8ea4b 100644
--- a/examples/game/world.tm
+++ b/examples/game/world.tm
@@ -5,7 +5,7 @@ use ./raylib.tm
use ./box.tm
# Return a displacement relative to `a` that will push it out of `b`
-func solve_overlap(a_pos:Vector2, a_size:Vector2, b_pos:Vector2, b_size:Vector2 -> Vector2):
+func solve_overlap(a_pos:Vector2, a_size:Vector2, b_pos:Vector2, b_size:Vector2 -> Vector2)
a_left := a_pos.x
a_right := a_pos.x + a_size.x
a_top := a_pos.y
@@ -21,68 +21,68 @@ func solve_overlap(a_pos:Vector2, a_size:Vector2, b_pos:Vector2, b_size:Vector2
overlap_y := (a_bottom _min_ b_bottom) - (a_top _max_ b_top)
# If either axis is not overlapping, then there is no collision:
- if overlap_x <= 0 or overlap_y <= 0:
+ if overlap_x <= 0 or overlap_y <= 0
return Vector2(0, 0)
- if overlap_x < overlap_y:
- if a_right > b_left and a_right < b_right:
+ if overlap_x < overlap_y
+ if a_right > b_left and a_right < b_right
return Vector2(-(overlap_x), 0)
- else if a_left < b_right and a_left > b_left:
+ else if a_left < b_right and a_left > b_left
return Vector2(overlap_x, 0)
- else:
- if a_top < b_bottom and a_top > b_top:
+ else
+ if a_top < b_bottom and a_top > b_top
return Vector2(0, overlap_y)
- else if a_bottom > b_top and a_bottom < b_bottom:
+ else if a_bottom > b_top and a_bottom < b_bottom
return Vector2(0, -overlap_y)
return Vector2(0, 0)
-struct World(player:@Player, goal:@Box, boxes:@[@Box], dt_accum=Num32(0.0), won=no):
+struct World(player:@Player, goal:@Box, boxes:@[@Box], dt_accum=Num32(0.0), won=no)
DT := (Num32(1.)/Num32(60.))
STIFFNESS := Num32(0.3)
- func update(w:@World, dt:Num32):
+ func update(w:@World, dt:Num32)
w.dt_accum += dt
- while w.dt_accum > 0:
+ while w.dt_accum > 0
w.update_once()
w.dt_accum -= World.DT
- func update_once(w:@World):
+ func update_once(w:@World)
w.player.update()
- if solve_overlap(w.player.pos, Player.SIZE, w.goal.pos, w.goal.size) != Vector2(0,0):
+ if solve_overlap(w.player.pos, Player.SIZE, w.goal.pos, w.goal.size) != Vector2(0,0)
w.won = yes
# Resolve player overlapping with any boxes:
- for i in 3:
- for b in w.boxes:
+ for i in 3
+ for b in w.boxes
w.player.pos += World.STIFFNESS * solve_overlap(w.player.pos, Player.SIZE, b.pos, b.size)
- func draw(w:@World):
- for b in w.boxes:
+ func draw(w:@World)
+ for b in w.boxes
b.draw()
w.goal.draw()
w.player.draw()
- if w.won:
+ if w.won
DrawText(CString("WINNER"), GetScreenWidth()/Int32(2)-Int32(48*3), GetScreenHeight()/Int32(2)-Int32(24), 48, Color(0,0,0))
- func load_map(w:@World, map:Text):
- if map.has("[]"):
+ func load_map(w:@World, map:Text)
+ if map.has("[]")
map = map.translate({"[]"="#", "@ "="@", " "=" "})
w.boxes = @[]
box_size := Vector2(50., 50.)
- for y,line in map.lines():
- for x,cell in line.split():
- if cell == "#":
+ for y,line in map.lines()
+ for x,cell in line.split()
+ if cell == "#"
pos := Vector2((Num32(x)-1) * box_size.x, (Num32(y)-1) * box_size.y)
box := @Box(pos, size=box_size, color=Color(0x80,0x80,0x80))
w.boxes.insert(box)
- else if cell == "@":
+ else if cell == "@"
pos := Vector2((Num32(x)-1) * box_size.x, (Num32(y)-1) * box_size.y)
pos += box_size/Num32(2) - Player.SIZE/Num32(2)
w.player = @Player(pos,pos)
- else if cell == "?":
+ else if cell == "?"
pos := Vector2((Num32(x)-1) * box_size.x, (Num32(y)-1) * box_size.y)
w.goal.pos = pos
diff --git a/examples/http-server/connection-queue.tm b/examples/http-server/connection-queue.tm
index 3c8058d5..29759f38 100644
--- a/examples/http-server/connection-queue.tm
+++ b/examples/http-server/connection-queue.tm
@@ -1,22 +1,22 @@
use pthreads
-func _assert_success(name:Text, val:Int32; inline):
+func _assert_success(name:Text, val:Int32; inline)
fail("$name() failed!") if val < 0
-struct ConnectionQueue(_connections:@[Int32]=@[], _mutex=pthread_mutex_t.new(), _cond=pthread_cond_t.new()):
- func enqueue(queue:ConnectionQueue, connection:Int32):
+struct ConnectionQueue(_connections:@[Int32]=@[], _mutex=pthread_mutex_t.new(), _cond=pthread_cond_t.new())
+ func enqueue(queue:ConnectionQueue, connection:Int32)
queue._mutex.lock()
queue._connections.insert(connection)
queue._mutex.unlock()
queue._cond.signal()
- func dequeue(queue:ConnectionQueue -> Int32):
+ func dequeue(queue:ConnectionQueue -> Int32)
conn : Int32? = none
queue._mutex.lock()
- while queue._connections.length == 0:
+ while queue._connections.length == 0
queue._cond.wait(queue._mutex)
conn = queue._connections.pop(1)
diff --git a/examples/http-server/http-server.tm b/examples/http-server/http-server.tm
index 649a9e12..b814cdcb 100644
--- a/examples/http-server/http-server.tm
+++ b/examples/http-server/http-server.tm
@@ -15,12 +15,12 @@ use patterns
use ./connection-queue.tm
-func serve(port:Int32, handler:func(request:HTTPRequest -> HTTPResponse), num_threads=16):
+func serve(port:Int32, handler:func(request:HTTPRequest -> HTTPResponse), num_threads=16)
connections := ConnectionQueue()
workers : &[@pthread_t] = &[]
- for i in num_threads:
- workers.insert(pthread_t.new(func():
- repeat:
+ for i in num_threads
+ workers.insert(pthread_t.new(func()
+ repeat
connection := connections.dequeue()
request_text := inline C : Text {
Text_t request = EMPTY_TEXT;
@@ -62,17 +62,17 @@ func serve(port:Int32, handler:func(request:HTTPRequest -> HTTPResponse), num_th
s
}
- repeat:
+ repeat
conn := inline C : Int32 { accept(_$sock, NULL, NULL) }
stop if conn < 0
connections.enqueue(conn)
say("Shutting down...")
- for w in workers:
+ for w in workers
w.cancel()
-struct HTTPRequest(method:Text, path:Text, version:Text, headers:[Text], body:Text):
- func from_text(text:Text -> HTTPRequest?):
+struct HTTPRequest(method:Text, path:Text, version:Text, headers:[Text], body:Text)
+ func from_text(text:Text -> HTTPRequest?)
m := text.pattern_captures($Pat'{word} {..} HTTP/{..}{crlf}{..}') or return none
method := m[1]
path := m[2].replace_pattern($Pat'{2+ /}', '/')
@@ -82,8 +82,8 @@ struct HTTPRequest(method:Text, path:Text, version:Text, headers:[Text], body:Te
body := rest[-1]
return HTTPRequest(method, path, version, headers, body)
-struct HTTPResponse(body:Text, status=200, content_type="text/plain", headers:{Text=Text}={}):
- func bytes(r:HTTPResponse -> [Byte]):
+struct HTTPResponse(body:Text, status=200, content_type="text/plain", headers:{Text=Text}={})
+ func bytes(r:HTTPResponse -> [Byte])
body_bytes := r.body.bytes()
extra_headers := (++: "$k: $v$(\r\n)" for k,v in r.headers) or ""
return "
@@ -95,55 +95,55 @@ struct HTTPResponse(body:Text, status=200, content_type="text/plain", headers:{T
$\r$\n
".bytes() ++ body_bytes
-func _content_type(file:Path -> Text):
- when file.extension() is "html": return "text/html"
- is "tm": return "text/html"
- is "js": return "text/javascript"
- is "css": return "text/css"
- else: return "text/plain"
-
-enum RouteEntry(ServeFile(file:Path), Redirect(destination:Text)):
- func respond(entry:RouteEntry, request:HTTPRequest -> HTTPResponse):
- when entry is ServeFile(file):
- body := if file.can_execute():
+func _content_type(file:Path -> Text)
+ when file.extension() is "html" return "text/html"
+ is "tm" return "text/html"
+ is "js" return "text/javascript"
+ is "css" return "text/css"
+ else return "text/plain"
+
+enum RouteEntry(ServeFile(file:Path), Redirect(destination:Text))
+ func respond(entry:RouteEntry, request:HTTPRequest -> HTTPResponse)
+ when entry is ServeFile(file)
+ body := if file.can_execute()
Command(Text(file)).get_output()!
- else:
+ else
file.read()!
return HTTPResponse(body, content_type=_content_type(file))
- is Redirect(destination):
+ is Redirect(destination)
return HTTPResponse("Found", 302, headers={"Location"=destination})
-func load_routes(directory:Path -> {Text=RouteEntry}):
+func load_routes(directory:Path -> {Text=RouteEntry})
routes : &{Text=RouteEntry} = &{}
- for file in (directory ++ (./*)).glob():
+ for file in (directory ++ (./*)).glob()
skip unless file.is_file()
contents := file.read() or skip
server_path := "/" ++ "/".join(file.relative_to(directory).components)
- if file.base_name() == "index.html":
+ if file.base_name() == "index.html"
canonical := server_path.without_suffix("index.html")
routes[server_path] = Redirect(canonical)
routes[canonical] = ServeFile(file)
- else if file.extension() == "html":
+ else if file.extension() == "html"
canonical := server_path.without_suffix(".html")
routes[server_path] = Redirect(canonical)
routes[canonical] = ServeFile(file)
- else if file.extension() == "tm":
+ else if file.extension() == "tm"
canonical := server_path.without_suffix(".tm")
routes[server_path] = Redirect(canonical)
routes[canonical] = ServeFile(file)
- else:
+ else
routes[server_path] = ServeFile(file)
return routes[]
-func main(directory:Path, port=Int32(8080)):
+func main(directory:Path, port=Int32(8080))
say("Serving on port $port")
routes := load_routes(directory)
say(" Hosting: $routes")
- serve(port, func(request:HTTPRequest):
- if handler := routes[request.path]:
+ serve(port, func(request:HTTPRequest)
+ if handler := routes[request.path]
return handler.respond(request)
- else:
+ else
return HTTPResponse("Not found!", 404)
)
diff --git a/examples/http-server/sample-site/random.tm b/examples/http-server/sample-site/random.tm
index 29b93be7..153ac2af 100755
--- a/examples/http-server/sample-site/random.tm
+++ b/examples/http-server/sample-site/random.tm
@@ -1,7 +1,7 @@
#!/bin/env tomo
use random
-func main():
+func main()
say("
<!DOCTYPE HTML>
<html>
diff --git a/examples/http/http.tm b/examples/http/http.tm
index 048ffaab..39cbfd6d 100644
--- a/examples/http/http.tm
+++ b/examples/http/http.tm
@@ -7,9 +7,9 @@ struct HTTPResponse(code:Int, body:Text)
enum _Method(GET, POST, PUT, PATCH, DELETE)
-func _send(method:_Method, url:Text, data:Text?, headers:[Text]=[] -> HTTPResponse):
+func _send(method:_Method, url:Text, data:Text?, headers:[Text]=[] -> HTTPResponse)
chunks : @[Text] = @[]
- save_chunk := func(chunk:CString, size:Int64, n:Int64):
+ save_chunk := func(chunk:CString, size:Int64, n:Int64)
chunks.insert(inline C:Text {
Text$format("%.*s", _$size*_$n, _$chunk)
})
@@ -23,45 +23,45 @@ func _send(method:_Method, url:Text, data:Text?, headers:[Text]=[] -> HTTPRespon
curl_easy_setopt(curl, CURLOPT_WRITEDATA, _$save_chunk.userdata);
}
- defer:
+ defer
inline C {
if (chunk)
curl_slist_free_all(chunk);
curl_easy_cleanup(curl);
}
- when method is POST:
+ when method is POST
inline C {
curl_easy_setopt(curl, CURLOPT_POST, 1L);
}
- if posting := data:
+ if posting := data
inline C {
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Text$as_c_string(_$posting));
}
- is PUT:
+ is PUT
inline C {
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
}
- if putting := data:
+ if putting := data
inline C {
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Text$as_c_string(_$putting));
}
- is PATCH:
+ is PATCH
inline C {
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
}
- if patching := data:
+ if patching := data
inline C {
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, Text$as_c_string(_$patching));
}
- is DELETE:
+ is DELETE
inline C {
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
}
- else:
+ else
pass
- for header in headers:
+ for header in headers
inline C {
chunk = curl_slist_append(chunk, Text$as_c_string(_$header));
}
@@ -81,22 +81,22 @@ func _send(method:_Method, url:Text, data:Text?, headers:[Text]=[] -> HTTPRespon
}
return HTTPResponse(Int(code), "".join(chunks))
-func get(url:Text, headers:[Text]=[] -> HTTPResponse):
+func get(url:Text, headers:[Text]=[] -> HTTPResponse)
return _send(GET, url, none, headers)
-func post(url:Text, data="", headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse):
+func post(url:Text, data="", headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse)
return _send(POST, url, data, headers)
-func put(url:Text, data="", headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse):
+func put(url:Text, data="", headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse)
return _send(PUT, url, data, headers)
-func patch(url:Text, data="", headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse):
+func patch(url:Text, data="", headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse)
return _send(PATCH, url, data, headers)
-func delete(url:Text, data:Text?=none, headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse):
+func delete(url:Text, data:Text?=none, headers=["Content-Type: application/json", "Accept: application/json"] -> HTTPResponse)
return _send(DELETE, url, data, headers)
-func main():
+func main()
say("GET:")
say(get("https://httpbin.org/get").body)
say("Waiting 1sec...")
diff --git a/examples/ini/ini.tm b/examples/ini/ini.tm
index 3fa4c834..7d53d7e5 100644
--- a/examples/ini/ini.tm
+++ b/examples/ini/ini.tm
@@ -9,7 +9,7 @@ _HELP := "
$_USAGE
"
-func parse_ini(path:Path -> {Text={Text=Text}}):
+func parse_ini(path:Path -> {Text={Text=Text}})
text := path.read() or exit("Could not read INI file: $\[31;1]$(path)$\[]")
sections : @{Text=@{Text=Text}} = @{}
current_section : @{Text=Text} = @{}
@@ -17,30 +17,30 @@ func parse_ini(path:Path -> {Text={Text=Text}}):
# Line wraps:
text = text.replace_pattern($Pat/\{1 nl}{0+space}/, " ")
- for line in text.lines():
+ for line in text.lines()
line = line.trim()
skip if line.starts_with(";") or line.starts_with("#")
- if line.matches_pattern($Pat/[?]/):
+ if line.matches_pattern($Pat/[?]/)
section_name := line.replace($Pat/[?]/, "\1").trim().lower()
current_section = @{}
sections[section_name] = current_section
- else if line.matches_pattern($Pat/{..}={..}/):
+ 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[]}
-func main(path:Path, key:Text?):
+func main(path:Path, key:Text?)
keys := (key or "").split($|/|)
- if keys.length > 2:
+ if keys.length > 2
exit("
Too many arguments!
$_USAGE
")
data := parse_ini(path)
- if keys.length < 1 or keys[1] == '*':
+ if keys.length < 1 or keys[1] == '*'
say("$data")
return
@@ -49,7 +49,7 @@ func main(path:Path, key:Text?):
Invalid section name: $\[31;1]$section$\[]
Valid names: $\[1]$(", ".join([k.quoted() for k in data.keys]))$\[]
")
- if keys.length < 2 or keys[2] == '*':
+ if keys.length < 2 or keys[2] == '*'
say("$section_data")
return
diff --git a/examples/learnxiny.tm b/examples/learnxiny.tm
index 6a3b7e21..d05c92f2 100644
--- a/examples/learnxiny.tm
+++ b/examples/learnxiny.tm
@@ -3,7 +3,7 @@
# which is compiled to a binary using your C compiler of choice.
# To begin with, let's define a main function:
-func main():
+func main()
# This function's code will run if you run this file.
# Print to the console
@@ -45,11 +45,11 @@ func main():
my_bool := yes
# Conditionals:
- if my_bool:
+ if my_bool
say("It worked!")
- else if my_variable == 99:
+ else if my_variable == 99
say("else if")
- else:
+ else
say("else")
# Arrays:
@@ -73,11 +73,11 @@ func main():
# exit.
# Iteration:
- for num in my_numbers:
+ for num in my_numbers
>> num
# Optionally, you can use an iteration index as well:
- for index, num in my_numbers:
+ for index, num in my_numbers
pass # Pass means "do nothing"
# Arrays can be created with array comprehensions, which are loops:
@@ -87,15 +87,15 @@ func main():
= [100, 300]
# Loop control flow uses "skip" and "stop"
- for x in my_numbers:
- for y in my_numbers:
- if x == y:
+ for x in my_numbers
+ for y in my_numbers
+ if x == y
skip
# For readability, you can also use postfix conditionals:
skip if x == y
- if x + y == 60:
+ if x + y == 60
# Skip or stop can specify a loop variable if you want to
# affect an enclosing loop:
stop x
@@ -123,10 +123,10 @@ func main():
empty_table : {Text=Int} = {}
# Tables can be iterated over either by key or key,value:
- for key in table:
+ for key in table
pass
- for key, value in table:
+ for key, value in table
pass
# Tables also have ".keys" and ".values" fields to explicitly access the
@@ -213,15 +213,15 @@ func main():
# Functions must be declared at the top level of a file and must specify the
# types of all of their arguments and return value (if any):
-func add(x:Int, y:Int -> Int):
+func add(x:Int, y:Int -> Int)
return x + y
# Default values for arguments can be provided in place of a type (the type is
# inferred from the default value):
-func show_both(first:Int, second=0 -> Text):
+func show_both(first:Int, second=0 -> Text)
return "first=$first second=$second"
-func demo_keyword_args():
+func demo_keyword_args()
>> show_both(1, 2)
= "first=1 second=2"
@@ -244,27 +244,27 @@ func takes_many_types(
pointer_to_mutable_array_of_ints:@[Int],
optional_int:Int?,
function_from_int_to_text:func(x:Int -> Text),
-):
+)
pass
# Now let's define our own datastructure, a humble struct:
-struct Person(name:Text, age:Int):
+struct Person(name:Text, age:Int)
# We can define constants here if we want to:
max_age := 122
# Methods are defined here as well:
- func say_age(self:Person):
+ func say_age(self:Person)
say("My age is $self.age")
# If you want to mutate a value, you must have a mutable pointer:
- func increase_age(self:@Person, amount=1):
+ func increase_age(self:@Person, amount=1)
self.age += amount
# Methods don't have to take a Person as their first argument:
- func get_cool_name(->Text):
+ func get_cool_name(->Text)
return "Blade"
-func demo_structs():
+func demo_structs()
# Creating a struct:
alice := Person("Alice", 30)
>> alice
@@ -303,23 +303,23 @@ enum Shape(
Point,
Circle(radius:Num),
Rectangle(width:Num, height:Num),
-):
+)
# Just like with structs, you define methods and constants inside a level
# of indentation:
- func get_area(self:Shape->Num):
+ func get_area(self:Shape->Num)
# In order to work with an enum, it's most often handy to use a 'when'
# statement to get the internal values:
- when self is Point:
+ when self is Point
return 0
- is Circle(r):
+ is Circle(r)
return Num.PI * r^2
- is Rectangle(w, h):
+ is Rectangle(w, h)
return w * h
# 'when' statements are checked for exhaustiveness, so the compiler
# will give an error if you forgot any cases. You can also use 'else:'
# if you want a fallback to handle other cases.
-func demo_enums():
+func demo_enums()
# Enums are constructed like this:
my_shape := Shape.Circle(1.0)
@@ -338,16 +338,16 @@ func demo_enums():
>> {my_shape="nice"}
= {Shape.Circle(1)="nice"}
-func demo_lambdas():
+func demo_lambdas()
# Lambdas, or anonymous functions, can be used like this:
- add_one := func(x:Int): x + 1
+ add_one := func(x:Int) x + 1
>> add_one(5)
= 6
# Lambdas can capture closure values, but only as a snapshot from when the
# lambda was created:
n := 10
- add_n := func(x:Int): x + n
+ add_n := func(x:Int) x + n
>> add_n(5)
= 15
diff --git a/examples/log/log.tm b/examples/log/log.tm
index 7375d5f6..c6c45a21 100644
--- a/examples/log/log.tm
+++ b/examples/log/log.tm
@@ -5,7 +5,7 @@ timestamp_format := CString("%F %T")
logfiles : @{Path} = @{/}
-func _timestamp(->Text):
+func _timestamp(->Text)
c_str := inline C:CString {
char *str = GC_MALLOC_ATOMIC(20);
time_t t; time(&t);
@@ -15,33 +15,33 @@ func _timestamp(->Text):
}
return c_str.as_text()
-func info(text:Text, newline=yes):
+func info(text:Text, newline=yes)
say("$\[2]⚫ $text$\[]", newline)
- for file in logfiles:
+ for file in logfiles
file.append("$(_timestamp()) [info] $text$\n")
-func debug(text:Text, newline=yes):
+func debug(text:Text, newline=yes)
say("$\[32]🟢 $text$\[]", newline)
- for file in logfiles:
+ for file in logfiles
file.append("$(_timestamp()) [debug] $text$\n")
-func warn(text:Text, newline=yes):
+func warn(text:Text, newline=yes)
say("$\[33;1]🟡 $text$\[]", newline)
- for file in logfiles:
+ for file in logfiles
file.append("$(_timestamp()) [warn] $text$\n")
-func error(text:Text, newline=yes):
+func error(text:Text, newline=yes)
say("$\[31;1]🔴 $text$\[]", newline)
- for file in logfiles:
+ for file in logfiles
file.append("$(_timestamp()) [error] $text$\n")
-func add_logfile(file:Path):
+func add_logfile(file:Path)
logfiles.add(file)
-func remove_logfile(file:Path):
+func remove_logfile(file:Path)
logfiles.remove(file)
-func main():
+func main()
add_logfile((./log.txt))
>> info("Hello")
>> debug("Hello")
diff --git a/examples/patterns/patterns.tm b/examples/patterns/patterns.tm
index 15226848..3e671b80 100644
--- a/examples/patterns/patterns.tm
+++ b/examples/patterns/patterns.tm
@@ -2,46 +2,46 @@ use ./patterns.c
struct PatternMatch(text:Text, index:Int, captures:[Text])
-lang Pat:
- convert(text:Text -> Pat):
+lang Pat
+ convert(text:Text -> Pat)
return inline C : Pat { Pattern$escape_text(_$text); }
- convert(n:Int -> Pat):
+ convert(n:Int -> Pat)
return Pat.from_text("$n")
-extend Text:
- func matches_pattern(text:Text, pattern:Pat -> Bool):
+extend Text
+ func matches_pattern(text:Text, pattern:Pat -> Bool)
return inline C : Bool { Pattern$matches(_$text, _$pattern); }
- func pattern_captures(text:Text, pattern:Pat -> [Text]?):
+ func pattern_captures(text:Text, pattern:Pat -> [Text]?)
return inline C : [Text]? { Pattern$captures(_$text, _$pattern); }
- func replace_pattern(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 translate_patterns(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_pattern(text:Text, pattern:Pat -> Bool):
+ func has_pattern(text:Text, pattern:Pat -> Bool)
return inline C : Bool { Pattern$has(_$text, _$pattern); }
- func find_patterns(text:Text, pattern:Pat -> [PatternMatch]):
+ func find_patterns(text:Text, pattern:Pat -> [PatternMatch])
return inline C : [PatternMatch] { Pattern$find_all(_$text, _$pattern); }
- func by_pattern(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_pattern(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_pattern(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_pattern(text:Text, pattern:Pat -> [Text]):
+ func split_pattern(text:Text, pattern:Pat -> [Text])
return inline C : [Text] { Pattern$split(_$text, _$pattern); }
- func by_pattern_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_pattern(text:Text, pattern=$Pat"{space}", left=yes, right=yes -> Text):
+ func trim_pattern(text:Text, pattern=$Pat"{space}", left=yes, right=yes -> Text)
return inline C : Text { Pattern$trim(_$text, _$pattern, _$left, _$right); }
diff --git a/examples/pthreads/pthreads.tm b/examples/pthreads/pthreads.tm
index 3be052b4..61f94d0a 100644
--- a/examples/pthreads/pthreads.tm
+++ b/examples/pthreads/pthreads.tm
@@ -1,8 +1,8 @@
# A Posix Threads (pthreads) wrapper
use <pthread.h>
-struct pthread_mutex_t(; extern, opaque):
- func new(->@pthread_mutex_t):
+struct pthread_mutex_t(; extern, opaque)
+ func new(->@pthread_mutex_t)
return inline C : @pthread_mutex_t {
pthread_mutex_t *mutex = GC_MALLOC(sizeof(pthread_mutex_t));
pthread_mutex_init(mutex, NULL);
@@ -10,14 +10,14 @@ struct pthread_mutex_t(; extern, opaque):
mutex
}
- func lock(m:&pthread_mutex_t):
+ func lock(m:&pthread_mutex_t)
fail("Failed to lock mutex") unless inline C : Int32 { pthread_mutex_lock(_$m); } == 0
- func unlock(m:&pthread_mutex_t):
+ func unlock(m:&pthread_mutex_t)
fail("Failed to unlock mutex") unless inline C : Int32 { pthread_mutex_unlock(_$m); } == 0
-struct pthread_cond_t(; extern, opaque):
- func new(->@pthread_cond_t):
+struct pthread_cond_t(; extern, opaque)
+ func new(->@pthread_cond_t)
return inline C : @pthread_cond_t {
pthread_cond_t *cond = GC_MALLOC(sizeof(pthread_cond_t));
pthread_cond_init(cond, NULL);
@@ -25,17 +25,17 @@ struct pthread_cond_t(; extern, opaque):
cond
}
- func wait(cond:&pthread_cond_t, mutex:&pthread_mutex_t):
+ func wait(cond:&pthread_cond_t, mutex:&pthread_mutex_t)
fail("Failed to wait on condition") unless inline C : Int32 { pthread_cond_wait(_$cond, _$mutex); } == 0
- func signal(cond:&pthread_cond_t):
+ func signal(cond:&pthread_cond_t)
fail("Failed to signal pthread_cond_t") unless inline C : Int32 { pthread_cond_signal(_$cond); } == 0
- func broadcast(cond:&pthread_cond_t):
+ func broadcast(cond:&pthread_cond_t)
fail("Failed to broadcast pthread_cond_t") unless inline C : Int32 { pthread_cond_broadcast(_$cond); } == 0
-struct pthread_rwlock_t(; extern, opaque):
- func new(->@pthread_rwlock_t):
+struct pthread_rwlock_t(; extern, opaque)
+ func new(->@pthread_rwlock_t)
return inline C : @pthread_rwlock_t {
pthread_rwlock_t *lock = GC_MALLOC(sizeof(pthread_rwlock_t));
pthread_rwlock_init(lock, NULL);
@@ -43,60 +43,60 @@ struct pthread_rwlock_t(; extern, opaque):
lock
}
- func read_lock(lock:&pthread_rwlock_t):
+ func read_lock(lock:&pthread_rwlock_t)
inline C { pthread_rwlock_rdlock(_$lock); }
- func write_lock(lock:&pthread_rwlock_t):
+ func write_lock(lock:&pthread_rwlock_t)
inline C { pthread_rwlock_wrlock(_$lock); }
- func unlock(lock:&pthread_rwlock_t):
+ func unlock(lock:&pthread_rwlock_t)
inline C { pthread_rwlock_unlock(_$lock); }
-struct pthread_t(; extern, opaque):
- func new(fn:func() -> @pthread_t):
+struct pthread_t(; extern, opaque)
+ func new(fn:func() -> @pthread_t)
return inline C : @pthread_t {
pthread_t *thread = GC_MALLOC(sizeof(pthread_t));
pthread_create(thread, NULL, _$fn.fn, _$fn.userdata);
thread
}
- func join(p:pthread_t): inline C { pthread_join(_$p, NULL); }
- func cancel(p:pthread_t): inline C { pthread_cancel(_$p); }
- func detatch(p:pthread_t): inline C { pthread_detach(_$p); }
+ func join(p:pthread_t) inline C { pthread_join(_$p, NULL); }
+ func cancel(p:pthread_t) inline C { pthread_cancel(_$p); }
+ func detatch(p:pthread_t) inline C { pthread_detach(_$p); }
-struct IntQueue(_queue:@[Int], _mutex:@pthread_mutex_t, _cond:@pthread_cond_t):
- func new(initial:[Int]=[] -> IntQueue):
+struct IntQueue(_queue:@[Int], _mutex:@pthread_mutex_t, _cond:@pthread_cond_t)
+ func new(initial:[Int]=[] -> IntQueue)
return IntQueue(@initial, pthread_mutex_t.new(), pthread_cond_t.new())
- func give(q:IntQueue, n:Int):
- do: q._mutex.lock()
+ func give(q:IntQueue, n:Int)
+ do q._mutex.lock()
q._queue.insert(n)
q._mutex.unlock()
q._cond.signal()
- func take(q:IntQueue -> Int):
- do: q._mutex.lock()
+ func take(q:IntQueue -> Int)
+ do q._mutex.lock()
n := q._queue.pop(1)
- while not n:
+ while not n
q._cond.wait(q._mutex)
n = q._queue.pop(1)
q._mutex.unlock()
return n!
fail("Unreachable")
-func main():
+func main()
jobs := IntQueue.new()
results := IntQueue.new()
say_mutex := pthread_mutex_t.new()
- announce := func(speaker:Text, text:Text):
- do: say_mutex.lock()
+ announce := func(speaker:Text, text:Text)
+ do say_mutex.lock()
say("$\033[2m[$speaker]$\033[m $text")
say_mutex.unlock()
- worker := pthread_t.new(func():
+ worker := pthread_t.new(func()
say("I'm in the thread!")
- repeat:
+ repeat
announce("worker", "waiting for job")
job := jobs.take()
result := job * 10
@@ -105,12 +105,12 @@ func main():
announce("worker", "Signaled $result")
)
- for i in 10:
+ for i in 10
announce("boss", "Pushing job $i")
jobs.give(i)
announce("boss", "Gave job $i")
- for i in 10:
+ for i in 10
announce("boss", "Getting result...")
result := results.take()
announce("boss", "Got result $result")
diff --git a/examples/random/random.tm b/examples/random/random.tm
index 1f60aff0..94528dd7 100644
--- a/examples/random/random.tm
+++ b/examples/random/random.tm
@@ -3,8 +3,8 @@
use ./sysrandom.h
use ./chacha.h
-struct chacha_ctx(j0,j1,j2,j3,j4,j5,j6,j7,j8,j9,j10,j11,j12,j13,j14,j15:Int32; extern, secret):
- func from_seed(seed:[Byte]=[] -> chacha_ctx):
+struct chacha_ctx(j0,j1,j2,j3,j4,j5,j6,j7,j8,j9,j10,j11,j12,j13,j14,j15:Int32; extern, secret)
+ func from_seed(seed:[Byte]=[] -> chacha_ctx)
return inline C : chacha_ctx {
chacha_ctx ctx;
uint8_t seed_bytes[KEYSZ + IVSZ] = {};
@@ -17,19 +17,19 @@ struct chacha_ctx(j0,j1,j2,j3,j4,j5,j6,j7,j8,j9,j10,j11,j12,j13,j14,j15:Int32; e
random := RandomNumberGenerator.new()
-func _os_random_bytes(count:Int64 -> [Byte]):
+func _os_random_bytes(count:Int64 -> [Byte])
return inline C : [Byte] {
uint8_t *random_bytes = GC_MALLOC_ATOMIC(_$count);
getrandom(random_bytes, _$count, 0);
(Array_t){.length=_$count, .data=random_bytes, .stride=1, .atomic=1};
}
-struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret):
- func new(seed:[Byte]?=none, -> @RandomNumberGenerator):
+struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret)
+ func new(seed:[Byte]?=none, -> @RandomNumberGenerator)
ctx := chacha_ctx.from_seed(seed or _os_random_bytes(40))
return @RandomNumberGenerator(ctx, [])
- func _rekey(rng:&RandomNumberGenerator):
+ func _rekey(rng:&RandomNumberGenerator)
rng._random_bytes = inline C : [Byte] {
Byte_t new_keystream[KEYSZ + IVSZ] = {};
// Fill the buffer with the keystream
@@ -43,7 +43,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
new_bytes;
}
- func _fill_bytes(rng:&RandomNumberGenerator, dest:&Memory, needed:Int64):
+ func _fill_bytes(rng:&RandomNumberGenerator, dest:&Memory, needed:Int64)
inline C {
while (_$needed > 0) {
if (_$rng->_random_bytes.length == 0)
@@ -62,7 +62,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
}
}
- func bytes(rng:&RandomNumberGenerator, count:Int -> [Byte]):
+ func bytes(rng:&RandomNumberGenerator, count:Int -> [Byte])
return inline C : [Byte] {
int64_t count64 = Int64$from_int(_$count, false);
Array_t ret = {.data=GC_MALLOC_ATOMIC(count64), .stride=1, .atomic=1, .length=count64};
@@ -70,23 +70,23 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
ret;
}
- func byte(rng:&RandomNumberGenerator -> Byte):
+ func byte(rng:&RandomNumberGenerator -> Byte)
return inline C : Byte {
Byte_t b;
_$random$RandomNumberGenerator$_fill_bytes(_$rng, &b, sizeof(b));
b;
}
- func bool(rng:&RandomNumberGenerator, probability=0.5 -> Bool):
- if probability == 0.5:
+ func bool(rng:&RandomNumberGenerator, probability=0.5 -> Bool)
+ if probability == 0.5
return rng.byte() < 0x80
- else:
+ else
return rng.num(0., 1.) < 0.5
- func int64(rng:&RandomNumberGenerator, min=Int64.min, max=Int64.max -> Int64):
+ func int64(rng:&RandomNumberGenerator, min=Int64.min, max=Int64.max -> Int64)
fail("Random minimum value $min is larger than the maximum value $max") if min > max
return min if min == max
- if min == Int64.min and max == Int64.max:
+ if min == Int64.min and max == Int64.max
return inline C : Int64 {
int64_t i;
_$random$RandomNumberGenerator$_fill_bytes(_$rng, &i, sizeof(i));
@@ -104,10 +104,10 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
(int64_t)((uint64_t)_$min + (r % range));
}
- func int32(rng:&RandomNumberGenerator, min=Int32.min, max=Int32.max -> Int32):
+ func int32(rng:&RandomNumberGenerator, min=Int32.min, max=Int32.max -> Int32)
fail("Random minimum value $min is larger than the maximum value $max") if min > max
return min if min == max
- if min == Int32.min and max == Int32.max:
+ if min == Int32.min and max == Int32.max
return inline C : Int32 {
int32_t i;
_$random$RandomNumberGenerator$_fill_bytes(_$rng, &i, sizeof(i));
@@ -125,10 +125,10 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
(int32_t)((uint32_t)_$min + (r % range));
}
- func int16(rng:&RandomNumberGenerator, min=Int16.min, max=Int16.max -> Int16):
+ func int16(rng:&RandomNumberGenerator, min=Int16.min, max=Int16.max -> Int16)
fail("Random minimum value $min is larger than the maximum value $max") if min > max
return min if min == max
- if min == Int16.min and max == Int16.max:
+ if min == Int16.min and max == Int16.max
return inline C : Int16 {
int16_t i;
_$random$RandomNumberGenerator$_fill_bytes(_$rng, &i, sizeof(i));
@@ -146,10 +146,10 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
(int16_t)((uint16_t)_$min + (r % range));
}
- func int8(rng:&RandomNumberGenerator, min=Int8.min, max=Int8.max -> Int8):
+ func int8(rng:&RandomNumberGenerator, min=Int8.min, max=Int8.max -> Int8)
fail("Random minimum value $min is larger than the maximum value $max") if min > max
return min if min == max
- if min == Int8.min and max == Int8.max:
+ if min == Int8.min and max == Int8.max
return inline C : Int8 {
int8_t i;
_$random$RandomNumberGenerator$_fill_bytes(_$rng, &i, sizeof(i));
@@ -167,7 +167,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
(int8_t)((uint8_t)_$min + (r % range));
}
- func num(rng:&RandomNumberGenerator, min=0., max=1. -> Num):
+ func num(rng:&RandomNumberGenerator, min=0., max=1. -> Num)
return inline C : Num {
if (_$min > _$max) fail("Random minimum value (", _$min, ") is larger than the maximum value (", _$max, ")");
if (_$min == _$max) return _$min;
@@ -187,10 +187,10 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
(_$min == 0.0 && _$max == 1.0) ? r.num : ((1.0-r.num)*_$min + r.num*_$max);
}
- func num32(rng:&RandomNumberGenerator, min=Num32(0.), max=Num32(1.) -> Num32):
+ func num32(rng:&RandomNumberGenerator, min=Num32(0.), max=Num32(1.) -> Num32)
return Num32(rng.num(Num(min), Num(max)))
- func int(rng:&RandomNumberGenerator, min:Int, max:Int -> Int):
+ func int(rng:&RandomNumberGenerator, min:Int, max:Int -> Int)
return inline C : Int {
if (likely(((_$min.small & _$max.small) & 1) != 0)) {
int32_t r = _$random$RandomNumberGenerator$int32(_$rng, (int32_t)(_$min.small >> 2), (int32_t)(_$max.small >> 2));
@@ -226,7 +226,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
}
-func main():
+func main()
>> rng := RandomNumberGenerator.new()
>> rng.num()
>> rng.num()
diff --git a/examples/shell/shell.tm b/examples/shell/shell.tm
index 816d63a2..da03f843 100644
--- a/examples/shell/shell.tm
+++ b/examples/shell/shell.tm
@@ -1,44 +1,44 @@
use commands
-lang Shell:
- convert(text:Text -> Shell):
+lang Shell
+ convert(text:Text -> Shell)
return Shell.from_text("'" ++ text.replace($/'/, `'"'"'`) ++ "'")
- convert(texts:[Text] -> Shell):
+ convert(texts:[Text] -> Shell)
return Shell.from_text(" ".join([Shell(t).text for t in texts]))
- convert(path:Path -> Shell):
+ convert(path:Path -> Shell)
return Shell(Text(path.expand_home()))
- convert(paths:[Path] -> Shell):
+ convert(paths:[Path] -> Shell)
return Shell.from_text(" ".join([Shell(Text(p)).text for p in paths]))
- convert(n:Int -> Shell): return Shell.from_text(Text(n))
- convert(n:Int64 -> Shell): return Shell.from_text(Text(n))
- convert(n:Int32 -> Shell): return Shell.from_text(Text(n))
- convert(n:Int16 -> Shell): return Shell.from_text(Text(n))
- convert(n:Int8 -> Shell): return Shell.from_text(Text(n))
- convert(n:Num -> Shell): return Shell.from_text(Text(n))
- convert(n:Num32 -> Shell): return Shell.from_text(Text(n))
+ convert(n:Int -> Shell) return Shell.from_text(Text(n))
+ convert(n:Int64 -> Shell) return Shell.from_text(Text(n))
+ convert(n:Int32 -> Shell) return Shell.from_text(Text(n))
+ convert(n:Int16 -> Shell) return Shell.from_text(Text(n))
+ convert(n:Int8 -> Shell) return Shell.from_text(Text(n))
+ convert(n:Num -> Shell) return Shell.from_text(Text(n))
+ convert(n:Num32 -> Shell) return Shell.from_text(Text(n))
- func command(shell:Shell -> Command):
+ func command(shell:Shell -> Command)
return Command("sh", ["-c", shell.text])
- func result(shell:Shell, input="", input_bytes:[Byte]=[] -> ProgramResult):
+ func result(shell:Shell, input="", input_bytes:[Byte]=[] -> ProgramResult)
return shell.command().result(input=input, input_bytes=input_bytes)
- func run(shell:Shell -> ExitType):
+ func run(shell:Shell -> ExitType)
return shell.command().run()
- func get_output(shell:Shell, input="", trim_newline=yes -> Text?):
+ func get_output(shell:Shell, input="", trim_newline=yes -> Text?)
return shell.command().get_output(input=input, trim_newline=trim_newline)
- func get_output_bytes(shell:Shell, input="", input_bytes:[Byte]=[] -> [Byte]?):
+ func get_output_bytes(shell:Shell, input="", input_bytes:[Byte]=[] -> [Byte]?)
return shell.command().get_output_bytes(input=input, input_bytes=input_bytes)
- func by_line(shell:Shell -> func(->Text?)?):
+ func by_line(shell:Shell -> func(->Text?)?)
return shell.command().by_line()
-func main(command:Shell):
- for line in command.by_line()!:
+func main(command:Shell)
+ for line in command.by_line()!
>> line
diff --git a/examples/time/time.tm b/examples/time/time.tm
index 4d686ac7..4a5bfcf7 100644
--- a/examples/time/time.tm
+++ b/examples/time/time.tm
@@ -5,8 +5,8 @@ enum Weekday(Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday)
struct TimeInfo(year,month,day,hour,minute,second,nanosecond:Int, weekday:Weekday, day_of_year:Int, timezone:Text)
-struct Time(tv_sec:Int64, tv_usec:Int64; extern):
- func now(->Time):
+struct Time(tv_sec:Int64, tv_usec:Int64; extern)
+ func now(->Time)
return inline C : Time {
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
@@ -14,7 +14,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern):
(Time){.tv_sec=ts.tv_sec, .tv_usec=ts.tv_nsec/1000};
}
- func local_timezone(->Text):
+ func local_timezone(->Text)
inline C {
if (_local_timezone.length < 0) {
static char buf[PATH_MAX];
@@ -31,14 +31,14 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern):
}
return inline C : Text { _local_timezone; }
- func set_local_timezone(timezone:Text):
+ func set_local_timezone(timezone:Text)
inline C {
setenv("TZ", Text$as_c_string(_$timezone), 1);
_local_timezone = _$timezone;
tzset();
}
- func format(t:Time, format="%c", timezone=Time.local_timezone() -> Text):
+ func format(t:Time, format="%c", timezone=Time.local_timezone() -> Text)
return inline C : Text {
struct tm result;
time_t time = _$t.tv_sec;
@@ -49,7 +49,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern):
Text$from_strn(buf, len);
}
- func new(year,month,day:Int, hour=0, minute=0, second=0.0, timezone=Time.local_timezone() -> Time):
+ func new(year,month,day:Int, hour=0, minute=0, second=0.0, timezone=Time.local_timezone() -> Time)
return inline C : Time{
struct tm info = {
.tm_min=Int32$from_int(_$minute, false),
@@ -65,24 +65,24 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern):
(Time){.tv_sec=t + (time_t)_$second, .tv_usec=(suseconds_t)(fmod(_$second, 1.0) * 1e9)};
}
- func unix_timestamp(t:Time -> Int64):
+ func unix_timestamp(t:Time -> Int64)
return inline C : Int64 { (int64_t)_$t.tv_sec }
- func from_unix_timestamp(timestamp:Int64 -> Time):
+ func from_unix_timestamp(timestamp:Int64 -> Time)
return inline C : Time { (Time){.tv_sec=_$timestamp}; }
- func seconds_till(t:Time, target:Time -> Num):
+ func seconds_till(t:Time, target:Time -> Num)
seconds := Num(target.tv_sec - t.tv_sec)
seconds += 1e-9*Num(target.tv_usec - t.tv_usec)
return seconds
- func minutes_till(t:Time, target:Time -> Num):
+ func minutes_till(t:Time, target:Time -> Num)
return t.seconds_till(target)/60.
- func hours_till(t:Time, target:Time -> Num):
+ func hours_till(t:Time, target:Time -> Num)
return t.seconds_till(target)/3600.
- func relative(t:Time, relative_to=Time.now(), timezone=Time.local_timezone() -> Text):
+ func relative(t:Time, relative_to=Time.now(), timezone=Time.local_timezone() -> Text)
inline C {
struct tm info = {};
struct tm relative_info = {};
@@ -114,21 +114,21 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern):
}
fail("Unreachable")
- func time(t:Time, seconds=no, am_pm=yes, timezone=Time.local_timezone() -> Text):
- time := if seconds and am_pm:
+ func time(t:Time, seconds=no, am_pm=yes, timezone=Time.local_timezone() -> Text)
+ time := if seconds and am_pm
t.format("%l:%M:%S%P")
- else if seconds and not am_pm:
+ else if seconds and not am_pm
t.format("%T")
- else if not seconds and am_pm:
+ else if not seconds and am_pm
t.format("%l:%M%P")
- else:
+ else
t.format("%H:%M")
return time.trim()
- func date(t:Time, timezone=Time.local_timezone() -> Text):
+ func date(t:Time, timezone=Time.local_timezone() -> Text)
return t.format("%F")
- func info(t:Time, timezone=Time.local_timezone() -> TimeInfo):
+ func info(t:Time, timezone=Time.local_timezone() -> TimeInfo)
return inline C : TimeInfo {
struct tm info = {};
WITH_TIMEZONE(_$timezone, localtime_r(&_$t.tv_sec, &info));
@@ -146,7 +146,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern):
};
}
- func after(t:Time, seconds=0.0, minutes=0.0, hours=0.0, days=0, weeks=0, months=0, years=0, timezone=Time.local_timezone() -> Time):
+ func after(t:Time, seconds=0.0, minutes=0.0, hours=0.0, days=0, weeks=0, months=0, years=0, timezone=Time.local_timezone() -> Time)
return inline C : Time {
double offset = _$seconds + 60.*_$minutes + 3600.*_$hours ;
_$t.tv_sec += (time_t)offset;
@@ -165,7 +165,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern):
};
}
- func parse(text:Text, format="%Y-%m-%dT%H:%M:%S%z", timezone=Time.local_timezone() -> Time?):
+ func parse(text:Text, format="%Y-%m-%dT%H:%M:%S%z", timezone=Time.local_timezone() -> Time?)
return inline C : Time? {
struct tm info = {.tm_isdst=-1};
const char *str = Text$as_c_string(_$text);
@@ -184,7 +184,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern):
(_$time$$OptionalTime$$type){.value={.tv_sec=t + offset - info.tm_gmtoff}};
}
-func _run_tests():
+func _run_tests()
>> Time.now().format()
>> Time.set_local_timezone("Europe/Paris")
>> Time.now().format()
@@ -206,5 +206,5 @@ func _run_tests():
# >> Time.parse("2023-11-05 01:01", "%Y-%m-%d %H:%M")
# >> Time.parse("2023-11-05 01:01", "%Y-%m-%d %H:%M", timezone="Europe/Paris")
-func main():
+func main()
_run_tests()
diff --git a/examples/tomo-install/tomo-install.tm b/examples/tomo-install/tomo-install.tm
index 0a255987..fd8b3c40 100644
--- a/examples/tomo-install/tomo-install.tm
+++ b/examples/tomo-install/tomo-install.tm
@@ -10,19 +10,19 @@ _HELP := "
Usage: $_USAGE
"
-func find_urls(path:Path -> [Text]):
+func find_urls(path:Path -> [Text])
urls : @[Text] = @[]
- if path.is_directory():
- for f in path.children():
+ if path.is_directory()
+ for f in path.children()
urls.insert_all(find_urls(f))
- else if path.is_file() and path.extension() == ".tm":
- for line in path.by_line()!:
- if captures := line.pattern_captures($Pat/use{space}{url}/) or line.pattern_captures($Pat/{id}{space}:={space}use{space}{url}/):
+ else if path.is_file() and path.extension() == ".tm"
+ for line in path.by_line()!
+ if captures := line.pattern_captures($Pat/use{space}{url}/) or line.pattern_captures($Pat/{id}{space}:={space}use{space}{url}/)
urls.insert(captures[-1])
return urls
-func main(paths:[Path]):
- if paths.length == 0:
+func main(paths:[Path])
+ if paths.length == 0
paths = [(./)]
urls := (++: find_urls(p) for p in paths) or []
@@ -32,23 +32,23 @@ func main(paths:[Path]):
(~/.local/share/tomo/installed).create_directory()
(~/.local/share/tomo/lib).create_directory()
- for url in urls:
+ for url in urls
original_url := url
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():
+ if (~/.local/share/tomo/installed/$hash).is_directory()
say("Already installed: $url")
skip
alias : Text? = none
curl_flags := ["-L"]
- if github := url_without_protocol.pattern_captures($Pat"github.com/{!/}/{!/}#{..}"):
+ if github := url_without_protocol.pattern_captures($Pat"github.com/{!/}/{!/}#{..}")
user := github[1]
repo := github[2]
tag := github[3]
url = "https://api.github.com/repos/$user/$repo/tarball/$tag"
alias = "$(repo.without_prefix("tomo-")).$(tag).$(user)"
- if github_token:
+ if github_token
curl_flags ++= ["-H", "Authorization: Bearer $github_token"]
curl_flags ++= [
"-H", "Accept: application/vnd.github+json",
@@ -69,7 +69,7 @@ func main(paths:[Path]):
fi
`.get_output()!)
- if alias:
+ if alias
say($Shell(
set -exuo pipefail
ln -f -s @hash ~/.local/share/tomo/installed/@alias
diff --git a/examples/tomodeps/tomodeps.tm b/examples/tomodeps/tomodeps.tm
index dd7bec10..4ccbec2c 100644
--- a/examples/tomodeps/tomodeps.tm
+++ b/examples/tomodeps/tomodeps.tm
@@ -11,107 +11,107 @@ _HELP := "
enum Dependency(File(path:Path), Module(name:Text))
-func _get_file_dependencies(file:Path -> {Dependency}):
- if not file.is_file():
+func _get_file_dependencies(file:Path -> {Dependency})
+ if not file.is_file()
say("Could not read file: $file")
return {/}
deps : @{Dependency} = @{/}
- if lines := file.by_line():
- for line in lines:
- if line.matches_pattern($Pat/use {..}.tm/):
+ if lines := file.by_line()
+ for line in lines
+ 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_pattern($Pat/use {id}/):
+ else if line.matches_pattern($Pat/use {id}/)
module_name := line.replace_pattern($Pat/use {..}/, "\1")
deps.add(Dependency.Module(module_name))
return deps[]
-func _build_dependency_graph(dep:Dependency, dependencies:@{Dependency={Dependency}}):
+func _build_dependency_graph(dep:Dependency, dependencies:@{Dependency={Dependency}})
return if dependencies.has(dep)
dependencies[dep] = {/} # Placeholder
- dep_deps := when dep is File(path):
+ dep_deps := when dep is File(path)
_get_file_dependencies(path)
- is Module(module):
+ is Module(module)
dir := (~/.local/share/tomo/installed/$module)
module_deps : @{Dependency} = @{/}
visited : @{Path} = @{/}
unvisited := @{f.resolved() for f in dir.files() if f.extension() == ".tm"}
- while unvisited.length > 0:
+ while unvisited.length > 0
file := unvisited.items[-1]
unvisited.remove(file)
visited.add(file)
- for file_dep in _get_file_dependencies(file):
- when file_dep is File(f):
- if not visited.has(f):
+ for file_dep in _get_file_dependencies(file)
+ when file_dep is File(f)
+ if not visited.has(f)
unvisited.add(f)
- is Module(m):
+ is Module(m)
module_deps.add(file_dep)
module_deps[]
dependencies[dep] = dep_deps
- for dep2 in dep_deps:
+ for dep2 in dep_deps
_build_dependency_graph(dep2, dependencies)
-func get_dependency_graph(dep:Dependency -> {Dependency={Dependency}}):
+func get_dependency_graph(dep:Dependency -> {Dependency={Dependency}})
graph : @{Dependency={Dependency}} = @{}
_build_dependency_graph(dep, graph)
return graph
-func _printable_name(dep:Dependency -> Text):
- when dep is Module(module):
+func _printable_name(dep:Dependency -> Text)
+ when dep is Module(module)
return "$(\x1b)[34;1m$module$(\x1b)[m"
- is File(f):
+ is File(f)
f = f.relative_to((.))
- if f.exists():
+ if f.exists()
return Text(f)
- else:
+ else
return "$(\x1b)[31;1m$(f) (not found)$(\x1b)[m"
-func _draw_tree(dep:Dependency, dependencies:{Dependency={Dependency}}, already_printed:@{Dependency}, prefix="", is_last=yes):
- if already_printed.has(dep):
- say(prefix ++ (if is_last: "└── " else: "├── ") ++ _printable_name(dep) ++ " $\x1b[2m(recursive)$\x1b[m")
+func _draw_tree(dep:Dependency, dependencies:{Dependency={Dependency}}, already_printed:@{Dependency}, prefix="", is_last=yes)
+ if already_printed.has(dep)
+ say(prefix ++ (if is_last "└── " else "├── ") ++ _printable_name(dep) ++ " $\x1b[2m(recursive)$\x1b[m")
return
- say(prefix ++ (if is_last: "└── " else: "├── ") ++ _printable_name(dep))
+ say(prefix ++ (if is_last "└── " else "├── ") ++ _printable_name(dep))
already_printed.add(dep)
- child_prefix := prefix ++ (if is_last: " " else: "│ ")
+ child_prefix := prefix ++ (if is_last " " else "│ ")
children := dependencies[dep] or {/}
- for i,child in children.items:
+ for i,child in children.items
is_child_last := (i == children.length)
_draw_tree(child, dependencies, already_printed, child_prefix, is_child_last)
-func draw_tree(dep:Dependency, dependencies:{Dependency={Dependency}}):
+func draw_tree(dep:Dependency, dependencies:{Dependency={Dependency}})
printed : @{Dependency} = @{/}
say(_printable_name(dep))
printed.add(dep)
deps := dependencies[dep] or {/}
- for i,child in deps.items:
+ for i,child in deps.items
is_child_last := (i == deps.length)
_draw_tree(child, dependencies, already_printed=printed, is_last=is_child_last)
-func main(files:[Text]):
- if files.length == 0:
+func main(files:[Text])
+ if files.length == 0
exit("
Please provide at least one file!
$_USAGE
")
- for arg in files:
- if arg.matches_pattern($Pat/{..}.tm/):
+ for arg in files
+ 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_pattern($Pat/{id}/):
+ else if arg.matches_pattern($Pat/{id}/)
dependencies := get_dependency_graph(Module(arg))
draw_tree(Module(arg), dependencies)
- else:
+ else
say("$\x1b[2mSkipping $arg$\x1b[m")
skip
diff --git a/examples/vectors/vectors.tm b/examples/vectors/vectors.tm
index 42ada614..1fd0c4fa 100644
--- a/examples/vectors/vectors.tm
+++ b/examples/vectors/vectors.tm
@@ -1,72 +1,72 @@
# A math vector library for 2D and 3D vectors of Nums or Ints
-struct Vec2(x,y:Num):
+struct Vec2(x,y:Num)
ZERO := Vec2(0, 0)
- func plus(a,b:Vec2->Vec2; inline):
+ func plus(a,b:Vec2->Vec2; inline)
return Vec2(a.x+b.x, a.y+b.y)
- func minus(a,b:Vec2->Vec2; inline):
+ func minus(a,b:Vec2->Vec2; inline)
return Vec2(a.x-b.x, a.y-b.y)
- func times(a,b:Vec2->Vec2; inline):
+ func times(a,b:Vec2->Vec2; inline)
return Vec2(a.x*b.x, a.y*b.y)
- func negative(v:Vec2->Vec2; inline):
+ func negative(v:Vec2->Vec2; inline)
return Vec2(-v.x, -v.y)
- func dot(a,b:Vec2->Num; inline):
+ func dot(a,b:Vec2->Num; inline)
return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)
- func cross(a,b:Vec2->Num; inline):
+ func cross(a,b:Vec2->Num; inline)
return a.x*b.y - a.y*b.x
- func scaled_by(v:Vec2, k:Num->Vec2; inline):
+ func scaled_by(v:Vec2, k:Num->Vec2; inline)
return Vec2(v.x*k, v.y*k)
- func divided_by(v:Vec2, divisor:Num->Vec2; inline):
+ func divided_by(v:Vec2, divisor:Num->Vec2; inline)
return Vec2(v.x/divisor, v.y/divisor)
- func length(v:Vec2->Num; inline):
+ func length(v:Vec2->Num; inline)
return (v.x*v.x + v.y*v.y).sqrt()
- func dist(a,b:Vec2->Num; inline):
+ func dist(a,b:Vec2->Num; inline)
return a.minus(b).length()
- func angle(v:Vec2->Num; inline):
+ func angle(v:Vec2->Num; inline)
return Num.atan2(v.y, v.x)
- func norm(v:Vec2->Vec2; inline):
- if v.x == 0 and v.y == 0:
+ func norm(v:Vec2->Vec2; inline)
+ if v.x == 0 and v.y == 0
return v
len := v.length()
return Vec2(v.x/len, v.y/len)
- func rotated(v:Vec2, radians:Num -> Vec2):
+ func rotated(v:Vec2, radians:Num -> Vec2)
cos := radians.cos() or return v
sin := radians.sin() or return v
return Vec2(cos*v.x - sin*v.y, sin*v.x + cos*v.y)
- func mix(a,b:Vec2, amount:Num -> Vec2):
+ func mix(a,b:Vec2, amount:Num -> Vec2)
return Vec2(
amount.mix(a.x, b.x),
amount.mix(a.y, b.y),
)
-struct Vec3(x,y,z:Num):
+struct Vec3(x,y,z:Num)
ZERO := Vec3(0, 0, 0)
- func plus(a,b:Vec3->Vec3; inline):
+ func plus(a,b:Vec3->Vec3; inline)
return Vec3(a.x+b.x, a.y+b.y, a.z+b.z)
- func minus(a,b:Vec3->Vec3; inline):
+ func minus(a,b:Vec3->Vec3; inline)
return Vec3(a.x-b.x, a.y-b.y, a.z-b.z)
- func times(a,b:Vec3->Vec3; inline):
+ func times(a,b:Vec3->Vec3; inline)
return Vec3(a.x*b.x, a.y*b.y, a.z*b.z)
- func negative(v:Vec3->Vec3; inline):
+ func negative(v:Vec3->Vec3; inline)
return Vec3(-v.x, -v.y, -v.z)
- func dot(a,b:Vec3->Num; inline):
+ func dot(a,b:Vec3->Num; inline)
return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) + (a.z-b.z)*(a.z-b.z)
- func cross(a,b:Vec3->Vec3; inline):
+ func cross(a,b:Vec3->Vec3; inline)
return Vec3(a.y*b.z - a.z-b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x)
- func scaled_by(v:Vec3, k:Num->Vec3; inline):
+ func scaled_by(v:Vec3, k:Num->Vec3; inline)
return Vec3(v.x*k, v.y*k, v.z*k)
- func divided_by(v:Vec3, divisor:Num->Vec3; inline):
+ func divided_by(v:Vec3, divisor:Num->Vec3; inline)
return Vec3(v.x/divisor, v.y/divisor, v.z/divisor)
- func length(v:Vec3->Num; inline):
+ func length(v:Vec3->Num; inline)
return (v.x*v.x + v.y*v.y + v.z*v.z).sqrt()
- func dist(a,b:Vec3->Num; inline):
+ func dist(a,b:Vec3->Num; inline)
return a.minus(b).length()
- func norm(v:Vec3->Vec3; inline):
- if v.x == 0 and v.y == 0 and v.z == 0:
+ func norm(v:Vec3->Vec3; inline)
+ if v.x == 0 and v.y == 0 and v.z == 0
return v
len := v.length()
return Vec3(v.x/len, v.y/len, v.z/len)
- func mix(a,b:Vec3, amount:Num -> Vec3):
+ func mix(a,b:Vec3, amount:Num -> Vec3)
return Vec3(
amount.mix(a.x, b.x),
amount.mix(a.y, b.y),
@@ -74,60 +74,60 @@ struct Vec3(x,y,z:Num):
)
-struct IVec2(x,y:Int):
+struct IVec2(x,y:Int)
ZERO := IVec2(0, 0)
- func plus(a,b:IVec2->IVec2; inline):
+ func plus(a,b:IVec2->IVec2; inline)
return IVec2(a.x+b.x, a.y+b.y)
- func minus(a,b:IVec2->IVec2; inline):
+ func minus(a,b:IVec2->IVec2; inline)
return IVec2(a.x-b.x, a.y-b.y)
- func times(a,b:IVec2->IVec2; inline):
+ func times(a,b:IVec2->IVec2; inline)
return IVec2(a.x*b.x, a.y*b.y)
- func negative(v:IVec2->IVec2; inline):
+ func negative(v:IVec2->IVec2; inline)
return IVec2(-v.x, -v.y)
- func dot(a,b:IVec2->Int; inline):
+ func dot(a,b:IVec2->Int; inline)
return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y)
- func cross(a,b:IVec2->Int; inline):
+ func cross(a,b:IVec2->Int; inline)
return a.x*b.y - a.y*b.x
- func scaled_by(v:IVec2, k:Int->IVec2; inline):
+ func scaled_by(v:IVec2, k:Int->IVec2; inline)
return IVec2(v.x*k, v.y*k)
- func divided_by(v:IVec2, divisor:Int->IVec2; inline):
+ func divided_by(v:IVec2, divisor:Int->IVec2; inline)
return IVec2(v.x/divisor, v.y/divisor)
- func length(v:IVec2->Num; inline):
+ func length(v:IVec2->Num; inline)
x := Num(v.x)
y := Num(v.y)
return Num.sqrt(x*x + y*y)
- func dist(a,b:IVec2->Num; inline):
+ func dist(a,b:IVec2->Num; inline)
return a.minus(b).length()
- func angle(v:IVec2->Num; inline):
+ func angle(v:IVec2->Num; inline)
return Num.atan2(Num(v.y), Num(v.x))
-struct IVec3(x,y,z:Int):
+struct IVec3(x,y,z:Int)
ZERO := IVec3(0, 0, 0)
- func plus(a,b:IVec3->IVec3; inline):
+ func plus(a,b:IVec3->IVec3; inline)
return IVec3(a.x+b.x, a.y+b.y, a.z+b.z)
- func minus(a,b:IVec3->IVec3; inline):
+ func minus(a,b:IVec3->IVec3; inline)
return IVec3(a.x-b.x, a.y-b.y, a.z-b.z)
- func times(a,b:IVec3->IVec3; inline):
+ func times(a,b:IVec3->IVec3; inline)
return IVec3(a.x*b.x, a.y*b.y, a.z*b.z)
- func negative(v:IVec3->IVec3; inline):
+ func negative(v:IVec3->IVec3; inline)
return IVec3(-v.x, -v.y, -v.z)
- func dot(a,b:IVec3->Int; inline):
+ func dot(a,b:IVec3->Int; inline)
return (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) + (a.z-b.z)*(a.z-b.z)
- func cross(a,b:IVec3->IVec3; inline):
+ func cross(a,b:IVec3->IVec3; inline)
return IVec3(a.y*b.z - a.z-b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x)
- func scaled_by(v:IVec3, k:Int->IVec3; inline):
+ func scaled_by(v:IVec3, k:Int->IVec3; inline)
return IVec3(v.x*k, v.y*k, v.z*k)
- func divided_by(v:IVec3, divisor:Int->IVec3; inline):
+ func divided_by(v:IVec3, divisor:Int->IVec3; inline)
return IVec3(v.x/divisor, v.y/divisor, v.z/divisor)
- func length(v:IVec3->Num; inline):
+ func length(v:IVec3->Num; inline)
x := Num(v.x)
y := Num(v.y)
z := Num(v.z)
return Num.sqrt(x*x + y*y + z*z)
- func dist(a,b:IVec3->Num; inline):
+ func dist(a,b:IVec3->Num; inline)
return a.minus(b).length()
-func main():
+func main()
>> Vec2(10, 20)
>> Vec2(10, 20) + Vec2(100, 100)
= Vec2(x=110, y=120)
diff --git a/examples/wrap/wrap.tm b/examples/wrap/wrap.tm
index 448ab813..c539a0ea 100644
--- a/examples/wrap/wrap.tm
+++ b/examples/wrap/wrap.tm
@@ -13,19 +13,19 @@ HELP := "
UNICODE_HYPHEN := \{hyphen}
-func unwrap(text:Text, preserve_paragraphs=yes, hyphen=UNICODE_HYPHEN -> Text):
- if preserve_paragraphs:
+func unwrap(text:Text, preserve_paragraphs=yes, hyphen=UNICODE_HYPHEN -> Text)
+ if preserve_paragraphs
paragraphs := text.split($/{2+ nl}/)
- if paragraphs.length > 1:
+ if paragraphs.length > 1
return \n\n.join([unwrap(p, hyphen=hyphen, preserve_paragraphs=no) for p in paragraphs])
return text.replace($/$(hyphen)$(\n)/, "")
-func wrap(text:Text, width:Int, min_split=3, hyphen="-" -> Text):
- if width <= 0:
+func wrap(text:Text, width:Int, min_split=3, hyphen="-" -> Text)
+ if width <= 0
fail("Width must be a positive integer, not $width")
- if 2*min_split - hyphen.length > width:
+ if 2*min_split - hyphen.length > width
fail("
Minimum word split length ($min_split) is too small for the given wrap width ($width)!
@@ -35,66 +35,66 @@ func wrap(text:Text, width:Int, min_split=3, hyphen="-" -> Text):
lines : @[Text] = @[]
line := ""
- for word in text.split($/{whitespace}/):
+ for word in text.split($/{whitespace}/)
letters := word.split()
skip if letters.length == 0
- while not _can_fit_word(line, letters, width):
+ while not _can_fit_word(line, letters, width)
line_space := width - line.length
- if line != "": line_space -= 1
+ if line != "" line_space -= 1
- if min_split > 0 and line_space >= min_split + hyphen.length and letters.length >= 2*min_split:
+ if min_split > 0 and line_space >= min_split + hyphen.length and letters.length >= 2*min_split
# Split word with a hyphen:
split := line_space - hyphen.length
split = split _max_ min_split
split = split _min_ (letters.length - min_split)
- if line != "": line ++= " "
+ if line != "" line ++= " "
line ++= ((++: letters.to(split)) or "") ++ hyphen
letters = letters.from(split + 1)
- else if line == "":
+ else if line == ""
# Force split word without hyphenation:
- if line != "": line ++= " "
+ if line != "" line ++= " "
line ++= (++: letters.to(line_space)) or ""
letters = letters.from(line_space + 1)
- else:
+ else
pass # Move to next line
lines.insert(line)
line = ""
- if letters.length > 0:
- if line != "": line ++= " "
+ if letters.length > 0
+ if line != "" line ++= " "
line ++= (++: letters) or ""
- if line != "":
+ if line != ""
lines.insert(line)
return \n.join(lines)
-func _can_fit_word(line:Text, letters:[Text], width:Int -> Bool; inline):
- if line == "":
+func _can_fit_word(line:Text, letters:[Text], width:Int -> Bool; inline)
+ if line == ""
return letters.length <= width
- else:
+ else
return line.length + 1 + letters.length <= width
-func main(files:[Path], width=80, inplace=no, min_split=3, rewrap=yes, hyphen=UNICODE_HYPHEN):
- if files.length == 0:
+func main(files:[Path], width=80, inplace=no, min_split=3, rewrap=yes, hyphen=UNICODE_HYPHEN)
+ if files.length == 0
files = [(/dev/stdin)]
- for file in files:
+ for file in files
text := file.read() or exit("Could not read file: $file")
- if rewrap:
+ if rewrap
text = unwrap(text)
- out := if file.is_file() and inplace:
+ out := if file.is_file() and inplace
file
- else:
+ else
(/dev/stdout)
first := yes
wrapped_paragraphs : @[Text] = @[]
- for paragraph in text.split($/{2+ nl}/):
+ for paragraph in text.split($/{2+ nl}/)
wrapped_paragraphs.insert(
wrap(paragraph, width=width, min_split=min_split, hyphen=hyphen)
)
diff --git a/src/parse.c b/src/parse.c
index 0f76243d..ca6a6af2 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -1791,7 +1791,6 @@ PARSER(parse_extended_expr) {
PARSER(parse_block) {
const char *start = pos;
spaces(&pos);
- if (!match(&pos, ":")) return NULL;
ast_list_t *statements = NULL;
if (!indent(ctx, &pos)) {
@@ -1968,14 +1967,12 @@ PARSER(parse_struct_def) {
expect_closing(ctx, &pos, ")", "I wasn't able to parse the rest of this struct");
ast_t *namespace = NULL;
- if (match(&pos, ":")) {
- const char *ns_pos = pos;
- whitespace(&ns_pos);
- int64_t ns_indent = get_indent(ctx, ns_pos);
- if (ns_indent > starting_indent) {
- pos = ns_pos;
- namespace = optional(ctx, &pos, parse_namespace);
- }
+ const char *ns_pos = pos;
+ whitespace(&ns_pos);
+ int64_t ns_indent = get_indent(ctx, ns_pos);
+ if (ns_indent > starting_indent) {
+ pos = ns_pos;
+ namespace = optional(ctx, &pos, parse_namespace);
}
if (!namespace)
namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
@@ -2031,14 +2028,12 @@ PARSER(parse_enum_def) {
REVERSE_LIST(tags);
ast_t *namespace = NULL;
- if (match(&pos, ":")) {
- const char *ns_pos = pos;
- whitespace(&ns_pos);
- int64_t ns_indent = get_indent(ctx, ns_pos);
- if (ns_indent > starting_indent) {
- pos = ns_pos;
- namespace = optional(ctx, &pos, parse_namespace);
- }
+ const char *ns_pos = pos;
+ whitespace(&ns_pos);
+ int64_t ns_indent = get_indent(ctx, ns_pos);
+ if (ns_indent > starting_indent) {
+ pos = ns_pos;
+ namespace = optional(ctx, &pos, parse_namespace);
}
if (!namespace)
namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
@@ -2058,14 +2053,12 @@ PARSER(parse_lang_def) {
spaces(&pos);
ast_t *namespace = NULL;
- if (match(&pos, ":")) {
- const char *ns_pos = pos;
- whitespace(&ns_pos);
- int64_t ns_indent = get_indent(ctx, ns_pos);
- if (ns_indent > starting_indent) {
- pos = ns_pos;
- namespace = optional(ctx, &pos, parse_namespace);
- }
+ const char *ns_pos = pos;
+ whitespace(&ns_pos);
+ int64_t ns_indent = get_indent(ctx, ns_pos);
+ if (ns_indent > starting_indent) {
+ pos = ns_pos;
+ namespace = optional(ctx, &pos, parse_namespace);
}
if (!namespace)
namespace = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
@@ -2084,14 +2077,12 @@ PARSER(parse_extend) {
parser_err(ctx, start, pos, "I expected a name for this lang");
ast_t *body = NULL;
- if (match(&pos, ":")) {
- const char *ns_pos = pos;
- whitespace(&ns_pos);
- int64_t ns_indent = get_indent(ctx, ns_pos);
- if (ns_indent > starting_indent) {
- pos = ns_pos;
- body = optional(ctx, &pos, parse_namespace);
- }
+ const char *ns_pos = pos;
+ whitespace(&ns_pos);
+ int64_t ns_indent = get_indent(ctx, ns_pos);
+ if (ns_indent > starting_indent) {
+ pos = ns_pos;
+ body = optional(ctx, &pos, parse_namespace);
}
if (!body)
body = NewAST(ctx->file, pos, pos, Block, .statements=NULL);
diff --git a/test/arrays.tm b/test/arrays.tm
index c60085ca..f2ed2c7a 100644
--- a/test/arrays.tm
+++ b/test/arrays.tm
@@ -1,9 +1,9 @@
-func main():
- do:
+func main()
+ do
>> nums : [Num32] = []
= []
- do:
+ do
>> arr := [10, 20, 30]
= [10, 20, 30]
@@ -16,18 +16,18 @@ func main():
= 3
sum := 0
- for x in arr:
+ for x in arr
sum += x
>> sum
= 60
str := ""
- for i,x in arr:
+ for i,x in arr
str ++= "($i,$x)"
>> str
= "(1,10)(2,20)(3,30)"
- do:
+ do
>> arr := [10, 20] ++ [30, 40]
= [10, 20, 30, 40]
@@ -35,7 +35,7 @@ func main():
>> arr
= [10, 20, 30, 40, 50, 60]
- do:
+ do
>> arr := [10, 20]
>> copy := arr
>> arr ++= [30]
@@ -44,7 +44,7 @@ func main():
>> copy
= [10, 20]
- do:
+ do
>> [10*i for i in 5]
= [10, 20, 30, 40, 50]
@@ -57,7 +57,7 @@ func main():
>> [x for x in y if x > 1 for y in [3, 4, 5] if y < 5]
= [2, 3, 2, 3, 4]
- do:
+ do
>> arr := @[10, 20]
>> copy := arr[]
>> arr.insert(30)
@@ -70,7 +70,7 @@ func main():
>> arr
= @[999, 20, 30]
- do:
+ do
>> arr := &[10, 20, 30]
>> reversed := arr.reversed()
= [30, 20, 10]
@@ -79,7 +79,7 @@ func main():
>> reversed
= [30, 20, 10]
- do:
+ do
>> nums := @[10, -20, 30]
# Sorted function doesn't mutate original:
>> nums.sorted()
@@ -91,34 +91,34 @@ func main():
>> nums
= @[-20, 10, 30]
# Custom sort functions:
- >> nums.sort(func(x,y:&Int): x.abs() <> y.abs())
+ >> nums.sort(func(x,y:&Int) x.abs() <> y.abs())
>> nums
= @[10, -20, 30]
- >> nums.sort(func(x,y:&Int): y[] <> x[])
+ >> nums.sort(func(x,y:&Int) y[] <> x[])
>> nums
= @[30, 10, -20]
>> ["A", "B", "C"].sample(10, [1.0, 0.5, 0.0])
- do:
+ do
>> heap := @[(i * 1337) mod 37 for i in 10]
>> heap.heapify()
>> heap
heap_order : @[Int] = @[]
- repeat:
+ repeat
heap_order.insert(heap.heap_pop() or stop)
>> heap_order[] == heap_order.sorted()
= yes
heap_order[] = []
- for i in 10:
+ for i in 10
heap.heap_push((i*13337) mod 37)
>> heap
- repeat:
+ repeat
heap_order.insert(heap.heap_pop() or stop)
>> heap_order[] == heap_order.sorted()
= yes
- do:
+ do
>> [i*10 for i in 5].from(3)
= [30, 40, 50]
>> [i*10 for i in 5].to(3)
@@ -146,17 +146,17 @@ func main():
# Test iterating over array.from() and array.to()
xs := ["A", "B", "C", "D"]
- for i,x in xs.to(-2):
- for y in xs.from(i+1):
+ for i,x in xs.to(-2)
+ for y in xs.from(i+1)
say("$(x)$(y)")
- do:
+ do
>> nums := @[-7, -4, -1, 2, 5]
>> nums.sort()
>> [nums.binary_search(i) for i in nums[]]
= [1, 2, 3, 4, 5]
- >> nums.sort(func(a,b:&Int): a.abs() <> b.abs())
- >> [nums.binary_search(i, func(a,b:&Int): a.abs() <> b.abs()) for i in nums[]]
+ >> nums.sort(func(a,b:&Int) a.abs() <> b.abs())
+ >> [nums.binary_search(i, func(a,b:&Int) a.abs() <> b.abs()) for i in nums[]]
= [1, 2, 3, 4, 5]
>> ["a", "b", "c"].find("b")
@@ -164,12 +164,12 @@ func main():
>> ["a", "b", "c"].find("XXX")
= none
- >> [10, 20].first(func(i:&Int): i.is_prime())
+ >> [10, 20].first(func(i:&Int) i.is_prime())
= none
- >> [4, 5, 6].first(func(i:&Int): i.is_prime())
+ >> [4, 5, 6].first(func(i:&Int) i.is_prime())
= 2?
- do:
+ do
>> nums := &[10, 20, 30, 40, 50]
>> nums.pop()
= 50?
diff --git a/test/bytes.tm b/test/bytes.tm
index 862d2674..25efbeb8 100644
--- a/test/bytes.tm
+++ b/test/bytes.tm
@@ -1,5 +1,5 @@
-func main():
+func main()
say("Test bytes:")
>> Byte(100)
= Byte(0x64)
diff --git a/test/corecursive_func.tm b/test/corecursive_func.tm
index b5f5f13e..8faf8b0d 100644
--- a/test/corecursive_func.tm
+++ b/test/corecursive_func.tm
@@ -1,15 +1,15 @@
-func ping(x:Int->[Text]):
- if x > 0:
+func ping(x:Int->[Text])
+ if x > 0
return ["ping: $x"] ++ pong(x-1)
- else:
+ else
return ["ping: $x"]
-func pong(x:Int->[Text]):
- if x > 0:
+func pong(x:Int->[Text])
+ if x > 0
return ["pong: $x"] ++ ping(x-1)
- else:
+ else
return ["pong: $x"]
-func main():
+func main()
>> ping(3)
= ["ping: 3", "pong: 2", "ping: 1", "pong: 0"]
diff --git a/test/defer.tm b/test/defer.tm
index 4053f0c1..e5033075 100644
--- a/test/defer.tm
+++ b/test/defer.tm
@@ -1,8 +1,8 @@
-func main():
+func main()
x := 123
nums : @[Int] = @[]
- do:
- defer:
+ do
+ defer
nums.insert(x)
x = 999
@@ -11,28 +11,28 @@ func main():
>> x
= 999
- defer:
+ defer
say("All done!")
- for word in ["first", "second", "third"]:
- defer:
+ for word in ["first", "second", "third"]
+ defer
say("Got $word deferred")
- if word == "second":
+ if word == "second"
say("<skipped>")
skip
- else if word == "third":
+ else if word == "third"
say("<stopped>")
stop
- for i in 3:
- defer:
+ for i in 3
+ defer
say("Inner loop deferred $i")
- if i == 2:
+ if i == 2
say("<skipped inner>")
skip
- else if i == 3:
+ else if i == 3
say("<stopped inner>")
stop
@@ -40,12 +40,12 @@ func main():
say("Made it through the loop")
- >> thunk := func(return_early=no):
+ >> thunk := func(return_early=no)
say("Entering thunk")
- defer:
+ defer
say("Deferred thunk cleanup")
- if return_early:
+ if return_early
say("Returning early...")
return
@@ -65,20 +65,20 @@ func main():
>> counter()
= 3
-func defer_func(return_early=no):
+func defer_func(return_early=no)
say("Entering defer_func")
- defer:
+ defer
say("Deferred defer_func cleanup")
- if return_early:
+ if return_early
say("Returning early...")
return
say("Finished defer_func")
-func make_counter(->func(->Int)):
+func make_counter(->func(->Int))
i := 1
- return func():
- defer: i += 1
+ return func()
+ defer i += 1
return i
diff --git a/test/enums.tm b/test/enums.tm
index a11f95f9..3b3b31ea 100644
--- a/test/enums.tm
+++ b/test/enums.tm
@@ -1,21 +1,21 @@
enum Foo(Zero, One(x:Int), Two(x:Int, y:Int), Three(x:Int, y:Text, z:Bool), Four(x,y,z,w:Int), Last(t:Text))
-func choose_text(f:Foo->Text):
+func choose_text(f:Foo->Text)
>> f
- when f is Zero:
+ when f is Zero
return "Zero"
- is One(one):
+ is One(one)
return "One: $one"
- is Two(x, y):
+ is Two(x, y)
return "Two: x=$x, y=$y"
- is Three(three):
+ is Three(three)
return "Three: $three"
- is Four:
+ is Four
return "Four"
- else:
+ else
return "else: $f"
-func main():
+func main()
>> Foo.Zero
= Foo.Zero
>> Foo.One(123)
@@ -63,24 +63,24 @@ func main():
i := 1
cases := [Foo.One(1), Foo.One(2), Foo.Zero]
- while when cases[i] is One(x):
+ while when cases[i] is One(x)
>> x
i += 1
>> [
(
- when x is One(y), Two(y,_):
+ when x is One(y), Two(y,_)
"Small $y"
- is Zero:
+ is Zero
"Zero"
- else:
+ else
"Other"
) for x in [Foo.Zero, Foo.One(1), Foo.Two(2,2), Foo.Three(3,"",no)]
]
= ["Zero", "Small 1", "Small 2", "Other"]
- >> expr := when cases[1] is One(y):
+ >> expr := when cases[1] is One(y)
y + 1
- else:
+ else
-1
= 2
diff --git a/test/extern.tm b/test/extern.tm
index 17c39948..8e2b6c06 100644
--- a/test/extern.tm
+++ b/test/extern.tm
@@ -1,5 +1,5 @@
extern sqrt : func(n:Num->Num)
-func main():
+func main()
>> sqrt(4)
= 2.
diff --git a/test/for.tm b/test/for.tm
index e4967e86..75ad2fee 100644
--- a/test/for.tm
+++ b/test/for.tm
@@ -1,35 +1,35 @@
-func all_nums(nums:[Int] -> Text):
+func all_nums(nums:[Int] -> Text)
result := ""
- for num in nums:
+ for num in nums
result ++= "$num,"
- else:
+ else
return "EMPTY"
return result
-func labeled_nums(nums:[Int] -> Text):
+func labeled_nums(nums:[Int] -> Text)
result := ""
- for i,num in nums:
+ for i,num in nums
result ++= "$i:$num,"
- else:
+ else
return "EMPTY"
return result
-func table_str(t:{Text=Text} -> Text):
+func table_str(t:{Text=Text} -> Text)
str := ""
- for k,v in t:
+ for k,v in t
str ++= "$k:$v,"
- else: return "EMPTY"
+ else return "EMPTY"
return str
-func table_key_str(t:{Text=Text} -> Text):
+func table_key_str(t:{Text=Text} -> Text)
str := ""
- for k in t:
+ for k in t
str ++= "$k,"
- else: return "EMPTY"
+ else return "EMPTY"
return str
-func main():
+func main()
>> all_nums([10,20,30])
= "10,20,30,"
>> all_nums([])
diff --git a/test/functions.tm b/test/functions.tm
index 22d950d4..17ca1e85 100644
--- a/test/functions.tm
+++ b/test/functions.tm
@@ -1,10 +1,10 @@
-func add(x:Int, y:Int -> Int):
+func add(x:Int, y:Int -> Int)
return x + y
-func cached_heap(x:Int->@Int; cached):
+func cached_heap(x:Int->@Int; cached)
return @x
-func main():
+func main()
>> add(3, 5)
= 8
diff --git a/test/import.tm b/test/import.tm
index 960bfcbb..a6a6fa16 100644
--- a/test/import.tm
+++ b/test/import.tm
@@ -1,13 +1,13 @@
vectors := use ../examples/vectors/vectors.tm
use ./use_import.tm
-func returns_vec(->vectors.Vec2):
+func returns_vec(->vectors.Vec2)
return vectors.Vec2(1, 2)
-func returns_imported_type(->ImportedType):
+func returns_imported_type(->ImportedType)
return get_value() # Imported from ./use_import.tm
-func main():
+func main()
>> empty : [vectors.Vec2] = []
>> returns_vec()
= Vec2(x=1, y=2)
diff --git a/test/inline_c.tm b/test/inline_c.tm
index 3c0949cd..a79359d1 100644
--- a/test/inline_c.tm
+++ b/test/inline_c.tm
@@ -1,5 +1,5 @@
-func main():
+func main()
>> inline C:Int32 { int x = 1 + 2; x }
= Int32(3)
diff --git a/test/integers.tm b/test/integers.tm
index 508a38ae..72a195b4 100644
--- a/test/integers.tm
+++ b/test/integers.tm
@@ -1,4 +1,4 @@
-func main():
+func main()
>> 2 + 3
= 5
@@ -37,7 +37,7 @@ func main():
= 1
nums := ""
- for x in 5:
+ for x in 5
nums ++= "$x,"
>> nums
= "1,2,3,4,5,"
@@ -66,7 +66,7 @@ func main():
>> Int(2.1, truncate=yes)
= 2
- do:
+ do
>> small_int := 1
= 1
>> max_small_int := 536870911
@@ -84,11 +84,11 @@ func main():
>> super_big + 1
= 10000000000000000000000
- do:
+ do
interesting_numerators := [-999999, -100, -23, -1, 0, 1, 23, 100, 999999]
interesting_denominators := [-99, -20, -17, -1, 1, 17, 20, 99]
- for n in interesting_numerators:
- for d in interesting_denominators:
+ for n in interesting_numerators
+ for d in interesting_denominators
>> (n/d)*d + (n mod d) == n
= yes
diff --git a/test/iterators.tm b/test/iterators.tm
index 64d21ea3..1816fd7a 100644
--- a/test/iterators.tm
+++ b/test/iterators.tm
@@ -1,22 +1,22 @@
struct Pair(x:Text, y:Text)
-func pairwise(strs:[Text] -> func(->Pair?)):
+func pairwise(strs:[Text] -> func(->Pair?))
i := 1
- return func():
- if i + 1 > strs.length: return none
+ return func()
+ if i + 1 > strs.length return none
i += 1
return Pair(strs[i-1], strs[i])?
-func range(first:Int, last:Int -> func(->Int?)):
+func range(first:Int, last:Int -> func(->Int?))
i := first
- return func():
- if i > last:
+ return func()
+ if i > last
return none
i += 1
return (i-1)?
-func main():
+func main()
values := ["A", "B", "C", "D"]
>> (++: "($(foo.x)$(foo.y))" for foo in pairwise(values))!
@@ -24,9 +24,9 @@ func main():
>> ["$(foo.x)$(foo.y)" for foo in pairwise(values)]
= ["AB", "BC", "CD"]
- do:
+ do
result : @[Text] = @[]
- for foo in pairwise(values):
+ for foo in pairwise(values)
result.insert("$(foo.x)$(foo.y)")
>> result[]
= ["AB", "BC", "CD"]
diff --git a/test/lambdas.tm b/test/lambdas.tm
index 6e261e0f..d6501cb7 100644
--- a/test/lambdas.tm
+++ b/test/lambdas.tm
@@ -1,18 +1,18 @@
-func make_adder(x:Int -> func(y:Int->Int)):
- return func(y:Int): x + y
+func make_adder(x:Int -> func(y:Int->Int))
+ return func(y:Int) x + y
-func suffix_fn(fn:func(t:Text->Text), suffix:Text -> func(t:Text->Text)):
- return func(t:Text): fn(t)++suffix
+func suffix_fn(fn:func(t:Text->Text), suffix:Text -> func(t:Text->Text))
+ return func(t:Text) fn(t)++suffix
-func mul_func(n:Int, fn:func(x:Int->Int) -> func(x:Int->Int)):
- return func(x:Int): n*fn(x)
+func mul_func(n:Int, fn:func(x:Int->Int) -> func(x:Int->Int))
+ return func(x:Int) n*fn(x)
-func main():
- >> add_one := func(x:Int): x + 1
+func main()
+ >> add_one := func(x:Int) x + 1
>> add_one(10)
= 11
- >> shout := func(msg:Text): say("$(msg.upper())!")
+ >> shout := func(msg:Text) say("$(msg.upper())!")
>> shout("hello")
>> asdf := add_one
@@ -23,7 +23,7 @@ func main():
>> add_100(5)
= 105
- >> shout2 := suffix_fn(func(t:Text): t.upper(), "!")
+ >> shout2 := suffix_fn(func(t:Text) t.upper(), "!")
>> shout2("hello")
= "HELLO!"
@@ -33,10 +33,10 @@ func main():
# Test nested lambdas:
outer := "Hello"
- fn := func():
- return func():
- return func():
- defer: say("$outer")
+ fn := func()
+ return func()
+ return func()
+ defer say("$outer")
return outer
>> fn()()()
= "Hello"
diff --git a/test/lang.tm b/test/lang.tm
index 6d0a94ea..081438ed 100644
--- a/test/lang.tm
+++ b/test/lang.tm
@@ -1,6 +1,6 @@
-lang HTML:
+lang HTML
HEADER := $HTML"<!DOCTYPE HTML>"
- convert(t:Text->HTML):
+ convert(t:Text->HTML)
t = t.translate({
"&"="&amp;",
"<"="&lt;",
@@ -11,17 +11,17 @@ lang HTML:
return HTML.from_text(t)
- convert(i:Int->HTML):
+ convert(i:Int->HTML)
return HTML.from_text("$i")
- func paragraph(content:HTML->HTML):
+ func paragraph(content:HTML->HTML)
return $HTML"<p>$content</p>"
-struct Bold(text:Text):
- convert(b:Bold -> HTML):
+struct Bold(text:Text)
+ convert(b:Bold -> HTML)
return $HTML"<b>$(b.text)</b>"
-func main():
+func main()
>> HTML.HEADER
= $HTML"<!DOCTYPE HTML>"
diff --git a/test/metamethods.tm b/test/metamethods.tm
index aac37c4b..9399bc9a 100644
--- a/test/metamethods.tm
+++ b/test/metamethods.tm
@@ -1,50 +1,50 @@
-struct Vec2(x,y:Int):
- func plus(a,b:Vec2 -> Vec2; inline):
+struct Vec2(x,y:Int)
+ func plus(a,b:Vec2 -> Vec2; inline)
return Vec2(a.x+b.x, a.y+b.y)
- func minus(a,b:Vec2 -> Vec2; inline):
+ func minus(a,b:Vec2 -> Vec2; inline)
return Vec2(a.x-b.x, a.y-b.y)
- func dot(a,b:Vec2 -> Int; inline):
+ func dot(a,b:Vec2 -> Int; inline)
return a.x*b.x + a.y*b.y
- func scaled_by(a:Vec2, k:Int -> Vec2; inline):
+ func scaled_by(a:Vec2, k:Int -> Vec2; inline)
return Vec2(a.x*k, a.y*k)
- func times(a,b:Vec2 -> Vec2; inline):
+ func times(a,b:Vec2 -> Vec2; inline)
return Vec2(a.x*b.x, a.y*b.y)
- func divided_by(a:Vec2, k:Int -> Vec2; inline):
+ func divided_by(a:Vec2, k:Int -> Vec2; inline)
return Vec2(a.x/k, a.y/k)
- func negative(v:Vec2 -> Vec2; inline):
+ func negative(v:Vec2 -> Vec2; inline)
return Vec2(-v.x, -v.y)
- func negated(v:Vec2 -> Vec2; inline):
+ func negated(v:Vec2 -> Vec2; inline)
return Vec2(not v.x, not v.y)
- func bit_and(a,b:Vec2 -> Vec2; inline):
+ func bit_and(a,b:Vec2 -> Vec2; inline)
return Vec2(a.x and b.x, a.y and b.y)
- func bit_or(a,b:Vec2 -> Vec2; inline):
+ func bit_or(a,b:Vec2 -> Vec2; inline)
return Vec2(a.x or b.x, a.y or b.y)
- func bit_xor(a,b:Vec2 -> Vec2; inline):
+ func bit_xor(a,b:Vec2 -> Vec2; inline)
return Vec2(a.x xor b.x, a.y xor b.y)
- func left_shifted(v:Vec2, bits:Int -> Vec2; inline):
+ func left_shifted(v:Vec2, bits:Int -> Vec2; inline)
return Vec2(v.x >> bits, v.y >> bits)
- func right_shifted(v:Vec2, bits:Int -> Vec2; inline):
+ func right_shifted(v:Vec2, bits:Int -> Vec2; inline)
return Vec2(v.x << bits, v.y << bits)
- func modulo(v:Vec2, modulus:Int -> Vec2; inline):
+ func modulo(v:Vec2, modulus:Int -> Vec2; inline)
return Vec2(v.x mod modulus, v.y mod modulus)
- func modulo1(v:Vec2, modulus:Int -> Vec2; inline):
+ func modulo1(v:Vec2, modulus:Int -> Vec2; inline)
return Vec2(v.x mod1 modulus, v.y mod1 modulus)
-func main():
+func main()
>> x := Vec2(10, 20)
>> y := Vec2(100, 200)
>> x + y
diff --git a/test/minmax.tm b/test/minmax.tm
index a0f0640f..8ffb401e 100644
--- a/test/minmax.tm
+++ b/test/minmax.tm
@@ -1,9 +1,9 @@
-struct Foo(x:Int, y:Int):
- func len(f:Foo->Num):
+struct Foo(x:Int, y:Int)
+ func len(f:Foo->Num)
return Num.sqrt(Num(f.x*f.x + f.y*f.y))!
-func main():
+func main()
>> 3 _min_ 5
= 3
>> 5 _min_ 3
diff --git a/test/nums.tm b/test/nums.tm
index e5de1e22..573b50ec 100644
--- a/test/nums.tm
+++ b/test/nums.tm
@@ -1,4 +1,4 @@
-func main():
+func main()
>> n := 1.5
= 1.5
diff --git a/test/optionals.tm b/test/optionals.tm
index bf3e1633..d81d065f 100644
--- a/test/optionals.tm
+++ b/test/optionals.tm
@@ -1,74 +1,74 @@
-struct Struct(x:Int, y:Text):
- func maybe(should_i:Bool->Struct?):
- if should_i:
+struct Struct(x:Int, y:Text)
+ func maybe(should_i:Bool->Struct?)
+ if should_i
return Struct(123, "hello")
- else:
+ else
return none
-enum Enum(X, Y(y:Int)):
- func maybe(should_i:Bool->Enum?):
- if should_i:
+enum Enum(X, Y(y:Int))
+ func maybe(should_i:Bool->Enum?)
+ if should_i
return Enum.Y(123)
- else:
+ else
return none
-func maybe_int(should_i:Bool->Int?):
- if should_i:
+func maybe_int(should_i:Bool->Int?)
+ if should_i
return 123
- else:
+ else
return none
-func maybe_int64(should_i:Bool->Int64?):
- if should_i:
+func maybe_int64(should_i:Bool->Int64?)
+ if should_i
return Int64(123)
- else:
+ else
return none
-func maybe_array(should_i:Bool->[Int]?):
- if should_i:
+func maybe_array(should_i:Bool->[Int]?)
+ if should_i
return [10, 20, 30]
- else:
+ else
return none
-func maybe_bool(should_i:Bool->Bool?):
- if should_i:
+func maybe_bool(should_i:Bool->Bool?)
+ if should_i
return no
- else:
+ else
return none
-func maybe_text(should_i:Bool->Text?):
- if should_i:
+func maybe_text(should_i:Bool->Text?)
+ if should_i
return "Hello"
- else:
+ else
return none
-func maybe_num(should_i:Bool->Num?):
- if should_i:
+func maybe_num(should_i:Bool->Num?)
+ if should_i
return 12.3
- else:
+ else
return none
-func maybe_lambda(should_i:Bool-> func()?):
- if should_i:
- return func(): say("hi!")
- else:
+func maybe_lambda(should_i:Bool-> func()?)
+ if should_i
+ return func() say("hi!")
+ else
return none
-func maybe_c_string(should_i:Bool->CString?):
- if should_i:
+func maybe_c_string(should_i:Bool->CString?)
+ if should_i
return ("hi".as_c_string())?
- else:
+ else
return none
-func main():
+func main()
>> 5?
= 5?
- >> if no:
+ >> if no
x : Int? = none
x
- else:
+ else
5
= 5?
@@ -85,157 +85,157 @@ func main():
>> none_int or -1
= -1
- do:
+ do
say("Ints:")
>> yep := maybe_int(yes)
= 123?
>> nope := maybe_int(no)
= none
- >> if yep:
+ >> if yep
>> yep
= 123
- else: fail("Falsey: $yep")
- >> if nope:
+ else fail("Falsey: $yep")
+ >> if nope
fail("Truthy: $nope")
- else: say("Falsey: $nope")
+ else say("Falsey: $nope")
- do:
+ do
say("Int64s:")
>> yep := maybe_int64(yes)
= Int64(123)?
>> nope := maybe_int64(no)
= none
- >> if yep:
+ >> if yep
>> yep
= Int64(123)
- else: fail("Falsey: $yep")
- >> if nope:
+ else fail("Falsey: $yep")
+ >> if nope
fail("Truthy: $nope")
- else: say("Falsey: $nope")
+ else say("Falsey: $nope")
- do:
+ do
say("Arrays:")
>> yep := maybe_array(yes)
= [10, 20, 30]?
>> nope := maybe_array(no)
= none
- >> if yep:
+ >> if yep
>> yep
= [10, 20, 30]
- else: fail("Falsey: $yep")
- >> if nope:
+ else fail("Falsey: $yep")
+ >> if nope
fail("Truthy: $nope")
- else: say("Falsey: $nope")
+ else say("Falsey: $nope")
- do:
+ do
say("...")
say("Bools:")
>> yep := maybe_bool(yes)
= no?
>> nope := maybe_bool(no)
= none
- >> if yep:
+ >> if yep
>> yep
= no
- else: fail("Falsey: $yep")
- >> if nope:
+ else fail("Falsey: $yep")
+ >> if nope
fail("Truthy: $nope")
- else: say("Falsey: $nope")
+ else say("Falsey: $nope")
- do:
+ do
say("...")
say("Text:")
>> yep := maybe_text(yes)
= "Hello"?
>> nope := maybe_text(no)
= none
- >> if yep:
+ >> if yep
>> yep
= "Hello"
- else: fail("Falsey: $yep")
- >> if nope:
+ else fail("Falsey: $yep")
+ >> if nope
fail("Truthy: $nope")
- else: say("Falsey: $nope")
+ else say("Falsey: $nope")
- do:
+ do
say("...")
say("Nums:")
>> yep := maybe_num(yes)
= 12.3?
>> nope := maybe_num(no)
= none
- >> if yep:
+ >> if yep
>> yep
= 12.3
- else: fail("Falsey: $yep")
- >> if nope:
+ else fail("Falsey: $yep")
+ >> if nope
fail("Truthy: $nope")
- else: say("Falsey: $nope")
+ else say("Falsey: $nope")
- do:
+ do
say("...")
say("Lambdas:")
# >> yep := maybe_lambda(yes)
# = func() [optionals.tm:54] : func()?
>> nope := maybe_lambda(no)
= none
- # >> if yep:
+ # >> if yep
# >> yep
# = func() [optionals.tm:54]
- # else: fail("Falsey: $yep")
- >> if nope:
+ # else fail("Falsey: $yep")
+ >> if nope
fail("Truthy: $nope")
- else: say("Falsey: $nope")
+ else say("Falsey: $nope")
- do:
+ do
say("...")
say("Structs:")
>> yep := Struct.maybe(yes)
= Struct(x=123, y="hello")?
>> nope := Struct.maybe(no)
= none
- >> if yep:
+ >> if yep
>> yep
= Struct(x=123, y="hello")
- else: fail("Falsey: $yep")
- >> if nope:
+ else fail("Falsey: $yep")
+ >> if nope
fail("Truthy: $nope")
- else: say("Falsey: $nope")
+ else say("Falsey: $nope")
- do:
+ do
say("...")
say("Enums:")
>> yep := Enum.maybe(yes)
= Enum.Y(123)?
>> nope := Enum.maybe(no)
= none
- >> if yep:
+ >> if yep
>> yep
= Enum.Y(123)
- else: fail("Falsey: $yep")
- >> if nope:
+ else fail("Falsey: $yep")
+ >> if nope
fail("Truthy: $nope")
- else: say("Falsey: $nope")
+ else say("Falsey: $nope")
- do:
+ do
say("...")
say("C Strings:")
>> yep := maybe_c_string(yes)
= CString("hi")?
>> nope := maybe_c_string(no)
= none
- >> if yep:
+ >> if yep
>> yep
= CString("hi")
- else: fail("Falsey: $yep")
- >> if nope:
+ else fail("Falsey: $yep")
+ >> if nope
fail("Truthy: $nope")
- else: say("Falsey: $nope")
+ else say("Falsey: $nope")
- if yep := maybe_int(yes):
+ if yep := maybe_int(yes)
>> yep
= 123
- else: fail("Unreachable")
+ else fail("Unreachable")
>> maybe_int(yes)!
= 123
@@ -251,32 +251,32 @@ func main():
>> [5?, none, none, 6?].sorted()
= [none, none, 5, 6]
- do:
- >> value := if var := 5?:
+ do
+ >> value := if var := 5?
var
- else:
+ else
0
= 5
- do:
+ do
>> value := if var : Int? = none:
var
- else:
+ else
0
= 0
- do:
+ do
>> opt := 5?
- >> if opt:
+ >> if opt
>> opt
- else:
+ else
>> opt
- do:
+ do
>> opt : Int? = none
- >> if opt:
+ >> if opt
>> opt
- else:
+ else
>> opt
>> not 5?
@@ -289,7 +289,7 @@ func main():
>> [Struct(5,"A")?, Struct(6,"B"), Struct(7,"C")]
= [Struct(x=5, y="A")?, Struct(x=6, y="B")?, Struct(x=7, y="C")?]
- if 5? or no:
+ if 5? or no
say("Binary op 'or' works with optionals")
- else:
+ else
fail("Failed to do binary op 'or' on optional")
diff --git a/test/paths.tm b/test/paths.tm
index 85f9b191..700a0393 100644
--- a/test/paths.tm
+++ b/test/paths.tm
@@ -1,5 +1,5 @@
# Tests for file paths
-func main():
+func main()
>> (/).exists()
= yes
>> (~/).exists()
@@ -29,19 +29,19 @@ func main():
>> tmpdir.files().has(tmpfile)
= yes
- if tmp_lines := tmpfile.by_line():
+ if tmp_lines := tmpfile.by_line()
>> [line for line in tmp_lines]
= ["Hello world!"]
- else:
+ else
fail("Couldn't read lines in $tmpfile")
>> (./does-not-exist.xxx).read()
= none
>> (./does-not-exist.xxx).read_bytes()
= none
- if lines := (./does-not-exist.xxx).by_line():
+ if lines := (./does-not-exist.xxx).by_line()
fail("I could read lines in a nonexistent file")
- else:
+ else
pass
>> tmpfile.remove()
diff --git a/test/reductions.tm b/test/reductions.tm
index c56c7d09..2666e1a9 100644
--- a/test/reductions.tm
+++ b/test/reductions.tm
@@ -1,6 +1,6 @@
struct Foo(x,y:Int)
-func main():
+func main()
>> (+: [10, 20, 30])
= 60?
diff --git a/test/serialization.tm b/test/serialization.tm
index b3ccc67a..457442e5 100644
--- a/test/serialization.tm
+++ b/test/serialization.tm
@@ -3,45 +3,45 @@ struct Foo(name:Text, next:@Foo?=none)
enum MyEnum(Zero, One(x:Int), Two(x:Num, y:Text))
-func main():
- do:
+func main()
+ do
>> obj := Int64(123)
>> bytes := obj.serialized()
>> deserialize(bytes -> Int64) == obj
= yes
- do:
+ do
>> obj := 5
>> bytes := obj.serialized()
>> deserialize(bytes -> Int) == obj
= yes
- do:
+ do
>> obj := 9999999999999999999999999999999999999999999999999999
>> bytes := obj.serialized()
>> deserialize(bytes -> Int) == obj
= yes
- do:
+ do
>> obj := "Héllo"
>> bytes := obj.serialized()
>> deserialize(bytes -> Text)
>> deserialize(bytes -> Text) == obj
= yes
- do:
+ do
>> obj := [Int64(10), Int64(20), Int64(30)].reversed()
>> bytes := obj.serialized()
>> deserialize(bytes -> [Int64]) == obj
= yes
- do:
+ do
>> obj := yes
>> bytes := obj.serialized()
>> deserialize(bytes -> Bool) == obj
= yes
- do:
+ do
>> obj := @[10, 20]
>> bytes := obj.serialized()
>> roundtrip := deserialize(bytes -> @[Int])
@@ -50,46 +50,46 @@ func main():
>> roundtrip[] == obj[]
= yes
- do:
+ do
>> obj := {"A"=10, "B"=20; fallback={"C"=30}}
>> bytes := obj.serialized()
>> deserialize(bytes -> {Text=Int}) == obj
= yes
- do:
+ do
>> obj := @Foo("root")
>> obj.next = @Foo("abcdef", next=obj)
>> bytes := obj.serialized()
>> deserialize(bytes -> @Foo)
# = @Foo(name="root", next=@Foo(name="abcdef", next=@~1))
- do:
+ do
>> obj := MyEnum.Two(123, "OKAY")
>> bytes := obj.serialized()
>> deserialize(bytes -> MyEnum) == obj
= yes
- do:
+ do
>> obj := "Hello"?
>> bytes := obj.serialized()
>> deserialize(bytes -> Text?) == obj
= yes
- do:
+ do
>> obj := {10, 20, 30}
>> bytes := obj.serialized()
>> deserialize(bytes -> {Int}) == obj
= yes
- do:
+ do
>> obj : Num? = none
>> bytes := obj.serialized()
>> deserialize(bytes -> Num?) == obj
= yes
- do:
+ do
cases := [0, -1, 1, 10, 100000, 999999999999999999999999999]
- for i in cases:
+ for i in cases
>> bytes := i.serialized()
>> deserialize(bytes -> Int) == i
= yes
diff --git a/test/sets.tm b/test/sets.tm
index 5179947e..1c395fba 100644
--- a/test/sets.tm
+++ b/test/sets.tm
@@ -1,5 +1,5 @@
-func main():
+func main()
>> t1 := @{10, 20, 30, 10}
= @{10, 20, 30}
>> t1.has(10)
diff --git a/test/structs.tm b/test/structs.tm
index cf7b6a1c..f1ae49d0 100644
--- a/test/structs.tm
+++ b/test/structs.tm
@@ -8,7 +8,7 @@ struct Password(text:Text; secret)
struct CorecursiveA(other:@CorecursiveB?)
struct CorecursiveB(other:@CorecursiveA?=none)
-func test_literals():
+func test_literals()
>> Single(123)
= Single(123)
>> x := Pair(10, 20)
@@ -20,7 +20,7 @@ func test_literals():
>> x == Pair(-1, -2)
= no
-func test_metamethods():
+func test_metamethods()
>> x := Pair(10, 20)
>> y := Pair(100, 200)
>> x == y
@@ -38,7 +38,7 @@ func test_metamethods():
>> set.has(y)
= no
-func test_mixed():
+func test_mixed()
>> x := Mixed(10, "Hello")
>> y := Mixed(99, "Hello")
>> x == y
@@ -55,14 +55,14 @@ func test_mixed():
>> set.has(y)
= no
-func test_text():
+func test_text()
>> b := @CorecursiveB()
>> a := @CorecursiveA(b)
>> b.other = a
>> a
# = @CorecursiveA(@CorecursiveB(@~1))
-func main():
+func main()
test_literals()
test_metamethods()
test_mixed()
diff --git a/test/tables.tm b/test/tables.tm
index a5f51520..67299142 100644
--- a/test/tables.tm
+++ b/test/tables.tm
@@ -1,4 +1,4 @@
-func main():
+func main()
>> t := {"one"=1, "two"=2}
= {"one"=1, "two"=2}
@@ -14,7 +14,7 @@ func main():
= -1
t_str := ""
- for k,v in t:
+ for k,v in t
t_str ++= "($k=$v)"
>> t_str
= "(one=1)(two=2)"
@@ -45,7 +45,7 @@ func main():
= {"one"=1, "two"=2}?
t2_str := ""
- for k,v in t2:
+ for k,v in t2
t2_str ++= "($k=$v)"
>> t2_str
= "(three=3)"
@@ -62,7 +62,7 @@ func main():
>> t3
= @{1=10, 2=20}
- do:
+ do
>> plain := {1=10, 2=20, 3=30}
>> plain[2]!
= 20
@@ -81,14 +81,14 @@ func main():
>> fallback[1] or -999
= 10
- do:
+ do
>> t4 := &{"one"= 1}
>> t4["one"] = 999
>> t4["two"] = 222
>> t4
= &{"one"=999, "two"=222}
- do:
+ do
>> {1=1, 2=2} == {2=2, 1=1}
= yes
>> {1=1, 2=2} == {1=1, 2=999}
@@ -102,7 +102,7 @@ func main():
>> other_ints : [{Int}] = [{/}, {1}, {2}, {99}, {0, 3}, {1, 2}, {99}].sorted()
= [{/}, {0, 3}, {1}, {1, 2}, {2}, {99}, {99}]
- do:
+ do
# Default values:
counter := &{"x"=10; default=0}
>> counter["x"]
diff --git a/test/text.tm b/test/text.tm
index b353aa26..1cabbdea 100644
--- a/test/text.tm
+++ b/test/text.tm
@@ -1,4 +1,4 @@
-func main():
+func main()
str := "Hello Amélie!"
say("Testing strings like $str")
@@ -236,7 +236,7 @@ func main():
>> ("hello" ++ " " ++ "Amélie").reversed()
= "eilémA olleh"
- do:
+ do
say("Testing concatenation-stability:")
ab := Text.from_codepoint_names(["LATIN SMALL LETTER E", "COMBINING VERTICAL LINE BELOW"])!
>> ab.codepoint_names()
@@ -254,7 +254,7 @@ func main():
= 1
- do:
+ do
concat := "e" ++ Text.from_codepoints([Int32(0x300)])
>> concat.length
= 1
diff --git a/test/use_import.tm b/test/use_import.tm
index 714c26b0..a56d9cbb 100644
--- a/test/use_import.tm
+++ b/test/use_import.tm
@@ -2,8 +2,8 @@ struct ImportedType(name:Text)
needs_initializing := 999999999999999999
-func get_value(->ImportedType):
+func get_value(->ImportedType)
return ImportedType("Hello")
-func main():
+func main()
pass
diff --git a/test/when.tm b/test/when.tm
index d93745dd..28573d88 100644
--- a/test/when.tm
+++ b/test/when.tm
@@ -1,13 +1,13 @@
# Tests for the 'when' block
-func main():
+func main()
answers := [
(
- when x is "A","B":
+ when x is "A","B"
"A or B"
- is "C":
+ is "C"
"C"
- else:
+ else
"Other"
) for x in ["A", "B", "C", "D"]
]
@@ -15,7 +15,7 @@ func main():
= ["A or B", "A or B", "C", "Other"]
n := 23
- >> when n is 1: Int64(1)
- is 2: Int64(2)
- is 21 + 2: Int64(23)
+ >> when n is 1 Int64(1)
+ is 2 Int64(2)
+ is 21 + 2 Int64(23)
= Int64(23)?