| 1 | // Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license that can be found in the LICENSE file. |
| 3 | module js |
| 4 | |
| 5 | import v.ast |
| 6 | import v.util |
| 7 | import strings |
| 8 | |
| 9 | struct StrType { |
| 10 | styp string |
| 11 | mut: |
| 12 | typ ast.Type |
| 13 | } |
| 14 | |
| 15 | fn (mut g JsGen) ensure_autostr_helpers() { |
| 16 | if g.generated_autostr_helpers { |
| 17 | return |
| 18 | } |
| 19 | g.generated_autostr_helpers = true |
| 20 | g.definitions.writeln('const builtin__autostr_type_stack_max_depth = 64;') |
| 21 | g.definitions.writeln('let builtin__g_autostr_type_stack = Array(builtin__autostr_type_stack_max_depth).fill(0);') |
| 22 | g.definitions.writeln('let builtin__g_autostr_type_stack_len = 0;') |
| 23 | g.definitions.writeln('function builtin__autostr_type_in_stack(typ) {') |
| 24 | g.definitions.writeln('\tfor (let i = 0; i < builtin__g_autostr_type_stack_len; ++i) {') |
| 25 | g.definitions.writeln('\t\tif (builtin__g_autostr_type_stack[i] === typ) return true;') |
| 26 | g.definitions.writeln('\t}') |
| 27 | g.definitions.writeln('\treturn false;') |
| 28 | g.definitions.writeln('}') |
| 29 | g.definitions.writeln('function builtin__autostr_type_push(typ) {') |
| 30 | g.definitions.writeln('\tif (builtin__g_autostr_type_stack_len >= builtin__autostr_type_stack_max_depth) return;') |
| 31 | g.definitions.writeln('\tbuiltin__g_autostr_type_stack[builtin__g_autostr_type_stack_len++] = typ;') |
| 32 | g.definitions.writeln('}') |
| 33 | g.definitions.writeln('function builtin__autostr_type_pop() {') |
| 34 | g.definitions.writeln('\tif (builtin__g_autostr_type_stack_len > 0) builtin__g_autostr_type_stack_len--;') |
| 35 | g.definitions.writeln('}') |
| 36 | } |
| 37 | |
| 38 | fn (mut g JsGen) get_str_fn(typ ast.Type) string { |
| 39 | mut unwrapped := g.unwrap_generic(typ).set_nr_muls(0).clear_flag(.variadic) |
| 40 | if g.pref.nofloat { |
| 41 | if typ == ast.f32_type { |
| 42 | unwrapped = ast.u32_type |
| 43 | } else if typ == ast.f64_type { |
| 44 | unwrapped = ast.u64_type |
| 45 | } |
| 46 | } |
| 47 | |
| 48 | if typ.has_flag(.option) { |
| 49 | unwrapped.set_flag(.option) |
| 50 | } |
| 51 | styp := g.styp(unwrapped) |
| 52 | mut sym := g.table.sym(unwrapped) |
| 53 | mut str_fn_name := styp_to_str_fn_name(styp) |
| 54 | if mut sym.info is ast.Alias { |
| 55 | if sym.info.is_import { |
| 56 | sym = g.table.sym(sym.info.parent_type) |
| 57 | str_fn_name = styp_to_str_fn_name(sym.name) |
| 58 | } |
| 59 | } |
| 60 | g.str_types << StrType{ |
| 61 | typ: unwrapped |
| 62 | styp: styp |
| 63 | } |
| 64 | return str_fn_name |
| 65 | } |
| 66 | |
| 67 | fn (mut g JsGen) final_gen_str(typ StrType) { |
| 68 | if typ in g.generated_str_fns { |
| 69 | return |
| 70 | } |
| 71 | g.generated_str_fns << typ |
| 72 | sym := g.table.sym(typ.typ) |
| 73 | if sym.has_method('str') && !typ.typ.has_flag(.option) { |
| 74 | return |
| 75 | } |
| 76 | styp := typ.styp |
| 77 | if styp == 'any' { |
| 78 | return |
| 79 | } |
| 80 | str_fn_name := styp_to_str_fn_name(styp) |
| 81 | if typ.typ.has_flag(.option) { |
| 82 | g.gen_str_for_option(typ.typ, styp, str_fn_name) |
| 83 | return |
| 84 | } |
| 85 | match sym.info { |
| 86 | ast.Alias { |
| 87 | if sym.info.is_import { |
| 88 | g.gen_str_default(sym, styp, str_fn_name) |
| 89 | } else { |
| 90 | g.gen_str_for_alias(sym.info, styp, str_fn_name) |
| 91 | } |
| 92 | } |
| 93 | ast.Array { |
| 94 | g.gen_str_for_array(sym.info, styp, str_fn_name) |
| 95 | } |
| 96 | ast.ArrayFixed { |
| 97 | g.gen_str_for_array_fixed(sym.info, styp, str_fn_name) |
| 98 | } |
| 99 | ast.Enum { |
| 100 | g.gen_str_for_enum(sym.info, styp, str_fn_name) |
| 101 | } |
| 102 | ast.FnType { |
| 103 | g.gen_str_for_fn_type(sym.info, styp, str_fn_name) |
| 104 | } |
| 105 | ast.Struct { |
| 106 | g.gen_str_for_struct(sym.info, styp, str_fn_name, sym.idx) |
| 107 | } |
| 108 | ast.Map { |
| 109 | g.gen_str_for_map(sym.info, styp, str_fn_name) |
| 110 | } |
| 111 | ast.MultiReturn { |
| 112 | g.gen_str_for_multi_return(sym.info, styp, str_fn_name) |
| 113 | } |
| 114 | ast.SumType { |
| 115 | g.gen_str_for_union_sum_type(sym.info, styp, str_fn_name) |
| 116 | } |
| 117 | ast.Interface { |
| 118 | g.gen_str_for_interface(sym.info, styp, str_fn_name) |
| 119 | } |
| 120 | ast.Chan { |
| 121 | g.gen_str_for_chan(sym.info, styp, str_fn_name) |
| 122 | } |
| 123 | ast.Thread { |
| 124 | g.gen_str_for_thread(sym.info, styp, str_fn_name) |
| 125 | } |
| 126 | else { |
| 127 | verror("could not generate string method ${str_fn_name} for type '${styp}'") |
| 128 | } |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | pub enum StrIntpType { |
| 133 | si_no_str = 0 // no parameter to print only fix string |
| 134 | si_c |
| 135 | si_u8 |
| 136 | si_i8 |
| 137 | si_u16 |
| 138 | si_i16 |
| 139 | si_u32 |
| 140 | si_i32 |
| 141 | si_u64 |
| 142 | si_i64 |
| 143 | si_e32 |
| 144 | si_e64 |
| 145 | si_f32 |
| 146 | si_f64 |
| 147 | si_g32 |
| 148 | si_g64 |
| 149 | si_s |
| 150 | si_p |
| 151 | si_r |
| 152 | si_vp |
| 153 | } |
| 154 | |
| 155 | pub fn type_to_str(x StrIntpType) string { |
| 156 | match x { |
| 157 | .si_no_str { return 'no_str' } |
| 158 | .si_c { return 'c' } |
| 159 | .si_u8 { return 'u8' } |
| 160 | .si_i8 { return 'i8' } |
| 161 | .si_u16 { return 'u16' } |
| 162 | .si_i16 { return 'i16' } |
| 163 | .si_u32 { return 'u32' } |
| 164 | .si_i32 { return 'i32' } |
| 165 | .si_u64 { return 'u64' } |
| 166 | .si_i64 { return 'i64' } |
| 167 | .si_f32 { return 'f32' } |
| 168 | .si_f64 { return 'f64' } |
| 169 | .si_g32 { return 'f32' } // g32 format use f32 data |
| 170 | .si_g64 { return 'f64' } // g64 format use f64 data |
| 171 | .si_e32 { return 'f32' } // e32 format use f32 data |
| 172 | .si_e64 { return 'f64' } // e64 format use f64 data |
| 173 | .si_s { return 's' } |
| 174 | .si_p { return 'p' } |
| 175 | .si_r { return 'r' } // repeat string |
| 176 | .si_vp { return 'vp' } |
| 177 | } |
| 178 | } |
| 179 | |
| 180 | pub fn data_str(x StrIntpType) string { |
| 181 | match x { |
| 182 | .si_no_str { return 'no_str' } |
| 183 | .si_c { return 'd_c' } |
| 184 | .si_u8 { return 'd_u8' } |
| 185 | .si_i8 { return 'd_i8' } |
| 186 | .si_u16 { return 'd_u16' } |
| 187 | .si_i16 { return 'd_i16' } |
| 188 | .si_u32 { return 'd_u32' } |
| 189 | .si_i32 { return 'd_i32' } |
| 190 | .si_u64 { return 'd_u64' } |
| 191 | .si_i64 { return 'd_i64' } |
| 192 | .si_f32 { return 'd_f32' } |
| 193 | .si_f64 { return 'd_f64' } |
| 194 | .si_g32 { return 'd_f32' } // g32 format use f32 data |
| 195 | .si_g64 { return 'd_f64' } // g64 format use f64 data |
| 196 | .si_e32 { return 'd_f32' } // e32 format use f32 data |
| 197 | .si_e64 { return 'd_f64' } // e64 format use f64 data |
| 198 | .si_s { return 'd_s' } |
| 199 | .si_p { return 'd_p' } |
| 200 | .si_r { return 'd_r' } // repeat string |
| 201 | .si_vp { return 'd_vp' } |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | // BUG: this const is not released from the memory! use a const for now |
| 206 | // si_s_code = "0x" + int(StrIntpType.si_s).hex() // code for a simple string |
| 207 | const si_s_code = '0xfe10' |
| 208 | |
| 209 | fn should_use_indent_func(kind ast.Kind) bool { |
| 210 | return kind in [.struct, .alias, .array, .array_fixed, .map, .sum_type, .interface] |
| 211 | } |
| 212 | |
| 213 | fn (mut g JsGen) gen_str_default(sym ast.TypeSymbol, styp string, str_fn_name string) { |
| 214 | mut convertor := '' |
| 215 | mut typename_ := '' |
| 216 | if sym.parent_idx in ast.integer_type_idxs { |
| 217 | convertor = 'int' |
| 218 | typename_ = 'int' |
| 219 | } else if sym.parent_idx == ast.f32_type_idx { |
| 220 | convertor = 'float' |
| 221 | typename_ = 'f32' |
| 222 | } else if sym.parent_idx == ast.f64_type_idx { |
| 223 | convertor = 'double' |
| 224 | typename_ = 'f64' |
| 225 | } else if sym.parent_idx == ast.bool_type_idx { |
| 226 | convertor = 'bool' |
| 227 | typename_ = 'bool' |
| 228 | } else { |
| 229 | panic("could not generate string method for type '${styp}'") |
| 230 | } |
| 231 | |
| 232 | g.definitions.writeln('function ${str_fn_name}(it) {') |
| 233 | if convertor == 'bool' { |
| 234 | g.definitions.writeln('\tlet tmp1 = string__plus(new string("${styp}("), it.valueOf()? new string("true") : new string("false"));') |
| 235 | } else { |
| 236 | g.definitions.writeln('\tlet tmp1 = string__plus(new string("${styp}("), new string(${typename_}_str((${convertor})it).str));') |
| 237 | } |
| 238 | g.definitions.writeln('\tstring tmp2 = string__plus(tmp1, new string(")"));') |
| 239 | g.definitions.writeln('\treturn tmp2;') |
| 240 | g.definitions.writeln('}') |
| 241 | } |
| 242 | |
| 243 | fn (mut g JsGen) gen_str_for_option(typ ast.Type, _styp string, str_fn_name string) { |
| 244 | parent_type := typ.clear_flag(.option) |
| 245 | sym := g.table.sym(parent_type) |
| 246 | sym_has_str_method, _, _ := sym.str_method_info() |
| 247 | parent_str_fn_name := g.get_str_fn(parent_type) |
| 248 | |
| 249 | g.definitions.writeln('function ${str_fn_name}(it) { return indent_${str_fn_name}(it, 0); }') |
| 250 | g.definitions.writeln('function indent_${str_fn_name}(it, indent_count) {') |
| 251 | g.definitions.writeln('\tlet res;') |
| 252 | g.definitions.writeln('\tif (it.state.val == 0) {') |
| 253 | if sym.kind == .string { |
| 254 | tmp_res := '${parent_str_fn_name}(it.data)' |
| 255 | g.definitions.writeln('\t\tres = ${str_intp_sq(tmp_res)};') |
| 256 | } else if should_use_indent_func(sym.kind) && !sym_has_str_method { |
| 257 | g.definitions.writeln('\t\tres = indent_${parent_str_fn_name}(it.data, indent_count);') |
| 258 | } else { |
| 259 | g.definitions.writeln('\t\tres = ${parent_str_fn_name}(it.data);') |
| 260 | } |
| 261 | g.definitions.writeln('\t} else {') |
| 262 | |
| 263 | tmp_str := str_intp_sub('error: %%', 'IError_str(it.err)') |
| 264 | g.definitions.writeln('\t\tres = ${tmp_str};') |
| 265 | g.definitions.writeln('\t}') |
| 266 | |
| 267 | g.definitions.writeln('\treturn ${str_intp_sub('Option(%%)', 'res')};') |
| 268 | g.definitions.writeln('}') |
| 269 | } |
| 270 | |
| 271 | fn (mut g JsGen) gen_str_for_alias(info ast.Alias, _styp string, str_fn_name string) { |
| 272 | parent_str_fn_name := g.get_str_fn(info.parent_type) |
| 273 | g.definitions.writeln('function ${str_fn_name}(it) { return indent_${str_fn_name}(it, 0); }') |
| 274 | |
| 275 | g.definitions.writeln('function indent_${str_fn_name}(it, indent_count) {') |
| 276 | g.definitions.writeln('\tlet indents = string_repeat(new string(" "), indent_count);') |
| 277 | g.definitions.writeln('\tlet tmp_ds = ${parent_str_fn_name}(it);') |
| 278 | g.definitions.writeln('\tlet res = new string("TODO");') |
| 279 | g.definitions.writeln('\treturn res;') |
| 280 | g.definitions.writeln('}') |
| 281 | } |
| 282 | |
| 283 | fn (mut g JsGen) gen_str_for_multi_return(info ast.MultiReturn, _styp string, str_fn_name string) { |
| 284 | mut fn_builder := strings.new_builder(512) |
| 285 | fn_builder.writeln('function ${str_fn_name}(a) {') |
| 286 | fn_builder.writeln('\tlet sb = strings__new_builder(${info.types.len} * 10);') |
| 287 | fn_builder.writeln('\tstrings__Builder_write_string(sb, new string("("));') |
| 288 | for i, typ in info.types { |
| 289 | sym := g.table.sym(typ) |
| 290 | is_arg_ptr := typ.is_ptr() |
| 291 | sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() |
| 292 | arg_str_fn_name := g.get_str_fn(typ) |
| 293 | |
| 294 | if should_use_indent_func(sym.kind) && !sym_has_str_method { |
| 295 | fn_builder.writeln('\tstrings__Builder_write_string(sb, ${arg_str_fn_name}(a[${i}]));') |
| 296 | } else if sym.kind in [.f32, .f64] { |
| 297 | if sym.kind == .f32 { |
| 298 | tmp_val := str_intp_g32('a[${i}]') |
| 299 | fn_builder.writeln('\tstrings__Builder_write_string(sb, ${tmp_val});') |
| 300 | } else { |
| 301 | tmp_val := str_intp_g64('a[${i}]') |
| 302 | fn_builder.writeln('\tstrings__Builder_write_string(sb, ${tmp_val});') |
| 303 | } |
| 304 | } else if sym.kind == .string { |
| 305 | tmp_str := str_intp_sq('a[${i}]') |
| 306 | fn_builder.writeln('\tstrings__Builder_write_string(sb, ${tmp_str});') |
| 307 | } else if sym.kind == .function { |
| 308 | fn_builder.writeln('\tstrings__Builder_write_string(sb, ${arg_str_fn_name}());') |
| 309 | } else { |
| 310 | deref, deref_label := deref_kind(str_method_expects_ptr, is_arg_ptr, typ) |
| 311 | fn_builder.writeln('\t\tstrings__Builder_write_string(sb, new string("${deref_label}"));') |
| 312 | fn_builder.writeln('\tstrings__Builder_write_string(sb, ${arg_str_fn_name}( a[${i}] ${deref} ));') |
| 313 | } |
| 314 | if i != info.types.len - 1 { |
| 315 | fn_builder.writeln('\tstrings__Builder_write_string(sb, new string(", "));') |
| 316 | } |
| 317 | } |
| 318 | fn_builder.writeln('\tstrings__Builder_write_string(sb, new string(")"));') |
| 319 | fn_builder.writeln('\tlet res = strings__Builder_str(sb);') |
| 320 | fn_builder.writeln('\treturn res;') |
| 321 | fn_builder.writeln('}') |
| 322 | g.definitions.writeln(fn_builder.str()) |
| 323 | } |
| 324 | |
| 325 | fn (mut g JsGen) gen_str_for_enum(info ast.Enum, styp string, str_fn_name string) { |
| 326 | s := util.no_dots(styp) |
| 327 | |
| 328 | g.definitions.writeln('function ${str_fn_name}(it) { /* gen_str_for_enum */') |
| 329 | // Enums tagged with `@[flag]` are special in that they can be a combination of enum values |
| 330 | if info.is_flag { |
| 331 | clean_name := util.strip_main_name(styp.replace('__', '.')) |
| 332 | g.definitions.writeln('\tlet ret = new string("${clean_name}{");') |
| 333 | g.definitions.writeln('\tlet first = 1;') |
| 334 | for i, val in info.vals { |
| 335 | g.definitions.writeln('\tif (it & (1 << ${i})) {if (!first) {ret = string__plus(ret, new string(" | "));} ret = string__plus(ret, new string(".${val}")); first = 0;}') |
| 336 | } |
| 337 | g.definitions.writeln('\tret = string__plus(ret, new string("}"));') |
| 338 | g.definitions.writeln('\treturn ret;') |
| 339 | } else { |
| 340 | g.definitions.writeln('\tswitch(it) {') |
| 341 | // Only use the first multi value on the lookup |
| 342 | mut seen := []string{len: info.vals.len} |
| 343 | for val in info.vals { |
| 344 | if info.is_multi_allowed && val in seen { |
| 345 | continue |
| 346 | } else if info.is_multi_allowed { |
| 347 | seen << val |
| 348 | } |
| 349 | g.definitions.writeln('\t\tcase ${s}.${val}: return new string("${val}");') |
| 350 | } |
| 351 | g.definitions.writeln('\t\tdefault: return new string("unknown enum value");') |
| 352 | g.definitions.writeln('\t}') |
| 353 | } |
| 354 | g.definitions.writeln('}') |
| 355 | } |
| 356 | |
| 357 | fn (mut g JsGen) gen_str_for_interface(info ast.Interface, styp string, str_fn_name string) { |
| 358 | // _str() functions should have a single argument, the indenting ones take 2: |
| 359 | |
| 360 | g.definitions.writeln('function ${str_fn_name}(x) { return indent_${str_fn_name}(x, 0); }') |
| 361 | |
| 362 | mut fn_builder := strings.new_builder(512) |
| 363 | mut clean_interface_v_type_name := styp.replace('__', '.') |
| 364 | if styp.ends_with('*') { |
| 365 | clean_interface_v_type_name = '&' + clean_interface_v_type_name.replace('*', '') |
| 366 | } |
| 367 | if clean_interface_v_type_name.contains('_T_') { |
| 368 | clean_interface_v_type_name = |
| 369 | clean_interface_v_type_name.replace('Array_', '[]').replace('_T_', '[').replace('_', ', ') + |
| 370 | ']' |
| 371 | } |
| 372 | clean_interface_v_type_name = util.strip_main_name(clean_interface_v_type_name) |
| 373 | fn_builder.writeln('function indent_${str_fn_name}(x,indent_count) { /* gen_str_for_interface */') |
| 374 | for typ in info.types { |
| 375 | subtype := g.table.sym(typ) |
| 376 | mut func_name := g.get_str_fn(typ) |
| 377 | sym_has_str_method, str_method_expects_ptr, _ := subtype.str_method_info() |
| 378 | if should_use_indent_func(subtype.kind) && !sym_has_str_method { |
| 379 | func_name = 'indent_${func_name}' |
| 380 | } |
| 381 | deref := if sym_has_str_method && str_method_expects_ptr { ' ' } else { '.valueOf()' } |
| 382 | // str_intp |
| 383 | |
| 384 | if typ == ast.string_type { |
| 385 | fn_builder.write_string('\tif (x.val instanceof string)') |
| 386 | fn_builder.write_string(' return "new string(${clean_interface_v_type_name}(" + x.val.str + ")");') |
| 387 | } else { |
| 388 | mut val := '${func_name}(x ${deref}' |
| 389 | if should_use_indent_func(subtype.kind) && !sym_has_str_method { |
| 390 | val += ', indent_count' |
| 391 | } |
| 392 | val += ')' |
| 393 | |
| 394 | fn_builder.write_string('\tif (x.val instanceof ${subtype.cname})') |
| 395 | fn_builder.write_string(' return new string("${clean_interface_v_type_name}(" + ${val}.str + ")");\n') |
| 396 | } |
| 397 | } |
| 398 | fn_builder.writeln('\treturn new string("unknown interface value");') |
| 399 | fn_builder.writeln('}') |
| 400 | g.definitions.writeln(fn_builder.str()) |
| 401 | } |
| 402 | |
| 403 | fn (mut g JsGen) gen_str_for_union_sum_type(info ast.SumType, _styp string, str_fn_name string) { |
| 404 | g.definitions.writeln('function ${str_fn_name}(x) { return indent_${str_fn_name}(x, 0); }') |
| 405 | mut fn_builder := strings.new_builder(512) |
| 406 | fn_builder.writeln('function indent_${str_fn_name}(x, indent_count) {') |
| 407 | for typ in info.variants { |
| 408 | typ_str := g.styp(typ) |
| 409 | mut func_name := g.get_str_fn(typ) |
| 410 | sym := g.table.sym(typ) |
| 411 | sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() |
| 412 | deref := if sym_has_str_method && str_method_expects_ptr { |
| 413 | ' ' |
| 414 | } else { |
| 415 | if typ.is_ptr() { '.valueOf()' } else { ' ' } |
| 416 | } |
| 417 | if should_use_indent_func(sym.kind) && !sym_has_str_method { |
| 418 | func_name = 'indent_${func_name}' |
| 419 | } |
| 420 | fn_builder.writeln('if (x instanceof ${typ_str}) { return ${func_name}(x${deref}); }') |
| 421 | } |
| 422 | fn_builder.writeln('builtin__panic(new string("unknown sum type value"));\n}') |
| 423 | g.definitions.writeln(fn_builder.str()) |
| 424 | } |
| 425 | |
| 426 | fn (mut g JsGen) fn_decl_str(info ast.FnType) string { |
| 427 | mut fn_str := 'fn (' |
| 428 | for i, arg in info.func.params { |
| 429 | if arg.is_mut { |
| 430 | fn_str += 'mut ' |
| 431 | } |
| 432 | if i > 0 { |
| 433 | fn_str += ', ' |
| 434 | } |
| 435 | if arg.typ.has_flag(.option) { |
| 436 | fn_str += '?' |
| 437 | } |
| 438 | fn_str += util.strip_main_name(g.table.get_type_name(g.unwrap_generic(arg.typ))) |
| 439 | } |
| 440 | fn_str += ')' |
| 441 | if info.func.return_type == ast.ovoid_type { |
| 442 | fn_str += ' ?' |
| 443 | } else if info.func.return_type == ast.rvoid_type { |
| 444 | fn_str += ' !' |
| 445 | } else if info.func.return_type != ast.void_type { |
| 446 | x := util.strip_main_name(g.table.get_type_name(g.unwrap_generic(info.func.return_type))) |
| 447 | if info.func.return_type.has_flag(.option) { |
| 448 | fn_str += ' ?${x}' |
| 449 | } else { |
| 450 | fn_str += ' ${x}' |
| 451 | } |
| 452 | } |
| 453 | return fn_str |
| 454 | } |
| 455 | |
| 456 | fn (mut g JsGen) gen_str_for_fn_type(info ast.FnType, _styp string, str_fn_name string) { |
| 457 | g.definitions.writeln('function ${str_fn_name}() { return new string("${g.fn_decl_str(info)}");}') |
| 458 | } |
| 459 | |
| 460 | fn (mut g JsGen) gen_str_for_chan(info ast.Chan, _styp string, str_fn_name string) { |
| 461 | elem_type_name := util.strip_main_name(g.table.get_type_name(g.unwrap_generic(info.elem_type))) |
| 462 | |
| 463 | g.definitions.writeln('function ${str_fn_name}(x) { return sync__Channel_auto_str(x, new string("${elem_type_name}")); }') |
| 464 | } |
| 465 | |
| 466 | fn (mut g JsGen) gen_str_for_thread(info ast.Thread, _styp string, str_fn_name string) { |
| 467 | ret_type_name := util.strip_main_name(g.table.get_type_name(info.return_type)) |
| 468 | |
| 469 | g.definitions.writeln('function ${str_fn_name}(_) { return new string("thread(${ret_type_name})");}') |
| 470 | } |
| 471 | |
| 472 | @[inline] |
| 473 | fn styp_to_str_fn_name(styp string) string { |
| 474 | return styp.replace_each(['*', '', '.', '__', ' ', '__']) + '_str' |
| 475 | } |
| 476 | |
| 477 | fn deref_kind(str_method_expects_ptr bool, is_elem_ptr bool, typ ast.Type) (string, string) { |
| 478 | if str_method_expects_ptr != is_elem_ptr { |
| 479 | if is_elem_ptr { |
| 480 | return '.val'.repeat(typ.nr_muls()), 'new \$ref('.repeat(typ.nr_muls()) |
| 481 | } else { |
| 482 | return 'new \$ref', '' |
| 483 | } |
| 484 | } |
| 485 | return '', '' |
| 486 | } |
| 487 | |
| 488 | fn (mut g JsGen) gen_str_for_array(info ast.Array, _styp string, str_fn_name string) { |
| 489 | mut typ := info.elem_type |
| 490 | mut sym := g.table.sym(info.elem_type) |
| 491 | if mut sym.info is ast.Alias { |
| 492 | typ = sym.info.parent_type |
| 493 | sym = g.table.sym(typ) |
| 494 | } |
| 495 | is_elem_ptr := typ.is_ptr() |
| 496 | sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() |
| 497 | mut elem_str_fn_name := g.get_str_fn(typ) |
| 498 | if sym.kind == .u8 { |
| 499 | elem_str_fn_name = elem_str_fn_name + '_escaped' |
| 500 | } |
| 501 | |
| 502 | g.definitions.writeln('function ${str_fn_name}(a) { return indent_${str_fn_name}(a, 0);}') |
| 503 | g.definitions.writeln('function indent_${str_fn_name}(a, indent_count) {') |
| 504 | g.definitions.writeln('\tlet sb = strings__new_builder(a.len * 10);') |
| 505 | g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("["));') |
| 506 | g.definitions.writeln('\tfor (let i = 0; i < a.len; ++i) {') |
| 507 | if sym.kind == .function { |
| 508 | g.definitions.writeln('\t\tlet it = ${elem_str_fn_name}();') |
| 509 | } else { |
| 510 | g.definitions.writeln('\t\tlet it = a.arr.get(new int(i));') |
| 511 | |
| 512 | if should_use_indent_func(sym.kind) && !sym_has_str_method { |
| 513 | if is_elem_ptr { |
| 514 | g.definitions.writeln('\t\tlet x = indent_${elem_str_fn_name}(it.val, indent_count);') |
| 515 | } else { |
| 516 | g.definitions.writeln('\t\tlet x = indent_${elem_str_fn_name}(it, indent_count);') |
| 517 | } |
| 518 | } else if sym.kind in [.f32, .f64] { |
| 519 | g.definitions.writeln('\t\tlet x = new string( it.val + "");') |
| 520 | } else if sym.kind == .rune { |
| 521 | g.definitions.writeln('\t\tlet x = new string("\`" + String.fromCharCode(it.val) + "\`");') |
| 522 | // Rune are managed at this level as strings |
| 523 | // g.definitions.writeln('\t\tstring x = builtin__str_intp(2, _MOV((StrIntpData[]){{new string("\`"), ${c.si_s_code}, {.d_s = ${elem_str_fn_name}(it) }}, {new string("\`"), 0, {.d_c = 0 }}}));\n') |
| 524 | } else if sym.kind == .string { |
| 525 | g.definitions.writeln('\t\tlet x = new string(it);') |
| 526 | // g.definitions.writeln('\t\tstring x = builtin__str_intp(2, _MOV((StrIntpData[]){{new string("\'"), ${c.si_s_code}, {.d_s = it }}, {new string("\'"), 0, {.d_c = 0 }}}));\n') |
| 527 | } else { |
| 528 | // There is a custom .str() method, so use it. |
| 529 | // Note: we need to take account of whether the user has defined |
| 530 | // `fn (x T) str() {` or `fn (x &T) str() {`, and convert accordingly |
| 531 | deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ) |
| 532 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string("${deref_label}"));') |
| 533 | g.definitions.writeln('\t\tlet x = ${elem_str_fn_name}( ${deref} it);') |
| 534 | } |
| 535 | } |
| 536 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, x);') |
| 537 | |
| 538 | g.definitions.writeln('\t\tif (i < a.len-1) {') |
| 539 | g.definitions.writeln('\t\t\tstrings__Builder_write_string(sb, new string(", "));') |
| 540 | g.definitions.writeln('\t\t}') |
| 541 | g.definitions.writeln('\t}') |
| 542 | g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("]"));') |
| 543 | g.definitions.writeln('\tlet res = strings__Builder_str(sb);') |
| 544 | g.definitions.writeln('\treturn res;') |
| 545 | g.definitions.writeln('}') |
| 546 | } |
| 547 | |
| 548 | fn (mut g JsGen) gen_str_for_array_fixed(info ast.ArrayFixed, _styp string, str_fn_name string) { |
| 549 | mut typ := info.elem_type |
| 550 | mut sym := g.table.sym(info.elem_type) |
| 551 | if mut sym.info is ast.Alias { |
| 552 | typ = sym.info.parent_type |
| 553 | sym = g.table.sym(typ) |
| 554 | } |
| 555 | is_elem_ptr := typ.is_ptr() |
| 556 | sym_has_str_method, str_method_expects_ptr, _ := sym.str_method_info() |
| 557 | elem_str_fn_name := g.get_str_fn(typ) |
| 558 | |
| 559 | g.definitions.writeln('function ${str_fn_name}(a) { return indent_${str_fn_name}(a, 0);}') |
| 560 | |
| 561 | g.definitions.writeln('function indent_${str_fn_name}(a, indent_count) {') |
| 562 | g.definitions.writeln('\tlet sb = strings__new_builder(${info.size} * 10);') |
| 563 | g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("["));') |
| 564 | g.definitions.writeln('\tfor (let i = 0; i < ${info.size}; ++i) {') |
| 565 | if sym.kind == .function { |
| 566 | g.definitions.writeln('\t\tstring x = ${elem_str_fn_name}();') |
| 567 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, x);') |
| 568 | } else { |
| 569 | deref, deref_label := deref_kind(str_method_expects_ptr, is_elem_ptr, typ) |
| 570 | if should_use_indent_func(sym.kind) && !sym_has_str_method { |
| 571 | if is_elem_ptr { |
| 572 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string("${deref_label}"));') |
| 573 | g.definitions.writeln('\t\tif ( 0 == a.arr.get(new int(i)) ) {') |
| 574 | g.definitions.writeln('\t\t\tstrings__Builder_write_string(sb, new string("0"));') |
| 575 | g.definitions.writeln('\t\t}else{') |
| 576 | g.definitions.writeln('\t\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(a.arr.get(new int(i)) ${deref}) );') |
| 577 | g.definitions.writeln('\t\t}') |
| 578 | } else { |
| 579 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(a.arr.get(new int(i))) );') |
| 580 | } |
| 581 | } else if sym.kind in [.f32, .f64] { |
| 582 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string(a.arr.get(new int(i)).val.toString()) );') |
| 583 | } else if sym.kind == .string { |
| 584 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, a.arr.get(new int(i)));') |
| 585 | } else if sym.kind == .rune { |
| 586 | g.definitions.writeln('\t\tlet x = new string("\`" + String.fromCharCode(a.arr.get(new int(i)).val) + "\`");') |
| 587 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb,x);') |
| 588 | } else { |
| 589 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(a.arr.get(new int(i)) ${deref}));') |
| 590 | } |
| 591 | } |
| 592 | g.definitions.writeln('\t\tif (i < ${info.size - 1}) {') |
| 593 | g.definitions.writeln('\t\t\tstrings__Builder_write_string(sb, new string(", "));') |
| 594 | g.definitions.writeln('\t\t}') |
| 595 | g.definitions.writeln('\t}') |
| 596 | g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("]"));') |
| 597 | g.definitions.writeln('\tlet res = strings__Builder_str(sb);') |
| 598 | g.definitions.writeln('\treturn res;') |
| 599 | g.definitions.writeln('}') |
| 600 | } |
| 601 | |
| 602 | fn (mut g JsGen) gen_str_for_map(info ast.Map, _styp string, str_fn_name string) { |
| 603 | mut key_typ := info.key_type |
| 604 | mut key_sym := g.table.sym(key_typ) |
| 605 | if mut key_sym.info is ast.Alias { |
| 606 | key_typ = key_sym.info.parent_type |
| 607 | key_sym = g.table.sym(key_typ) |
| 608 | } |
| 609 | key_styp := g.styp(key_typ) |
| 610 | key_str_fn_name := key_styp.replace('*', '') + '_str' |
| 611 | if !key_sym.has_method('str') { |
| 612 | g.get_str_fn(key_typ) |
| 613 | } |
| 614 | |
| 615 | mut val_typ := info.value_type |
| 616 | mut val_sym := g.table.sym(val_typ) |
| 617 | if mut val_sym.info is ast.Alias { |
| 618 | val_typ = val_sym.info.parent_type |
| 619 | val_sym = g.table.sym(val_typ) |
| 620 | } |
| 621 | val_styp := g.styp(val_typ) |
| 622 | elem_str_fn_name := val_styp.replace('*', '') + '_str' |
| 623 | if !val_sym.has_method('str') { |
| 624 | g.get_str_fn(val_typ) |
| 625 | } |
| 626 | |
| 627 | g.definitions.writeln('function ${str_fn_name}(m) { return indent_${str_fn_name}(m, 0);}') |
| 628 | |
| 629 | g.definitions.writeln('function indent_${str_fn_name}(m, indent_count) { /* gen_str_for_map */') |
| 630 | g.definitions.writeln('\tlet sb = strings__new_builder(m.map.length * 10);') |
| 631 | g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("{"));') |
| 632 | g.definitions.writeln('\tlet i = 0;') |
| 633 | g.definitions.writeln('\tlet keys = Object.keys(m.map);') |
| 634 | g.definitions.writeln('\tfor (let j = 0; j < keys.length;j++) {') |
| 635 | g.definitions.writeln('\t\tlet key = keys[j];') |
| 636 | g.definitions.writeln('\t\tlet value = m.map[key].val;') |
| 637 | if key_sym.kind == .enum { |
| 638 | g.definitions.writeln('\t\tkey = +key;') |
| 639 | } else { |
| 640 | g.definitions.writeln('\t\tkey = new ${key_styp}(key);') |
| 641 | } |
| 642 | if key_sym.kind == .string { |
| 643 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string("\'" + key.str + "\'"));') |
| 644 | } else if key_sym.kind == .rune { |
| 645 | g.definitions.writeln('\t\tlet x = new string("\`" + String.fromCharCode(key.val) + "\`");') |
| 646 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb,x);') |
| 647 | // g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${tmp_str});') |
| 648 | } else { |
| 649 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${key_str_fn_name}(key));') |
| 650 | } |
| 651 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string(": "));') |
| 652 | if val_sym.kind == .function { |
| 653 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}());') |
| 654 | } else if val_sym.kind == .string { |
| 655 | // tmp_str := str_intp_sq('*(${val_styp}*)DenseArray_value(&m.key_values, i)') |
| 656 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb,new string("\'" + value.str + "\'"));') |
| 657 | } else if should_use_indent_func(val_sym.kind) && !val_sym.has_method('str') { |
| 658 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, indent_${elem_str_fn_name}(value, indent_count));') |
| 659 | } else if val_sym.kind in [.f32, .f64] { |
| 660 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, new string(value.val + ""));') |
| 661 | } else if val_sym.kind == .rune { |
| 662 | g.definitions.writeln('\t\tlet x = new string("\`" + String.fromCharCode(value.val) + "\`");') |
| 663 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb,x);') |
| 664 | } else { |
| 665 | g.definitions.writeln('\t\tstrings__Builder_write_string(sb, ${elem_str_fn_name}(value));') |
| 666 | } |
| 667 | g.definitions.writeln('\t\tif (i != keys.length-1) {') |
| 668 | g.definitions.writeln('\t\t\tstrings__Builder_write_string(sb, new string(", "));') |
| 669 | g.definitions.writeln('\t\t}') |
| 670 | g.definitions.writeln('\t\ti++;') |
| 671 | g.definitions.writeln('\t}') |
| 672 | g.definitions.writeln('\tstrings__Builder_write_string(sb, new string("}"));') |
| 673 | g.definitions.writeln('\tlet res = strings__Builder_str(sb);') |
| 674 | g.definitions.writeln('\treturn res;') |
| 675 | g.definitions.writeln('}') |
| 676 | } |
| 677 | |
| 678 | fn (g &JsGen) type_to_fmt(typ ast.Type) StrIntpType { |
| 679 | if typ == ast.u8_type_idx { |
| 680 | return .si_u8 |
| 681 | } |
| 682 | if typ == ast.char_type_idx { |
| 683 | return .si_c |
| 684 | } |
| 685 | if typ in ast.voidptr_types || typ == ast.nil_type || typ in ast.byteptr_types { |
| 686 | return .si_p |
| 687 | } |
| 688 | if typ in ast.charptr_types { |
| 689 | // return '%C\\000' // a C string |
| 690 | return .si_s |
| 691 | } |
| 692 | sym := g.table.sym(typ) |
| 693 | if typ.is_int_valptr() || typ.is_float_valptr() { |
| 694 | return .si_s |
| 695 | } else if sym.kind in [.struct, .array, .array_fixed, .map, .bool, .enum, .interface, .sum_type, |
| 696 | .function, .alias, .chan] { |
| 697 | return .si_s |
| 698 | } else if sym.kind == .string { |
| 699 | return .si_s |
| 700 | // return "'%.*s\\000'" |
| 701 | } else if sym.kind in [.f32, .f64] { |
| 702 | if sym.kind == .f32 { |
| 703 | return .si_g32 |
| 704 | } |
| 705 | return .si_g64 |
| 706 | } else if sym.kind == .int { |
| 707 | return .si_i32 |
| 708 | } else if sym.kind == .u32 { |
| 709 | return .si_u32 |
| 710 | } else if sym.kind == .u64 { |
| 711 | return .si_u64 |
| 712 | } else if sym.kind == .i64 { |
| 713 | return .si_i64 |
| 714 | } else if sym.kind == .usize { |
| 715 | return .si_u64 |
| 716 | } else if sym.kind == .isize { |
| 717 | return .si_i64 |
| 718 | } |
| 719 | return .si_i32 |
| 720 | } |
| 721 | |
| 722 | fn (mut g JsGen) gen_str_for_struct(info ast.Struct, styp string, str_fn_name string, type_idx int) { |
| 723 | // _str() functions should have a single argument, the indenting ones take 2: |
| 724 | |
| 725 | g.definitions.writeln('function ${str_fn_name}(it) { return indent_${str_fn_name}(it, 0);}') |
| 726 | |
| 727 | mut fn_builder := strings.new_builder(512) |
| 728 | defer { |
| 729 | g.definitions.writeln(fn_builder.str()) |
| 730 | } |
| 731 | fn_builder.writeln('function indent_${str_fn_name}(it, indent_count) {') |
| 732 | mut clean_struct_v_type_name := styp.replace('__', '.') |
| 733 | if clean_struct_v_type_name.contains('_T_') { |
| 734 | // TODO: this is a bit hacky. styp shouldn't be even parsed with _T_ |
| 735 | // use something different than g.typ for styp |
| 736 | clean_struct_v_type_name = |
| 737 | clean_struct_v_type_name.replace('Array_', '[]').replace('_T_', '[').replace('_', ', ') + |
| 738 | ']' |
| 739 | } |
| 740 | clean_struct_v_type_name = util.strip_main_name(clean_struct_v_type_name) |
| 741 | // generate ident / indent length = 4 spaces |
| 742 | if info.fields.len == 0 { |
| 743 | fn_builder.writeln('\treturn new string("${clean_struct_v_type_name}{}");') |
| 744 | fn_builder.writeln('}') |
| 745 | return |
| 746 | } |
| 747 | allow_circular := info.attrs.any(it.name == 'autostr' && it.arg == 'allowrecurse') |
| 748 | if !allow_circular { |
| 749 | g.ensure_autostr_helpers() |
| 750 | fn_builder.writeln('\tif (builtin__autostr_type_in_stack(${type_idx})) {') |
| 751 | fn_builder.writeln('\t\treturn new string("<circular>")') |
| 752 | fn_builder.writeln('\t}') |
| 753 | fn_builder.writeln('\tbuiltin__autostr_type_push(${type_idx})') |
| 754 | } |
| 755 | |
| 756 | fn_builder.writeln('\tlet res = /*struct name*/new string("${clean_struct_v_type_name}{\\n")') |
| 757 | for i, field in info.fields { |
| 758 | mut ptr_amp := if field.typ.is_ptr() { '&' } else { '' } |
| 759 | mut prefix := '' |
| 760 | // manage prefix and quote symbol for the filed |
| 761 | /* |
| 762 | mut quote_str := '' |
| 763 | |
| 764 | |
| 765 | if sym.kind == .string { |
| 766 | quote_str = "'" |
| 767 | } else if field.typ in ast.charptr_types { |
| 768 | quote_str = '\\"' |
| 769 | prefix = 'C' |
| 770 | } |
| 771 | quote_str = quote_str |
| 772 | */ |
| 773 | sym := g.table.sym(g.unwrap_generic(field.typ)) |
| 774 | // first fields doesn't need \n |
| 775 | if i == 0 { |
| 776 | fn_builder.write_string('res.str += " ${field.name}: ${ptr_amp}${prefix}" + ') |
| 777 | } else { |
| 778 | fn_builder.write_string('res.str += "\\n ${field.name}: ${ptr_amp}${prefix}" + ') |
| 779 | } |
| 780 | |
| 781 | // custom methods management |
| 782 | has_custom_str := sym.has_method('str') |
| 783 | mut field_styp := g.styp(field.typ).replace('*', '') |
| 784 | field_styp_fn_name := if has_custom_str { |
| 785 | '${field_styp}_str' |
| 786 | } else { |
| 787 | g.get_str_fn(field.typ) |
| 788 | } |
| 789 | |
| 790 | mut func := struct_auto_str_func(mut g, sym, field.typ, field_styp_fn_name, field.name) |
| 791 | if field.typ in ast.cptr_types { |
| 792 | func = '(voidptr) it.${field.name}' |
| 793 | } else if field.typ.is_ptr() { |
| 794 | // reference types can be "nil" |
| 795 | fn_builder.write_string('builtin__isnil(it.${g.js_name(field.name)})') |
| 796 | fn_builder.write_string(' ? new string("nil") : ') |
| 797 | // struct, floats and ints have a special case through the _str function |
| 798 | if sym.kind != .struct && !field.typ.is_int_valptr() && !field.typ.is_float_valptr() { |
| 799 | fn_builder.write_string('*') |
| 800 | } |
| 801 | } |
| 802 | // handle circular ref type of struct to the struct itself |
| 803 | if styp == field_styp && !allow_circular { |
| 804 | fn_builder.write_string('res.str += new string("<circular>")') |
| 805 | } else { |
| 806 | // manage C charptr |
| 807 | if field.typ in ast.charptr_types { |
| 808 | fn_builder.write_string('builtin__tos4((byteptr)${func})') |
| 809 | } else { |
| 810 | if field.typ.is_ptr() && sym.kind == .struct { |
| 811 | fn_builder.write_string('(indent_count > 25)? new string("<probably circular>") : ') |
| 812 | } |
| 813 | fn_builder.write_string(func) |
| 814 | } |
| 815 | } |
| 816 | |
| 817 | fn_builder.writeln('') |
| 818 | } |
| 819 | fn_builder.writeln('res.str += "\\n}"') |
| 820 | if !allow_circular { |
| 821 | fn_builder.writeln('\tbuiltin__autostr_type_pop()') |
| 822 | } |
| 823 | // fn_builder.writeln('\t\t{new string("\\n"), ${c.si_s_code}, {.d_s=indents}}, {new string("}"), 0, {.d_c=0}},') |
| 824 | fn_builder.writeln('\treturn res;') |
| 825 | fn_builder.writeln('}') |
| 826 | } |
| 827 | |
| 828 | fn struct_auto_str_func(mut g JsGen, sym &ast.TypeSymbol, field_type ast.Type, fn_name string, field_name string) string { |
| 829 | has_custom_str, expects_ptr, _ := sym.str_method_info() |
| 830 | if sym.kind == .enum { |
| 831 | return '${fn_name}(it.${g.js_name(field_name)})' |
| 832 | } else if should_use_indent_func(sym.kind) { |
| 833 | mut obj := 'it.${g.js_name(field_name)}' |
| 834 | if field_type.is_ptr() && !expects_ptr { |
| 835 | obj = '*${obj}' |
| 836 | } |
| 837 | if has_custom_str { |
| 838 | return '${fn_name}(${obj})' |
| 839 | } |
| 840 | return 'indent_${fn_name}(${obj}, indent_count + 1)' |
| 841 | } else if sym.kind in [.array, .array_fixed, .map, .sum_type] { |
| 842 | if has_custom_str { |
| 843 | return '${fn_name}(it.${g.js_name(field_name)})' |
| 844 | } |
| 845 | return 'indent_${fn_name}(it.${g.js_name(field_name)}, indent_count + 1)' |
| 846 | } else if sym.kind == .function { |
| 847 | return '${fn_name}()' |
| 848 | } else { |
| 849 | if sym.kind == .chan { |
| 850 | return '${fn_name}(it.${g.js_name(field_name)})' |
| 851 | } |
| 852 | mut method_str := 'it.${g.js_name(field_name)}' |
| 853 | if sym.kind == .bool { |
| 854 | method_str += ' ? new string("true") : new string("false")' |
| 855 | } else if (field_type.is_int_valptr() || field_type.is_float_valptr()) && !expects_ptr { |
| 856 | // ptr int can be "nil", so this needs to be casted to a string |
| 857 | if sym.kind == .f32 { |
| 858 | return 'builtin__str_intp(1, _MOV((StrIntpData[]){ |
| 859 | {_SLIT0, ${si_g32_code}, {.d_f32 = *${method_str} }} |
| 860 | }))' |
| 861 | } else if sym.kind == .f64 { |
| 862 | return 'builtin__str_intp(1, _MOV((StrIntpData[]){ |
| 863 | {_SLIT0, ${si_g64_code}, {.d_f64 = *${method_str} }} |
| 864 | }))' |
| 865 | } else if sym.kind in [.u64, .usize] { |
| 866 | fmt_type := StrIntpType.si_u64 |
| 867 | return 'builtin__str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_u64 = *${method_str} }}}))' |
| 868 | } else if sym.kind in [.i64, .isize] { |
| 869 | fmt_type := StrIntpType.si_u64 |
| 870 | return 'builtin__str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i64 = *${method_str} }}}))' |
| 871 | } |
| 872 | fmt_type := StrIntpType.si_i32 |
| 873 | return 'builtin__str_intp(1, _MOV((StrIntpData[]){{_SLIT0, ${u32(fmt_type) | 0xfe00}, {.d_i32 = *${method_str} }}}))' |
| 874 | } |
| 875 | return method_str |
| 876 | } |
| 877 | } |
| 878 | |