aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/c-interoperability.md6
-rw-r--r--examples/colorful/colorful.tm12
-rw-r--r--examples/coroutines/coroutines.tm20
-rw-r--r--examples/game/player.tm8
-rw-r--r--examples/http-server/http-server.tm18
-rw-r--r--examples/http/http.tm50
-rw-r--r--examples/ini/ini.tm14
-rw-r--r--examples/log/log.tm4
-rw-r--r--examples/wrap/wrap.tm8
-rw-r--r--lib/commands/commands.tm16
-rw-r--r--lib/json/json.tm2
-rw-r--r--lib/patterns/patterns.tm28
-rw-r--r--lib/pthreads/pthreads.tm57
-rw-r--r--lib/random/random.tm46
-rw-r--r--lib/shell/shell.tm2
-rw-r--r--lib/time/time.tm42
-rw-r--r--src/parse/text.c100
-rw-r--r--test/inline_c.tm6
-rw-r--r--test/text.tm11
19 files changed, 223 insertions, 227 deletions
diff --git a/docs/c-interoperability.md b/docs/c-interoperability.md
index 3c0906ee..ae959220 100644
--- a/docs/c-interoperability.md
+++ b/docs/c-interoperability.md
@@ -23,12 +23,12 @@ without evaluating to anything:
```tomo
# Inline C block:
-C_code {
+C_code `
printf("This is just a block that is executed without a return value\n");
-}
+`
# Inline C expression (you must specify a type)
-val := C_code : Int32 (int x = 1; x + 1)
+val := C_code : Int32 `int x = 1; x + 1`
```
Inline C expressions must specify a type and they can be [compound statement
diff --git a/examples/colorful/colorful.tm b/examples/colorful/colorful.tm
index 5b01cfd5..8a1d46b0 100644
--- a/examples/colorful/colorful.tm
+++ b/examples/colorful/colorful.tm
@@ -45,18 +45,18 @@ func main(texts:[Text], files:[Path]=[], by_line=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))
+ 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}/)
+ if text.matches_pattern($Pat"#{3-6 hex}")
hex := text.from(2)
return none unless hex.length == 3 or hex.length == 6
if hex.length == 3
hex = hex[1]++hex[1]++hex[2]++hex[2]++hex[3]++hex[3]
n := Int32.parse("0x" ++ hex) or return none
return Color24Bit(n)
- else if text.matches_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)
@@ -171,10 +171,10 @@ func _add_ansi_sequences(text:Text, prev_state:_TermState -> Text)
else if text == "rparen" return ")"
else if text == "@" or text == "at" return "@"
parts := (
- text.pattern_captures($Pat/{0+..}:{0+..}/) or
+ 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}/)
+ attributes := parts[1].split_pattern($Pat"{0+space},{0+space}")
new_state := prev_state
for attr in attributes
if attr.starts_with("fg=")
@@ -215,6 +215,6 @@ func _add_ansi_sequences(text:Text, prev_state:_TermState -> Text)
fail("Invalid attribute: '$attr'")
result := prev_state.apply(new_state)
- result ++= parts[2].map_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/coroutines/coroutines.tm b/examples/coroutines/coroutines.tm
index b530a685..c4ef1a97 100644
--- a/examples/coroutines/coroutines.tm
+++ b/examples/coroutines/coroutines.tm
@@ -37,31 +37,31 @@ struct Coroutine(co:@aco_t)
main_co := _main_co
shared_stack := _shared_stack
- aco_ptr := C_code:@aco_t(
+ aco_ptr := C_code:@aco_t `
aco_create(@main_co, @shared_stack, 0, (void*)@fn.fn, @fn.userdata)
- )
+ `
return Coroutine(aco_ptr)
func is_finished(co:Coroutine->Bool; inline)
- return C_code:Bool(((aco_t*)@co.co)->is_finished)
+ return C_code:Bool`((aco_t*)@co.co)->is_finished`
func resume(co:Coroutine->Bool)
if co.is_finished()
return no
- C_code { aco_resume(@co.co); }
+ C_code `aco_resume(@co.co);`
return yes
func _init()
- C_code {
+ C_code `
aco_set_allocator(GC_malloc, NULL);
aco_thread_init(aco_exit_fn);
- }
- _main_co = C_code:@aco_t(aco_create(NULL, NULL, 0, NULL, NULL))
+ `
+ _main_co = C_code:@aco_t`aco_create(NULL, NULL, 0, NULL, NULL)`
- _shared_stack = C_code:@aco_shared_stack_t(aco_shared_stack_new(0))
+ _shared_stack = C_code:@aco_shared_stack_t`aco_shared_stack_new(0)`
func yield(; inline)
- C_code {
+ C_code `
aco_yield();
- }
+ `
diff --git a/examples/game/player.tm b/examples/game/player.tm
index 2e5e54f6..b34eadd0 100644
--- a/examples/game/player.tm
+++ b/examples/game/player.tm
@@ -10,12 +10,12 @@ struct Player(pos,prev_pos:Vector2)
COLOR := Color(0x60, 0x60, 0xbF)
func update(p:@Player)
- target_x := C_code:Num32(
+ target_x := C_code:Num32`
(Num32_t)((IsKeyDown(KEY_A) ? -1 : 0) + (IsKeyDown(KEY_D) ? 1 : 0))
- )
- target_y := C_code:Num32(
+ `
+ target_y := C_code:Num32`
(Num32_t)((IsKeyDown(KEY_W) ? -1 : 0) + (IsKeyDown(KEY_S) ? 1 : 0))
- )
+ `
target_vel := Vector2(target_x, target_y).norm() * Player.WALK_SPEED
vel := (p.pos - p.prev_pos)/World.DT
diff --git a/examples/http-server/http-server.tm b/examples/http-server/http-server.tm
index 8e8aff7e..dbe57805 100644
--- a/examples/http-server/http-server.tm
+++ b/examples/http-server/http-server.tm
@@ -22,7 +22,7 @@ func serve(port:Int32, handler:func(request:HTTPRequest -> HTTPResponse), num_th
workers.insert(pthread_t.new(func()
repeat
connection := connections.dequeue()
- request_text := C_code:Text(
+ request_text := C_code:Text```
Text_t request = EMPTY_TEXT;
char buf[1024] = {};
for (ssize_t n; (n = read(@connection, buf, sizeof(buf) - 1)) > 0; ) {
@@ -32,20 +32,20 @@ func serve(port:Int32, handler:func(request:HTTPRequest -> HTTPResponse), num_th
break;
}
request
- )
+ ```
request := HTTPRequest.from_text(request_text) or skip
response := handler(request).bytes()
- C_code {
+ C_code `
if (@response.stride != 1)
List$compact(&@response, 1);
write(@connection, @response.data, @response.length);
close(@connection);
- }
+ `
))
- sock := C_code:Int32(
+ sock := C_code:Int32 `
int s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) err(1, "Couldn't connect to socket!");
@@ -60,10 +60,10 @@ func serve(port:Int32, handler:func(request:HTTPRequest -> HTTPResponse), num_th
err(1, "Couldn't listen on socket");
s
- )
+ `
repeat
- conn := C_code:Int32(accept(@sock, NULL, NULL))
+ conn := C_code:Int32`accept(@sock, NULL, NULL)`
stop if conn < 0
connections.enqueue(conn)
@@ -77,8 +77,8 @@ struct HTTPRequest(method:Text, path:Text, version:Text, headers:[Text], body:Te
method := m[1]
path := m[2].replace_pattern($Pat'{2+ /}', '/')
version := m[3]
- rest := m[-1].pattern_captures($Pat/{..}{2 crlf}{0+ ..}/) or return none
- headers := rest[1].split_pattern($Pat/{crlf}/)
+ rest := m[-1].pattern_captures($Pat'{..}{2 crlf}{0+ ..}') or return none
+ headers := rest[1].split_pattern($Pat'{crlf}')
body := rest[-1]
return HTTPRequest(method, path, version, headers, body)
diff --git a/examples/http/http.tm b/examples/http/http.tm
index 3fe41ae2..8d111904 100644
--- a/examples/http/http.tm
+++ b/examples/http/http.tm
@@ -10,73 +10,73 @@ enum _Method(GET, POST, PUT, PATCH, DELETE)
func _send(method:_Method, url:Text, data:Text?, headers:[Text]=[] -> HTTPResponse)
chunks : @[Text]
save_chunk := func(chunk:CString, size:Int64, n:Int64)
- chunks.insert(C_code:Text(Text$from_strn(@chunk, @size*@n)))
+ chunks.insert(C_code:Text`Text$from_strn(@chunk, @size*@n)`)
return n*size
- C_code {
+ C_code `
CURL *curl = curl_easy_init();
struct curl_slist *chunk = NULL;
curl_easy_setopt(curl, CURLOPT_URL, @(CString(url)));
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, @save_chunk.fn);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, @save_chunk.userdata);
- }
+ `
defer
- C_code {
+ C_code `
if (chunk)
curl_slist_free_all(chunk);
curl_easy_cleanup(curl);
- }
+ `
when method is POST
- C_code {
+ C_code `
curl_easy_setopt(curl, CURLOPT_POST, 1L);
- }
+ `
if posting := data
- C_code {
+ C_code `
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, @(CString(posting)));
- }
+ `
is PUT
- C_code {
+ C_code `
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
- }
+ `
if putting := data
- C_code {
+ C_code `
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, @(CString(putting)));
- }
+ `
is PATCH
- C_code {
+ C_code `
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
- }
+ `
if patching := data
- C_code {
+ C_code `
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, @(CString(patching)));
- }
+ `
is DELETE
- C_code {
+ C_code `
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
- }
+ `
else
pass
for header in headers
- C_code {
+ C_code `
chunk = curl_slist_append(chunk, @(CString(header)));
- }
+ `
- C_code {
+ C_code `
if (chunk)
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
- }
+ `
code := Int64(0)
- C_code {
+ C_code ```
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &@code);
- }
+ ```
return HTTPResponse(Int(code), "".join(chunks))
func get(url:Text, headers:[Text]=[] -> HTTPResponse)
diff --git a/examples/ini/ini.tm b/examples/ini/ini.tm
index 4dc27725..576d273f 100644
--- a/examples/ini/ini.tm
+++ b/examples/ini/ini.tm
@@ -15,24 +15,24 @@ func parse_ini(path:Path -> {Text={Text=Text}})
current_section : @{Text=Text}
# Line wraps:
- text = text.replace_pattern($Pat/\\{1 nl}{0+space}/, " ")
+ text = text.replace_pattern($Pat`\\{1 nl}{0+space}`, " ")
for line in text.lines()
line = line.trim()
skip if line.starts_with(";") or line.starts_with("#")
- if line.matches_pattern($Pat/[?]/)
- section_name := line.replace($Pat/[?]/, "@1").trim().lower()
+ 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/{..}={..}/)
- key := line.replace_pattern($Pat/{..}={..}/, "@1").trim().lower()
- value := line.replace_pattern($Pat/{..}={..}/, "@2").trim()
+ else if line.matches_pattern($Pat`{..}={..}`)
+ key := line.replace_pattern($Pat`{..}={..}`, "@1").trim().lower()
+ value := line.replace_pattern($Pat`{..}={..}`, "@2").trim()
current_section[key] = value
return {k=v[] for k,v in sections[]}
func main(path:Path, key:Text?)
- keys := (key or "").split($|/|)
+ keys := (key or "").split(`/`)
if keys.length > 2
exit("
Too many arguments!
diff --git a/examples/log/log.tm b/examples/log/log.tm
index 4b7893fd..2798b7ae 100644
--- a/examples/log/log.tm
+++ b/examples/log/log.tm
@@ -6,13 +6,13 @@ timestamp_format := CString("%F %T")
logfiles : @|Path|
func _timestamp(->Text)
- c_str := C_code:CString(
+ c_str := C_code:CString`
char *str = GC_MALLOC_ATOMIC(20);
time_t t; time(&t);
struct tm *tm_info = localtime(&t);
strftime(str, 20, "%F %T", tm_info);
str
- )
+ `
return c_str.as_text()
func info(text:Text, newline=yes)
diff --git a/examples/wrap/wrap.tm b/examples/wrap/wrap.tm
index bae01739..402d22af 100644
--- a/examples/wrap/wrap.tm
+++ b/examples/wrap/wrap.tm
@@ -1,3 +1,5 @@
+use patterns
+
HELP := "
wrap: A tool for wrapping lines of text
@@ -15,7 +17,7 @@ UNICODE_HYPHEN := "\{hyphen}"
func unwrap(text:Text, preserve_paragraphs=yes, hyphen=UNICODE_HYPHEN -> Text)
if preserve_paragraphs
- paragraphs := text.split($/{2+ nl}/)
+ paragraphs := text.split_pattern($Pat"{2+ nl}")
if paragraphs.length > 1
return "\n\n".join([unwrap(p, hyphen=hyphen, preserve_paragraphs=no) for p in paragraphs])
@@ -35,7 +37,7 @@ 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_pattern($Pat"{whitespace}")
letters := word.split()
skip if letters.length == 0
@@ -94,7 +96,7 @@ func main(files:[Path], width=80, inplace=no, min_split=3, rewrap=yes, hyphen=UN
first := yes
wrapped_paragraphs : @[Text]
- for paragraph in text.split($/{2+ nl}/)
+ for paragraph in text.split_pattern($Pat"{2+ nl}")
wrapped_paragraphs.insert(
wrap(paragraph, width=width, min_split=min_split, hyphen=hyphen)
)
diff --git a/lib/commands/commands.tm b/lib/commands/commands.tm
index 8a131042..b9b176af 100644
--- a/lib/commands/commands.tm
+++ b/lib/commands/commands.tm
@@ -57,22 +57,22 @@ struct Command(command:Text, args:[Text]=[], env:{Text=Text}={})
errors : [Byte]
status := run_command(command.command, command.args, command.env, input_bytes, &output, &errors)
- if C_code:Bool(WIFEXITED(@status))
- return ProgramResult(output, errors, ExitType.Exited(C_code:Int32(WEXITSTATUS(@status))))
+ if C_code:Bool`WIFEXITED(@status)`
+ return ProgramResult(output, errors, ExitType.Exited(C_code:Int32`WEXITSTATUS(@status)`))
- if C_code:Bool(WIFSIGNALED(@status))
- return ProgramResult(output, errors, ExitType.Signaled(C_code:Int32(WTERMSIG(@status))))
+ if C_code:Bool`WIFSIGNALED(@status)`
+ return ProgramResult(output, errors, ExitType.Signaled(C_code:Int32`WTERMSIG(@status)`))
return ProgramResult(output, errors, ExitType.Failed)
func run(command:Command, -> ExitType)
status := run_command(command.command, command.args, command.env, none, none, none)
- if C_code:Bool(WIFEXITED(@status))
- return ExitType.Exited(C_code:Int32(WEXITSTATUS(@status)))
+ if C_code:Bool`WIFEXITED(@status)`
+ return ExitType.Exited(C_code:Int32`WEXITSTATUS(@status)`)
- if C_code:Bool(WIFSIGNALED(@status))
- return ExitType.Signaled(C_code:Int32(WTERMSIG(@status)))
+ if C_code:Bool`WIFSIGNALED(@status)`
+ return ExitType.Signaled(C_code:Int32`WTERMSIG(@status)`)
return ExitType.Failed
diff --git a/lib/json/json.tm b/lib/json/json.tm
index 8127ce52..35a139c5 100644
--- a/lib/json/json.tm
+++ b/lib/json/json.tm
@@ -78,7 +78,7 @@ enum JSON(
if esc := escapes[text[pos+1]]
string ++= esc
pos += 2
- else if m := text.matching_pattern($Pat/u{4 digit}/)
+ else if m := text.matching_pattern($Pat"u{4 digit}")
string ++= Text.from_codepoints([Int32.parse(m.captures[1])!])
pos += 1 + m.text.length
else
diff --git a/lib/patterns/patterns.tm b/lib/patterns/patterns.tm
index c5444b86..f62c6be0 100644
--- a/lib/patterns/patterns.tm
+++ b/lib/patterns/patterns.tm
@@ -4,7 +4,7 @@ struct PatternMatch(text:Text, index:Int, captures:[Text])
lang Pat
convert(text:Text -> Pat)
- return C_code:Pat(Pattern$escape_text(@text))
+ return C_code:Pat`Pattern$escape_text(@text)`
convert(n:Int -> Pat)
return Pat.from_text("$n")
@@ -12,45 +12,45 @@ lang Pat
extend Text
func matching_pattern(text:Text, pattern:Pat, pos:Int = 1 -> PatternMatch?)
result : PatternMatch
- if C_code:Bool(Pattern$match_at(@text, @pattern, @pos, (void*)&@result))
+ if C_code:Bool`Pattern$match_at(@text, @pattern, @pos, (void*)&@result)`
return result
return none
func matches_pattern(text:Text, pattern:Pat -> Bool)
- return C_code:Bool(Pattern$matches(@text, @pattern))
+ return C_code:Bool`Pattern$matches(@text, @pattern)`
func pattern_captures(text:Text, pattern:Pat -> [Text]?)
- return C_code:[Text]?(Pattern$captures(@text, @pattern))
+ return C_code:[Text]?`Pattern$captures(@text, @pattern)`
func replace_pattern(text:Text, pattern:Pat, replacement:Text, backref="@", recursive=yes -> Text)
- return C_code:Text(Pattern$replace(@text, @pattern, @replacement, @backref, @recursive))
+ return C_code:Text`Pattern$replace(@text, @pattern, @replacement, @backref, @recursive)`
func translate_patterns(text:Text, replacements:{Pat=Text}, backref="@", recursive=yes -> Text)
- return C_code:Text(Pattern$replace_all(@text, @replacements, @backref, @recursive))
+ return C_code:Text`Pattern$replace_all(@text, @replacements, @backref, @recursive)`
func has_pattern(text:Text, pattern:Pat -> Bool)
- return C_code:Bool(Pattern$has(@text, @pattern))
+ return C_code:Bool`Pattern$has(@text, @pattern)`
func find_patterns(text:Text, pattern:Pat -> [PatternMatch])
- return C_code:[PatternMatch](Pattern$find_all(@text, @pattern))
+ return C_code:[PatternMatch]`Pattern$find_all(@text, @pattern)`
func by_pattern(text:Text, pattern:Pat -> func(->PatternMatch?))
- return C_code:func(->PatternMatch?)(Pattern$by_match(@text, @pattern))
+ return C_code:func(->PatternMatch?)`Pattern$by_match(@text, @pattern)`
func each_pattern(text:Text, pattern:Pat, fn:func(m:PatternMatch), recursive=yes)
- C_code { Pattern$each(@text, @pattern, @fn, @recursive); }
+ C_code `Pattern$each(@text, @pattern, @fn, @recursive);`
func map_pattern(text:Text, pattern:Pat, fn:func(m:PatternMatch -> Text), recursive=yes -> Text)
- return C_code:Text(Pattern$map(@text, @pattern, @fn, @recursive))
+ return C_code:Text`Pattern$map(@text, @pattern, @fn, @recursive)`
func split_pattern(text:Text, pattern:Pat -> [Text])
- return C_code:[Text](Pattern$split(@text, @pattern))
+ return C_code:[Text]`Pattern$split(@text, @pattern)`
func by_pattern_split(text:Text, pattern:Pat -> func(->Text?))
- return C_code:func(->Text?)(Pattern$by_split(@text, @pattern))
+ return C_code:func(->Text?)`Pattern$by_split(@text, @pattern)`
func trim_pattern(text:Text, pattern=$Pat"{space}", left=yes, right=yes -> Text)
- return C_code:Text(Pattern$trim(@text, @pattern, @left, @right))
+ return C_code:Text`Pattern$trim(@text, @pattern, @left, @right)`
func main()
>> "Hello world".matching_pattern($Pat'{id}')
diff --git a/lib/pthreads/pthreads.tm b/lib/pthreads/pthreads.tm
index 8fca6bd6..c93df20a 100644
--- a/lib/pthreads/pthreads.tm
+++ b/lib/pthreads/pthreads.tm
@@ -3,66 +3,83 @@ use <pthread.h>
struct pthread_mutex_t(; extern, opaque)
func new(->@pthread_mutex_t)
- return C_code : @pthread_mutex_t(
+ return C_code : @pthread_mutex_t `
pthread_mutex_t *mutex = GC_MALLOC(sizeof(pthread_mutex_t));
pthread_mutex_init(mutex, NULL);
GC_register_finalizer(mutex, (void*)pthread_mutex_destroy, NULL, NULL, NULL);
mutex
- )
+ `
func lock(m:&pthread_mutex_t)
- fail("Failed to lock mutex") unless C_code:Int32(pthread_mutex_lock(@m)) == 0
+ fail("Failed to lock mutex") unless C_code:Int32 `pthread_mutex_lock(@m)` == 0
func unlock(m:&pthread_mutex_t)
- fail("Failed to unlock mutex") unless C_code:Int32(pthread_mutex_unlock(@m)) == 0
+ fail("Failed to unlock mutex") unless C_code:Int32 `pthread_mutex_unlock(@m)` == 0
struct pthread_cond_t(; extern, opaque)
func new(->@pthread_cond_t)
- return C_code : @pthread_cond_t(
+ return C_code : @pthread_cond_t `
pthread_cond_t *cond = GC_MALLOC(sizeof(pthread_cond_t));
pthread_cond_init(cond, NULL);
GC_register_finalizer(cond, (void*)pthread_cond_destroy, NULL, NULL, NULL);
cond
- )
+ `
func wait(cond:&pthread_cond_t, mutex:&pthread_mutex_t)
- fail("Failed to wait on condition") unless C_code:Int32(pthread_cond_wait(@cond, @mutex)) == 0
+ fail("Failed to wait on condition") unless C_code:Int32 `pthread_cond_wait(@cond, @mutex)` == 0
func signal(cond:&pthread_cond_t)
- fail("Failed to signal pthread_cond_t") unless C_code:Int32(pthread_cond_signal(@cond)) == 0
+ fail("Failed to signal pthread_cond_t") unless C_code:Int32 `pthread_cond_signal(@cond)` == 0
func broadcast(cond:&pthread_cond_t)
- fail("Failed to broadcast pthread_cond_t") unless C_code:Int32(pthread_cond_broadcast(@cond)) == 0
+ fail("Failed to broadcast pthread_cond_t") unless C_code:Int32 `pthread_cond_broadcast(@cond)` == 0
struct pthread_rwlock_t(; extern, opaque)
func new(->@pthread_rwlock_t)
- return C_code : @pthread_rwlock_t (
+ return C_code : @pthread_rwlock_t `
pthread_rwlock_t *lock = GC_MALLOC(sizeof(pthread_rwlock_t));
pthread_rwlock_init(lock, NULL);
GC_register_finalizer(lock, (void*)pthread_rwlock_destroy, NULL, NULL, NULL);
lock
- )
+ `
func read_lock(lock:&pthread_rwlock_t)
- C_code { pthread_rwlock_rdlock(@lock); }
+ C_code `
+ pthread_rwlock_rdlock(@lock);
+ `
func write_lock(lock:&pthread_rwlock_t)
- C_code { pthread_rwlock_wrlock(@lock); }
+ C_code `
+ pthread_rwlock_wrlock(@lock);
+ `
func unlock(lock:&pthread_rwlock_t)
- C_code { pthread_rwlock_unlock(@lock); }
+ C_code `
+ pthread_rwlock_unlock(@lock);
+ `
struct pthread_t(; extern, opaque)
func new(fn:func() -> @pthread_t)
- return C_code:@pthread_t(
+ return C_code:@pthread_t `
pthread_t *thread = GC_MALLOC(sizeof(pthread_t));
pthread_create(thread, NULL, @fn.fn, @fn.userdata);
thread
- )
-
- func join(p:pthread_t) C_code { pthread_join(@p, NULL); }
- func cancel(p:pthread_t) C_code { pthread_cancel(@p); }
- func detatch(p:pthread_t) C_code { pthread_detach(@p); }
+ `
+
+ func join(p:pthread_t)
+ C_code `
+ pthread_join(@p, NULL);
+ `
+
+ func cancel(p:pthread_t)
+ C_code `
+ pthread_cancel(@p);
+ `
+
+ func detatch(p:pthread_t)
+ C_code `
+ pthread_detach(@p);
+ `
struct IntQueue(_queue:@[Int], _mutex:@pthread_mutex_t, _cond:@pthread_cond_t)
func new(initial:[Int]=[] -> IntQueue)
diff --git a/lib/random/random.tm b/lib/random/random.tm
index 107fad66..6d639c3a 100644
--- a/lib/random/random.tm
+++ b/lib/random/random.tm
@@ -6,7 +6,7 @@ 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)
- return C_code:chacha_ctx(
+ return C_code:chacha_ctx `
chacha_ctx ctx;
uint8_t seed_bytes[KEYSZ + IVSZ] = {};
for (int64_t i = 0; i < (int64_t)sizeof(seed_bytes); i++)
@@ -14,23 +14,24 @@ struct chacha_ctx(j0,j1,j2,j3,j4,j5,j6,j7,j8,j9,j10,j11,j12,j13,j14,j15:Int32; e
chacha_keysetup(&ctx, seed_bytes);
chacha_ivsetup(&ctx, seed_bytes + KEYSZ);
ctx
- )
+ `
random := RandomNumberGenerator.new()
func _os_random_bytes(count:Int64 -> [Byte])
- return C_code:[Byte](
+ return C_code:[Byte] `
uint8_t *random_bytes = GC_MALLOC_ATOMIC(@count);
assert(getrandom(random_bytes, (size_t)@count, 0) == (size_t)@count);
(List_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)
ctx := chacha_ctx.from_seed(seed or _os_random_bytes(40))
return @RandomNumberGenerator(ctx, [])
func _rekey(rng:&RandomNumberGenerator)
- rng._random_bytes = C_code:[Byte](
+ rng._random_bytes = C_code:[Byte] `
Byte_t new_keystream[KEYSZ + IVSZ] = {};
// Fill the buffer with the keystream
chacha_encrypt_bytes(&@rng->_chacha, new_keystream, new_keystream, sizeof(new_keystream));
@@ -41,10 +42,10 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
memset(new_bytes.data, 0, new_bytes.length);
chacha_encrypt_bytes(&@rng->_chacha, new_bytes.data, new_bytes.data, new_bytes.length);
new_bytes
- )
+ `
func _fill_bytes(rng:&RandomNumberGenerator, dest:&Memory, needed:Int64)
- C_code {
+ C_code `
while (@needed > 0) {
if (@rng->_random_bytes.length == 0)
@(rng._rekey());
@@ -60,13 +61,13 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
@dest += batch_size;
@needed -= batch_size;
}
- }
+ `
func bytes(rng:&RandomNumberGenerator, count:Int -> [Byte])
count64 := Int64(count)
- buf := C_code:@Memory(GC_MALLOC_ATOMIC(@count64))
+ buf := C_code:@Memory `GC_MALLOC_ATOMIC(@count64)`
rng._fill_bytes(buf, count64)
- return C_code:[Byte]((List_t){.data=@buf, .stride=1, .atomic=1, .length=@count64})
+ return C_code:[Byte] `(List_t){.data=@buf, .stride=1, .atomic=1, .length=@count64}`
func byte(rng:&RandomNumberGenerator -> Byte)
byte : &Byte
@@ -87,7 +88,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
if min == Int64.min and max == Int64.max
return random_int64
- return C_code:Int64(
+ return C_code:Int64 `
uint64_t range = (uint64_t)@max - (uint64_t)@min + 1;
uint64_t min_r = -range % range;
uint64_t r;
@@ -97,7 +98,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
if (r >= min_r) break;
}
(int64_t)((uint64_t)@min + (r % range))
- )
+ `
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
@@ -107,7 +108,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
if min == Int32.min and max == Int32.max
return random_int32
- return C_code:Int32(
+ return C_code:Int32 `
uint32_t range = (uint32_t)@max - (uint32_t)@min + 1;
uint32_t min_r = -range % range;
uint32_t r;
@@ -117,7 +118,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
if (r >= min_r) break;
}
(int32_t)((uint32_t)@min + (r % range))
- )
+ `
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
@@ -127,7 +128,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
if min == Int16.min and max == Int16.max
return random_int16
- return C_code:Int16(
+ return C_code:Int16 `
uint16_t range = (uint16_t)@max - (uint16_t)@min + 1;
uint16_t min_r = -range % range;
uint16_t r;
@@ -137,7 +138,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
if (r >= min_r) break;
}
(int16_t)((uint16_t)@min + (r % range))
- )
+ `
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
@@ -147,7 +148,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
if min == Int8.min and max == Int8.max
return random_int8
- return C_code:Int8(
+ return C_code:Int8 `
uint8_t range = (uint8_t)@max - (uint8_t)@min + 1;
uint8_t min_r = -range % range;
uint8_t r;
@@ -157,11 +158,11 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
if (r >= min_r) break;
}
(int8_t)((uint8_t)@min + (r % range))
- )
+ `
func num(rng:&RandomNumberGenerator, min=0., max=1. -> Num)
num_buf : &Num
- return C_code:Num(
+ return C_code:Num `
if (@min > @max) fail("Random minimum value (", @min, ") is larger than the maximum value (", @max, ")");
if (@min == @max) return @min;
@@ -179,13 +180,13 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
r.num -= 1.0;
(@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)
return Num32(rng.num(Num(min), Num(max)))
func int(rng:&RandomNumberGenerator, min:Int, max:Int -> Int)
- return C_code:Int(
+ return C_code:Int `
if (likely(((@min.small & @max.small) & 1) != 0)) {
int32_t r = @(rng.int32(Int32(min), Int32(max)));
return I_small(r);
@@ -217,8 +218,7 @@ struct RandomNumberGenerator(_chacha:chacha_ctx, _random_bytes:[Byte]=[]; secret
gmp_randclear(gmp_rng);
Int$plus(@min, Int$from_mpz(r))
- )
-
+ `
func main()
>> rng := RandomNumberGenerator.new()
diff --git a/lib/shell/shell.tm b/lib/shell/shell.tm
index f9476161..08b36f1a 100644
--- a/lib/shell/shell.tm
+++ b/lib/shell/shell.tm
@@ -2,7 +2,7 @@ use commands_v1.0
lang Shell
convert(text:Text -> Shell)
- return Shell.from_text("'" ++ text.replace($/'/, `'"'"'`) ++ "'")
+ return Shell.from_text("'" ++ text.replace(`'`, `'"'"'`) ++ "'")
convert(texts:[Text] -> Shell)
return Shell.from_text(" ".join([Shell(t).text for t in texts]))
diff --git a/lib/time/time.tm b/lib/time/time.tm
index d26d7218..cb7005cf 100644
--- a/lib/time/time.tm
+++ b/lib/time/time.tm
@@ -8,15 +8,15 @@ struct TimeInfo(year,month,day,hour,minute,second,nanosecond:Int, weekday:Weekda
struct Time(tv_sec:Int64, tv_usec:Int64; extern)
func now(->Time)
- return C_code : Time (
+ return C_code : Time `
struct timespec ts;
if (clock_gettime(CLOCK_REALTIME, &ts) != 0)
fail("Couldn't get the time!");
(Time){.tv_sec=ts.tv_sec, .tv_usec=ts.tv_nsec/1000}
- )
+ `
func local_timezone(->Text)
- C_code {
+ C_code `
if (_local_timezone.length < 0) {
static char buf[PATH_MAX];
ssize_t len = readlink("/etc/localtime", buf, sizeof(buf));
@@ -29,18 +29,18 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern)
else
fail("Could not resolve local tz!");
}
- }
- return C_code:Text(_local_timezone)
+ `
+ return C_code:Text`_local_timezone`
func set_local_timezone(timezone:Text)
- C_code {
+ C_code `
setenv("TZ", @(CString(timezone)), 1);
_local_timezone = @timezone;
tzset();
- }
+ `
func format(t:Time, format="%c", timezone=Time.local_timezone() -> Text)
- return C_code : Text (
+ return C_code : Text `
struct tm result;
time_t time = @t.tv_sec;
struct tm *final_info;
@@ -48,10 +48,10 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern)
static char buf[256];
size_t len = strftime(buf, sizeof(buf), String(@format), final_info);
Text$from_strn(buf, len)
- )
+ `
func new(year,month,day:Int, hour=0, minute=0, second=0.0, timezone=Time.local_timezone() -> Time)
- return C_code : Time(
+ return C_code : Time`
struct tm info = {
.tm_min=Int32$from_int(@minute, false),
.tm_hour=Int32$from_int(@hour, false),
@@ -64,13 +64,13 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern)
time_t t;
WITH_TIMEZONE(@timezone, t = mktime(&info));
(Time){.tv_sec=t + (time_t)@second, .tv_usec=(suseconds_t)(fmod(@second, 1.0) * 1e9)}
- )
+ `
func unix_timestamp(t:Time -> Int64)
- return C_code:Int64((int64_t)@t.tv_sec)
+ return C_code:Int64`(int64_t)@t.tv_sec`
func from_unix_timestamp(timestamp:Int64 -> Time)
- return C_code:Time((Time){.tv_sec=@timestamp};)
+ return C_code:Time`(Time){.tv_sec=@timestamp};`
func seconds_till(t:Time, target:Time -> Num)
seconds := Num(target.tv_sec - t.tv_sec)
@@ -84,7 +84,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern)
return t.seconds_till(target)/3600.
func relative(t:Time, relative_to=Time.now(), timezone=Time.local_timezone() -> Text)
- C_code {
+ C_code `
struct tm info = {};
struct tm relative_info = {};
WITH_TIMEZONE(@timezone, {
@@ -112,7 +112,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern)
else
return num_format((long)(second_diff), "second");
}
- }
+ `
fail("Unreachable")
func time(t:Time, seconds=no, am_pm=yes, timezone=Time.local_timezone() -> Text)
@@ -131,7 +131,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern)
func info(t:Time, timezone=Time.local_timezone() -> TimeInfo)
ret : TimeInfo
- C_code {
+ C_code `
struct tm info = {};
WITH_TIMEZONE(@timezone, localtime_r(&@t.tv_sec, &info));
@ret.year = I(info.tm_year + 1900);
@@ -144,11 +144,11 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern)
@ret.weekday = info.tm_wday + 1;
@ret.day_of_year = I(info.tm_yday);
@ret.timezone = @timezone;
- }
+ `
return ret
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 C_code : Time (
+ return C_code : Time `
double offset = @seconds + 60.*@minutes + 3600.*@hours ;
@t.tv_sec += (time_t)offset;
@@ -164,11 +164,11 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern)
.tv_sec=t,
.tv_usec=@t.tv_usec + (suseconds_t)(fmod(offset, 1.0) * 1e9),
}
- )
+ `
func parse(text:Text, format="%Y-%m-%dT%H:%M:%S%z", timezone=Time.local_timezone() -> Time?)
ret : Time?
- C_code {
+ C_code `
struct tm info = {.tm_isdst=-1};
const char *str = Text$as_c_string(@text);
const char *fmt = Text$as_c_string(@format);
@@ -185,7 +185,7 @@ struct Time(tv_sec:Int64, tv_usec:Int64; extern)
WITH_TIMEZONE(@timezone, t = mktime(&info));
@ret.value.tv_sec = t + offset - info.tm_gmtoff;
}
- }
+ `
return ret
func _run_tests()
diff --git a/src/parse/text.c b/src/parse/text.c
index c554273f..8897fd34 100644
--- a/src/parse/text.c
+++ b/src/parse/text.c
@@ -17,17 +17,33 @@
#include "types.h"
#include "utils.h"
-static const char closing[128] = {['('] = ')', ['['] = ']', ['<'] = '>', ['{'] = '}'};
-
-static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, char open_quote, char close_quote,
- char open_interp, bool allow_escapes) {
+static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos) {
const char *pos = *out_pos;
+
int64_t starting_indent = get_indent(ctx, pos);
int64_t string_indent = starting_indent + SPACES_PER_INDENT;
+
+ const char *quote, *interp;
+ bool allow_escapes = true;
+ if (match(&pos, "\"\"\"")) { // Triple double quote
+ quote = "\"\"\"", interp = "$", allow_escapes = false;
+ } else if (match(&pos, "'''")) { // Triple single quote
+ quote = "'''", interp = "$", allow_escapes = false;
+ } else if (match(&pos, "```")) { // Triple backtick
+ quote = "```", interp = "@", allow_escapes = false;
+ } else if (match(&pos, "\"")) { // Double quote
+ quote = "\"", interp = "$", allow_escapes = true;
+ } else if (match(&pos, "'")) { // Single quote
+ quote = "'", interp = "$", allow_escapes = true;
+ } else if (match(&pos, "`")) { // Backtick
+ quote = "`", interp = "@", allow_escapes = true;
+ } else {
+ parser_err(ctx, pos, pos, "I expected a valid text here");
+ }
+
ast_list_t *chunks = NULL;
Text_t chunk = EMPTY_TEXT;
const char *chunk_start = pos;
- int depth = 1;
bool leading_newline = false;
int64_t plain_span_len = 0;
#define FLUSH_PLAIN_SPAN() \
@@ -37,38 +53,30 @@ static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, ch
plain_span_len = 0; \
} \
} while (0)
- for (const char *end = ctx->file->text + ctx->file->len; pos < end && depth > 0;) {
+
+ for (const char *end = ctx->file->text + ctx->file->len; pos < end;) {
const char *after_indentation = pos;
- if (*pos == open_interp) { // Interpolation
+ const char *interp_start = pos;
+ if (interp != NULL && strncmp(pos, interp, strlen(interp)) == 0) { // Interpolation
FLUSH_PLAIN_SPAN();
- const char *interp_start = pos;
if (chunk.length > 0) {
ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .text = chunk);
chunks = new (ast_list_t, .ast = literal, .next = chunks);
chunk = EMPTY_TEXT;
}
- ++pos;
- ast_t *interp;
+ pos += strlen(interp);
if (*pos == ' ' || *pos == '\t')
parser_err(ctx, pos, pos + 1, "Whitespace is not allowed before an interpolation here");
- interp = expect(ctx, interp_start, &pos, parse_term_no_suffix, "I expected an interpolation term here");
- chunks = new (ast_list_t, .ast = interp, .next = chunks);
+ ast_t *value =
+ expect(ctx, interp_start, &pos, parse_term_no_suffix, "I expected an interpolation term here");
+ chunks = new (ast_list_t, .ast = value, .next = chunks);
chunk_start = pos;
} else if (allow_escapes && *pos == '\\') {
FLUSH_PLAIN_SPAN();
const char *c = unescape(ctx, &pos);
chunk = Texts(chunk, Text$from_str(c));
- } else if (!leading_newline && *pos == open_quote && closing[(int)open_quote]) { // Nested pair begin
- if (get_indent(ctx, pos) == starting_indent) {
- ++depth;
- }
- plain_span_len += 1;
- ++pos;
- } else if (!leading_newline && *pos == close_quote) { // Nested pair end
- if (get_indent(ctx, pos) == starting_indent) {
- --depth;
- if (depth == 0) break;
- }
+ } else if (!leading_newline && strncmp(pos, quote, strlen(quote)) == 0) { // Nested pair end
+ if (get_indent(ctx, pos) == starting_indent) break;
plain_span_len += 1;
++pos;
} else if (newline_with_indentation(&after_indentation, string_indent)) { // Newline
@@ -82,7 +90,7 @@ static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, ch
} else if (newline_with_indentation(&after_indentation, starting_indent)) { // Line continuation (..)
FLUSH_PLAIN_SPAN();
pos = after_indentation;
- if (*pos == close_quote) {
+ if (strncmp(pos, quote, strlen(quote)) == 0) {
break;
} else if (some_of(&pos, ".") >= 2) {
// Multi-line split
@@ -103,6 +111,8 @@ static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, ch
FLUSH_PLAIN_SPAN();
#undef FLUSH_PLAIN_SPAN
+ expect_closing(ctx, &pos, quote, "I was expecting a ", quote, " to finish this string");
+
if (chunk.length > 0) {
ast_t *literal = NewAST(ctx->file, chunk_start, pos, TextLiteral, .text = chunk);
chunks = new (ast_list_t, .ast = literal, .next = chunks);
@@ -110,8 +120,6 @@ static ast_list_t *_parse_text_helper(parse_ctx_t *ctx, const char **out_pos, ch
}
REVERSE_LIST(chunks);
- char close_str[2] = {close_quote, 0};
- expect_closing(ctx, &pos, close_str, "I was expecting a ", close_quote, " to finish this string");
*out_pos = pos;
return chunks;
}
@@ -122,36 +130,14 @@ ast_t *parse_text(parse_ctx_t *ctx, const char *pos) {
const char *start = pos;
const char *lang = NULL;
- char open_quote, close_quote, open_interp = '$';
- if (match(&pos, "\"")) { // Double quote
- open_quote = '"', close_quote = '"', open_interp = '$';
- } else if (match(&pos, "`")) { // Backtick
- open_quote = '`', close_quote = '`', open_interp = '$';
- } else if (match(&pos, "'")) { // Single quote
- open_quote = '\'', close_quote = '\'', open_interp = '$';
- } else if (match(&pos, "$")) { // Customized strings
+ if (match(&pos, "$")) {
lang = get_id(&pos);
- // $"..." or $@"...."
- static const char *interp_chars = "~!@#$%^&*+=\\?";
- if (match(&pos, "$")) { // Disable interpolation with $$
- open_interp = '\x03';
- } else if (strchr(interp_chars, *pos)) {
- open_interp = *pos;
- ++pos;
- }
- static const char *quote_chars = "\"'`|/;([{<";
- if (!strchr(quote_chars, *pos))
- parser_err(ctx, pos, pos + 1,
- "This is not a valid string quotation character. Valid characters are: \"'`|/;([{<");
- open_quote = *pos;
- ++pos;
- close_quote = closing[(int)open_quote] ? closing[(int)open_quote] : open_quote;
- } else {
- return NULL;
+ if (lang == NULL) parser_err(ctx, start, pos, "I expected a language name after the `$`");
}
- bool allow_escapes = (open_quote != '`');
- ast_list_t *chunks = _parse_text_helper(ctx, &pos, open_quote, close_quote, open_interp, allow_escapes);
+ if (!(*pos == '"' || *pos == '\'' || *pos == '`')) return NULL;
+
+ ast_list_t *chunks = _parse_text_helper(ctx, &pos);
bool colorize = match(&pos, "~") && match_word(&pos, "colorized");
return NewAST(ctx->file, start, pos, TextJoin, .lang = lang, .children = chunks, .colorize = colorize);
}
@@ -166,17 +152,15 @@ ast_t *parse_inline_c(parse_ctx_t *ctx, const char *pos) {
if (match(&pos, ":")) {
type = expect(ctx, start, &pos, parse_type, "I couldn't parse the type for this C_code code");
spaces(&pos);
- if (!match(&pos, "(")) parser_err(ctx, start, pos, "I expected a '(' here");
- chunks = new (ast_list_t, .ast = NewAST(ctx->file, pos, pos, TextLiteral, Text("({")),
- .next = _parse_text_helper(ctx, &pos, '(', ')', '@', false));
+ chunks = _parse_text_helper(ctx, &pos);
if (type) {
+ chunks = new (ast_list_t, .ast = NewAST(ctx->file, pos, pos, TextLiteral, Text("({")), .next = chunks);
REVERSE_LIST(chunks);
chunks = new (ast_list_t, .ast = NewAST(ctx->file, pos, pos, TextLiteral, Text("; })")), .next = chunks);
REVERSE_LIST(chunks);
}
} else {
- if (!match(&pos, "{")) parser_err(ctx, start, pos, "I expected a '{' here");
- chunks = _parse_text_helper(ctx, &pos, '{', '}', '@', false);
+ chunks = _parse_text_helper(ctx, &pos);
}
return NewAST(ctx->file, start, pos, InlineCCode, .chunks = chunks, .type_ast = type);
diff --git a/test/inline_c.tm b/test/inline_c.tm
index 77b56249..a9a7d6fc 100644
--- a/test/inline_c.tm
+++ b/test/inline_c.tm
@@ -1,8 +1,8 @@
func main()
- >> C_code:Int32(int x = 1 + 2; x)
+ >> C_code:Int32`int x = 1 + 2; x`
= Int32(3)
- >> C_code {
+ >> C_code `
say(Text("Inline C code works!"), true);
- }
+ `
diff --git a/test/text.tm b/test/text.tm
index ff55555d..02f24de7 100644
--- a/test/text.tm
+++ b/test/text.tm
@@ -104,17 +104,10 @@ func main()
= "A 3"
>> "A \$(1+2)"
= "A \$(1+2)"
- >> `A $(1+2)`
+ >> 'A $(1+2)'
= "A 3"
-
- >> $"A $(1+2)"
- = "A 3"
- >> $$"A $(1+2)"
- = "A \$(1+2)"
- >> $="A =(1+2)"
+ >> `A @(1+2)`
= "A 3"
- >> ${one {nested} two $(1+2)}
- = "one {nested} two 3"
c := "É̩"
>> c.codepoint_names()