refactor(lang): rename the str type (and stringify builtin) to string

Expand the abbreviated string type and its conversion builtin to the full
word everywhere:
  str            ->  string        (the immutable-string type)
  str(x) -> str  ->  string(x) -> string   (the stringify builtin;
                                            what `{…}` interpolation calls)

Types are recognized by identifier, and llty maps both spellings to LLVM
`ptr`, so this is an atomic source rewrite: type annotations, the Ludic
type tags, the builtin name/dispatch, and the interpolation desugar, plus
the grammars, LSP, docs (type-str -> type-string, fn-str -> fn-string), and
inventory. int/bool stay (universally accepted, like Math).

Reseeded; C-free fixpoint holds; all suites green (45/24/29); site + check.py OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-08-30 01:51:11 +03:00
parent 4c48077d68
commit b7745a4600
70 changed files with 207 additions and 207 deletions

View file

@ -19,13 +19,13 @@ var loc_ty: []ptr
var loc_mut: []int # 1 = mutable (var / param / loop-var), 0 = immutable (let)
var nloc: int = 0
var g_uses_str: bool = false # a `str + str` / `str == str` was emitted -> emit the prelude
var g_uses_intstr: bool = false # `str(int)` was emitted -> emit the int->string prelude
var g_uses_intstr: bool = false # `string(int)` was emitted -> emit the int->string prelude
var g_uses_strslice: bool = false # `s[a..b]` was emitted -> emit the substring prelude
var g_uses_mathrt: bool = false # Math.sqrt/sin/cos/tan was emitted -> emit the math runtime prelude
var g_uses_textrt: bool = false # Text.upper/lower/trim/repeat/pad was emitted -> emit the text builders
var g_uses_textrt2: bool = false # Text.split/join/replace was emitted -> emit the string/slice builders
var g_uses_hashrt: bool = false # Hash.of/fnv1a/crc32 was emitted -> emit the byte-stream hashers
var g_uses_longstr: bool = false # str(long) / interpolating a long was emitted -> emit fn_long_str
var g_uses_longstr: bool = false # string(long) / interpolating a long was emitted -> emit fn_long_str
# loop targets for break/continue (innermost last)
var brk_lbl: []ptr

View file

@ -97,8 +97,8 @@ function emit_program() -> void {
} }
if g_uses_loopback { emit_loopback() } # built-in transport, after all net_send/net_poll uses are seen
if g_uses_str { emit_str_prelude() } # @fn_str_eq / @fn_str_concat, after all uses are seen
if g_uses_intstr { emit_int_str() } # @fn_int_str, for str(int) in interpolation
if g_uses_longstr { emit_long_str() } # @fn_long_str, for str(long) / long interpolation
if g_uses_intstr { emit_int_str() } # @fn_int_str, for string(int) in interpolation
if g_uses_longstr { emit_long_str() } # @fn_long_str, for string(long) / long interpolation
if g_uses_strslice { emit_str_slice() } # @fn_str_slice, for s[a..b]
if g_uses_mathrt { emit_math_prelude() } # @fn_fx_sqrt / @fn_fx_sin + the sine table
if g_uses_textrt { emit_text_prelude() } # @fn_str_upper/lower/trim/repeat/pad builders

View file

@ -79,7 +79,7 @@ function to_long(v: Val) -> ptr {
function emit_str_op(op: ptr, a: Val, b: Val) -> Val {
g_uses_str = true
if (op == ("+")) {
return val(emit_bind(`call ptr @fn_str_concat(ptr {a.code}, ptr {b.code})`), "str")
return val(emit_bind(`call ptr @fn_str_concat(ptr {a.code}, ptr {b.code})`), "string")
}
let r = emit_bind(`call i32 @fn_str_eq(ptr {a.code}, ptr {b.code})`)
if (op == ("!=")) {
@ -411,12 +411,12 @@ function emit_call(e: Node) -> Val {
}
if (name == "len") { return emit_len(e) }
if (name == "push") { return emit_push(e) }
if (name == "str") { # str(x): int/bool/fixed/long -> text, a string passes through
if (name == "string") { # string(x): int/bool/fixed/long -> text, a string passes through
let a = emit_expr(e.kids[0])
if (llty(a.ty) == "ptr") { return a }
if (llty(a.ty) == "i64") { g_uses_longstr = true; return val(emit_bind(`call ptr @fn_long_str(i64 {a.code})`), "str") }
if (llty(a.ty) == "i64") { g_uses_longstr = true; return val(emit_bind(`call ptr @fn_long_str(i64 {a.code})`), "string") }
g_uses_intstr = true
return val(emit_bind(`call ptr @fn_int_str(i32 {a.code})`), "str")
return val(emit_bind(`call ptr @fn_int_str(i32 {a.code})`), "string")
}
if (name == "print") { # print(x): a value + newline (string, long, or int)
let a = emit_expr(e.kids[0])
@ -536,9 +536,9 @@ function emit_expr(e: Node) -> Val {
let lo = emit_expr(e.b)
let hi = emit_expr(e.c)
g_uses_strslice = true
return val(emit_bind(`call ptr @fn_str_slice(ptr {base.code}, i32 {lo.code}, i32 {hi.code})`), "str")
return val(emit_bind(`call ptr @fn_str_slice(ptr {base.code}, i32 {lo.code}, i32 {hi.code})`), "string")
}
if e.kind == E_STR { return val(emit_str_const(e.s), "str") }
if e.kind == E_STR { return val(emit_str_const(e.s), "string") }
if e.kind == E_NEW {
if is_slice_ty(e.s) { return emit_new_slice(e.s) }
return emit_new_struct(e.s)

View file

@ -170,7 +170,7 @@ function emit_str_prelude() -> void {
emith("fin:\n %pe = getelementptr inbounds i8, ptr %out, i32 %sum\n store i8 0, ptr %pe\n ret ptr %out\n}\n")
}
# int -> decimal string, emitted (once) into any program that uses str(int)
# int -> decimal string, emitted (once) into any program that uses string(int)
# (string interpolation of a number). Writes digits from the end of a 24-byte
# buffer, prepends '-' for negatives, and returns a pointer into the buffer.
function emit_int_str() -> void {

View file

@ -62,7 +62,7 @@ function emit_intrinsic(name: ptr, e: Node) -> Val {
let i = arg_code(e, 0)
let v = emit_bind("load ptr, ptr @L_argv")
let q = emit_bind(`getelementptr ptr, ptr {v}, i32 {i}`)
return val(emit_bind(`load ptr, ptr {q}`), "str")
return val(emit_bind(`load ptr, ptr {q}`), "string")
}
if (name == "exit") {
let n = arg_code(e, 0)
@ -79,7 +79,7 @@ function emit_intrinsic(name: ptr, e: Node) -> Val {
}
if (name == "getenv") {
let n = arg_code(e, 0)
return val(emit_bind(`call ptr @getenv(ptr {n})`), "str")
return val(emit_bind(`call ptr @getenv(ptr {n})`), "string")
}
# bitwise ops are the operators & | ^ << >> ~ now (see emit_bin / p_mul).
# peek32 / poke32 are `words` indexing now: w[i] and w[i] = v (see emit_index_addr).

View file

@ -34,7 +34,7 @@ function emit_intrinsic2(name: ptr, e: Node) -> Val {
if (name == "as_fixed") { let a = emit_expr(e.kids[0]); return val(a.code, "fixed") }
if (name == "as_int") { let a = emit_expr(e.kids[0]); return val(a.code, "int") }
if (name == "is_windowed") { if g_windowed { return val("1", "bool") }; return val("0", "bool") }
if (name == "game_title") { return val("@.gametitle", "str") }
if (name == "game_title") { return val("@.gametitle", "string") }
# windowing hooks — declared external; only reached on the is_windowed() branch
if (name == "win_poll") { return val(emit_bind("call i32 @win_poll()"), "int") }
if (name == "win_running") { return val(emit_bind("call i32 @win_running()"), "bool") }

View file

@ -1,7 +1,7 @@
# emit_text.ludic — the Text.* namespace over `str` (null-terminated byte
# strings). The libc-backed queries (length/char_at/starts_with/ends_with/
# contains/index_of/to_int) allocate nothing; slice/from_int/equals/concat reuse
# the string preludes that the `+`, `s[a..b]` and str(int) operators emit.
# the string preludes that the `+`, `s[a..b]` and string(int) operators emit.
function is_text_ns(meth: ptr) -> bool {
if (meth == "length") or (meth == "char_at") or (meth == "slice") { return true }
@ -15,15 +15,15 @@ function is_text_ns(meth: ptr) -> bool {
}
function emit_text_ns(meth: ptr, e: Node) -> Val {
if (meth == "from_int") { # int -> str, same as str(n)
if (meth == "from_int") { # int -> string, same as string(n)
let n = emit_expr(e.kids[0])
g_uses_intstr = true
return val(emit_bind(`call ptr @fn_int_str(i32 {n.code})`), "str")
return val(emit_bind(`call ptr @fn_int_str(i32 {n.code})`), "string")
}
if (meth == "slice") { # s[a..b], same substring helper
let s0 = emit_expr(e.kids[0]); let a = emit_expr(e.kids[1]); let b = emit_expr(e.kids[2])
g_uses_strslice = true
return val(emit_bind(`call ptr @fn_str_slice(ptr {s0.code}, i32 {a.code}, i32 {b.code})`), "str")
return val(emit_bind(`call ptr @fn_str_slice(ptr {s0.code}, i32 {a.code}, i32 {b.code})`), "string")
}
if (meth == "equals") { # byte-wise equality, same as ==
let a = emit_expr(e.kids[0]); let b = emit_expr(e.kids[1])
@ -33,7 +33,7 @@ function emit_text_ns(meth: ptr, e: Node) -> Val {
if (meth == "concat") { # a + b, same as the + operator
let a = emit_expr(e.kids[0]); let b = emit_expr(e.kids[1])
g_uses_str = true
return val(emit_bind(`call ptr @fn_str_concat(ptr {a.code}, ptr {b.code})`), "str")
return val(emit_bind(`call ptr @fn_str_concat(ptr {a.code}, ptr {b.code})`), "string")
}
let s = emit_expr(e.kids[0])
@ -52,45 +52,45 @@ function emit_text_ns(meth: ptr, e: Node) -> Val {
}
if (meth == "upper") { # ASCII a-z -> A-Z, fresh string
g_uses_textrt = true
return val(emit_bind(`call ptr @fn_str_upper(ptr {s.code})`), "str")
return val(emit_bind(`call ptr @fn_str_upper(ptr {s.code})`), "string")
}
if (meth == "lower") { # ASCII A-Z -> a-z, fresh string
g_uses_textrt = true
return val(emit_bind(`call ptr @fn_str_lower(ptr {s.code})`), "str")
return val(emit_bind(`call ptr @fn_str_lower(ptr {s.code})`), "string")
}
if (meth == "trim") { # drop leading/trailing whitespace
g_uses_textrt = true
return val(emit_bind(`call ptr @fn_str_trim(ptr {s.code})`), "str")
return val(emit_bind(`call ptr @fn_str_trim(ptr {s.code})`), "string")
}
if (meth == "repeat") { # s repeated n times
g_uses_textrt = true
let n = emit_expr(e.kids[1])
return val(emit_bind(`call ptr @fn_str_repeat(ptr {s.code}, i32 {n.code})`), "str")
return val(emit_bind(`call ptr @fn_str_repeat(ptr {s.code}, i32 {n.code})`), "string")
}
if (meth == "pad_left") { # pad with spaces to width, on the left
g_uses_textrt = true
let w = emit_expr(e.kids[1])
return val(emit_bind(`call ptr @fn_str_pad(ptr {s.code}, i32 {w.code}, i1 1)`), "str")
return val(emit_bind(`call ptr @fn_str_pad(ptr {s.code}, i32 {w.code}, i1 1)`), "string")
}
if (meth == "pad_right") { # pad with spaces to width, on the right
g_uses_textrt = true
let w = emit_expr(e.kids[1])
return val(emit_bind(`call ptr @fn_str_pad(ptr {s.code}, i32 {w.code}, i1 0)`), "str")
return val(emit_bind(`call ptr @fn_str_pad(ptr {s.code}, i32 {w.code}, i1 0)`), "string")
}
if (meth == "replace") { # replace every `from` with `to`
g_uses_textrt2 = true
let from = emit_expr(e.kids[1]); let to = emit_expr(e.kids[2])
return val(emit_bind(`call ptr @fn_str_replace(ptr {s.code}, ptr {from.code}, ptr {to.code})`), "str")
return val(emit_bind(`call ptr @fn_str_replace(ptr {s.code}, ptr {from.code}, ptr {to.code})`), "string")
}
if (meth == "split") { # split on a separator -> []str
if (meth == "split") { # split on a separator -> []string
g_uses_textrt2 = true
let sep = emit_expr(e.kids[1])
return val(emit_bind(`call ptr @fn_str_split(ptr {s.code}, ptr {sep.code})`), "[]str")
return val(emit_bind(`call ptr @fn_str_split(ptr {s.code}, ptr {sep.code})`), "[]string")
}
if (meth == "join") { # join a []str with a separator (s is the slice)
if (meth == "join") { # join a []string with a separator (s is the slice)
g_uses_textrt2 = true
let sep = emit_expr(e.kids[1])
return val(emit_bind(`call ptr @fn_str_join(ptr {s.code}, ptr {sep.code})`), "str")
return val(emit_bind(`call ptr @fn_str_join(ptr {s.code}, ptr {sep.code})`), "string")
}
if (meth == "contains") or (meth == "index_of") { # substring search
let sub = emit_expr(e.kids[1])
@ -340,7 +340,7 @@ function emit_text_prelude() -> void {
}
# emit_text2_prelude — the allocating Text ops that build strings/slices:
# replace, join (over a []str), split (returns a []str). Emitted once per
# replace, join (over a []string), split (returns a []string). Emitted once per
# program that uses them (g_uses_textrt2). Slices are the {data,len,cap}
# %LSlice with str (ptr) elements.
function emit_text2_prelude() -> void {

View file

@ -1,7 +1,7 @@
# io.ludic — reading the input file and writing the output, plus tiny stdio.
# The compiler reads one .ludic file whole and emits LLVM IR text to stdout.
function read_file(path: str) -> ptr {
function read_file(path: string) -> ptr {
let f = file_open(path, "rb")
if (f == null) { return null }
file_seek(f, 0, 2)

View file

@ -111,7 +111,7 @@ declare void @win_close()
@.str10 = private unnamed_addr constant [2 x i8] c",\00"
@.str11 = private unnamed_addr constant [2 x i8] c")\00"
@.str12 = private unnamed_addr constant [2 x i8] c"+\00"
@.str13 = private unnamed_addr constant [4 x i8] c"str\00"
@.str13 = private unnamed_addr constant [7 x i8] c"string\00"
@.str14 = private unnamed_addr constant [2 x i8] c"(\00"
@.str15 = private unnamed_addr constant [2 x i8] c")\00"
@.str16 = private unnamed_addr constant [2 x i8] c":\00"
@ -700,7 +700,7 @@ declare void @win_close()
@.str599 = private unnamed_addr constant [24 x i8] c"getelementptr ptr, ptr \00"
@.str600 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str601 = private unnamed_addr constant [15 x i8] c"load ptr, ptr \00"
@.str602 = private unnamed_addr constant [4 x i8] c"str\00"
@.str602 = private unnamed_addr constant [7 x i8] c"string\00"
@.str603 = private unnamed_addr constant [5 x i8] c"exit\00"
@.str604 = private unnamed_addr constant [23 x i8] c" call void @exit(i32 \00"
@.str605 = private unnamed_addr constant [3 x i8] c")\0A\00"
@ -720,7 +720,7 @@ declare void @win_close()
@.str619 = private unnamed_addr constant [7 x i8] c"getenv\00"
@.str620 = private unnamed_addr constant [22 x i8] c"call ptr @getenv(ptr \00"
@.str621 = private unnamed_addr constant [2 x i8] c")\00"
@.str622 = private unnamed_addr constant [4 x i8] c"str\00"
@.str622 = private unnamed_addr constant [7 x i8] c"string\00"
@.str623 = private unnamed_addr constant [2 x i8] c"0\00"
@.str624 = private unnamed_addr constant [5 x i8] c"void\00"
@.str625 = private unnamed_addr constant [5 x i8] c"free\00"
@ -770,7 +770,7 @@ declare void @win_close()
@.str669 = private unnamed_addr constant [5 x i8] c"bool\00"
@.str670 = private unnamed_addr constant [11 x i8] c"game_title\00"
@.str671 = private unnamed_addr constant [12 x i8] c"@.gametitle\00"
@.str672 = private unnamed_addr constant [4 x i8] c"str\00"
@.str672 = private unnamed_addr constant [7 x i8] c"string\00"
@.str673 = private unnamed_addr constant [9 x i8] c"win_poll\00"
@.str674 = private unnamed_addr constant [21 x i8] c"call i32 @win_poll()\00"
@.str675 = private unnamed_addr constant [4 x i8] c"int\00"
@ -1236,13 +1236,13 @@ declare void @win_close()
@.str1135 = private unnamed_addr constant [9 x i8] c"from_int\00"
@.str1136 = private unnamed_addr constant [26 x i8] c"call ptr @fn_int_str(i32 \00"
@.str1137 = private unnamed_addr constant [2 x i8] c")\00"
@.str1138 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1138 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1139 = private unnamed_addr constant [6 x i8] c"slice\00"
@.str1140 = private unnamed_addr constant [28 x i8] c"call ptr @fn_str_slice(ptr \00"
@.str1141 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str1142 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str1143 = private unnamed_addr constant [2 x i8] c")\00"
@.str1144 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1144 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1145 = private unnamed_addr constant [7 x i8] c"equals\00"
@.str1146 = private unnamed_addr constant [25 x i8] c"call i32 @fn_str_eq(ptr \00"
@.str1147 = private unnamed_addr constant [7 x i8] c", ptr \00"
@ -1252,7 +1252,7 @@ declare void @win_close()
@.str1151 = private unnamed_addr constant [29 x i8] c"call ptr @fn_str_concat(ptr \00"
@.str1152 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str1153 = private unnamed_addr constant [2 x i8] c")\00"
@.str1154 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1154 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1155 = private unnamed_addr constant [7 x i8] c"length\00"
@.str1156 = private unnamed_addr constant [22 x i8] c"call i64 @strlen(ptr \00"
@.str1157 = private unnamed_addr constant [2 x i8] c")\00"
@ -1273,46 +1273,46 @@ declare void @win_close()
@.str1172 = private unnamed_addr constant [6 x i8] c"upper\00"
@.str1173 = private unnamed_addr constant [28 x i8] c"call ptr @fn_str_upper(ptr \00"
@.str1174 = private unnamed_addr constant [2 x i8] c")\00"
@.str1175 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1175 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1176 = private unnamed_addr constant [6 x i8] c"lower\00"
@.str1177 = private unnamed_addr constant [28 x i8] c"call ptr @fn_str_lower(ptr \00"
@.str1178 = private unnamed_addr constant [2 x i8] c")\00"
@.str1179 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1179 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1180 = private unnamed_addr constant [5 x i8] c"trim\00"
@.str1181 = private unnamed_addr constant [27 x i8] c"call ptr @fn_str_trim(ptr \00"
@.str1182 = private unnamed_addr constant [2 x i8] c")\00"
@.str1183 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1183 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1184 = private unnamed_addr constant [7 x i8] c"repeat\00"
@.str1185 = private unnamed_addr constant [29 x i8] c"call ptr @fn_str_repeat(ptr \00"
@.str1186 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str1187 = private unnamed_addr constant [2 x i8] c")\00"
@.str1188 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1188 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1189 = private unnamed_addr constant [9 x i8] c"pad_left\00"
@.str1190 = private unnamed_addr constant [26 x i8] c"call ptr @fn_str_pad(ptr \00"
@.str1191 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str1192 = private unnamed_addr constant [8 x i8] c", i1 1)\00"
@.str1193 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1193 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1194 = private unnamed_addr constant [10 x i8] c"pad_right\00"
@.str1195 = private unnamed_addr constant [26 x i8] c"call ptr @fn_str_pad(ptr \00"
@.str1196 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str1197 = private unnamed_addr constant [8 x i8] c", i1 0)\00"
@.str1198 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1198 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1199 = private unnamed_addr constant [8 x i8] c"replace\00"
@.str1200 = private unnamed_addr constant [30 x i8] c"call ptr @fn_str_replace(ptr \00"
@.str1201 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str1202 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str1203 = private unnamed_addr constant [2 x i8] c")\00"
@.str1204 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1204 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1205 = private unnamed_addr constant [6 x i8] c"split\00"
@.str1206 = private unnamed_addr constant [28 x i8] c"call ptr @fn_str_split(ptr \00"
@.str1207 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str1208 = private unnamed_addr constant [2 x i8] c")\00"
@.str1209 = private unnamed_addr constant [6 x i8] c"[]str\00"
@.str1209 = private unnamed_addr constant [9 x i8] c"[]string\00"
@.str1210 = private unnamed_addr constant [5 x i8] c"join\00"
@.str1211 = private unnamed_addr constant [27 x i8] c"call ptr @fn_str_join(ptr \00"
@.str1212 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str1213 = private unnamed_addr constant [2 x i8] c")\00"
@.str1214 = private unnamed_addr constant [4 x i8] c"str\00"
@.str1214 = private unnamed_addr constant [7 x i8] c"string\00"
@.str1215 = private unnamed_addr constant [9 x i8] c"contains\00"
@.str1216 = private unnamed_addr constant [9 x i8] c"index_of\00"
@.str1217 = private unnamed_addr constant [22 x i8] c"call ptr @strstr(ptr \00"
@ -3148,7 +3148,7 @@ declare void @win_close()
@.str3047 = private unnamed_addr constant [29 x i8] c"call ptr @fn_str_concat(ptr \00"
@.str3048 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str3049 = private unnamed_addr constant [2 x i8] c")\00"
@.str3050 = private unnamed_addr constant [4 x i8] c"str\00"
@.str3050 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3051 = private unnamed_addr constant [25 x i8] c"call i32 @fn_str_eq(ptr \00"
@.str3052 = private unnamed_addr constant [7 x i8] c", ptr \00"
@.str3053 = private unnamed_addr constant [2 x i8] c")\00"
@ -3568,15 +3568,15 @@ declare void @win_close()
@.str3467 = private unnamed_addr constant [4 x i8] c"int\00"
@.str3468 = private unnamed_addr constant [4 x i8] c"len\00"
@.str3469 = private unnamed_addr constant [5 x i8] c"push\00"
@.str3470 = private unnamed_addr constant [4 x i8] c"str\00"
@.str3470 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3471 = private unnamed_addr constant [4 x i8] c"ptr\00"
@.str3472 = private unnamed_addr constant [4 x i8] c"i64\00"
@.str3473 = private unnamed_addr constant [27 x i8] c"call ptr @fn_long_str(i64 \00"
@.str3474 = private unnamed_addr constant [2 x i8] c")\00"
@.str3475 = private unnamed_addr constant [4 x i8] c"str\00"
@.str3475 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3476 = private unnamed_addr constant [26 x i8] c"call ptr @fn_int_str(i32 \00"
@.str3477 = private unnamed_addr constant [2 x i8] c")\00"
@.str3478 = private unnamed_addr constant [4 x i8] c"str\00"
@.str3478 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3479 = private unnamed_addr constant [6 x i8] c"print\00"
@.str3480 = private unnamed_addr constant [4 x i8] c"ptr\00"
@.str3481 = private unnamed_addr constant [51 x i8] c" call i32 (ptr, ...) @printf(ptr @.fmt_line, ptr \00"
@ -3712,8 +3712,8 @@ declare void @win_close()
@.str3611 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str3612 = private unnamed_addr constant [7 x i8] c", i32 \00"
@.str3613 = private unnamed_addr constant [2 x i8] c")\00"
@.str3614 = private unnamed_addr constant [4 x i8] c"str\00"
@.str3615 = private unnamed_addr constant [4 x i8] c"str\00"
@.str3614 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3615 = private unnamed_addr constant [7 x i8] c"string\00"
@.str3616 = private unnamed_addr constant [4 x i8] c"int\00"
@.str3617 = private unnamed_addr constant [6 x i8] c"load \00"
@.str3618 = private unnamed_addr constant [10 x i8] c", ptr @g_\00"

View file

@ -68,15 +68,15 @@ function args_call(call: Node) -> void {
}
# ---- string interpolation --------------------------------------------------
# `text {expr} text` desugars to a `+` chain of string literals and `str(expr)`
# `text {expr} text` desugars to a `+` chain of string literals and `string(expr)`
# holes, so it reuses the string-concat operator and needs no new runtime.
function interp_lit(buf: ptr, len: int) -> Node { let n = node(E_STR); n.s = buf[0..0 + len]; return n }
function interp_add(acc: Node, part: Node) -> Node {
if acc == null { return part }
return mkbin("+", acc, part)
}
function interp_str(e: Node) -> Node { # wrap a hole in str(...)
let c = node(E_CALL); let id = node(E_ID); id.s = "str"; c.a = id; push(c.kids, e); return c
function interp_str(e: Node) -> Node { # wrap a hole in string(...)
let c = node(E_CALL); let id = node(E_ID); id.s = "string"; c.a = id; push(c.kids, e); return c
}
function parse_hole(inner: ptr) -> Node { # re-lex+parse an embedded expression
let saved_toks = toks; let saved_pi = pi

View file

@ -18,6 +18,6 @@ program T {
print(x == x) # 1
print(0 - sq) # -1000000000000 (unary negate stays 64-bit)
print(big) # 1000000
print(Text.length(str(sq))) # 13 — str(long) renders all 13 digits
print(Text.length(string(sq))) # 13 — string(long) renders all 13 digits
}
}