Template Literals

Status: implemented

sergey-shandar approved the untagged-template design in #2822, as DESIGN.md §12 requires.

An untagged template is a backtick-delimited primary expression, with cooked text chunks separated by ${expression} substitutions:

const name = "world";
export default `Hello, ${name}!`;
// "Hello, world!"

Each substitution uses the ordinary full expression grammar, including object literals, function bodies and nested templates. A template can be an operand, call argument or property-access base, as in `abc`.length. Empty templates and adjacent substitutions are admitted too.

Text chunks accept JSON's escapes (\", \\, \/, \b, \f, \n, \r, \t, \uXXXX, \u{…}), hexadecimal escapes (\xHH), vertical-tab escapes (\v), escaped backticks and the escaped substitution opener \${. Quotes stand raw. Only an unescaped ${ opens a substitution. Literal LF, CR and CRLF are admitted; raw CR and CRLF cook to LF, while escaped \r or \u000D stays CR. Raw U+2028 and U+2029 keep their values. Additional JavaScript template escapes, other raw C0 controls and line continuations remain deferred here and are refused. The quoted-string counterparts are tracked separately in js-string-literals, which excludes templates. Malformed or unterminated templates and tagged templates such as tag`a${b}c` are compilation errors.

A hexadecimal escape consumes exactly two hexadecimal digits, in either case. \xHH denotes the same single UTF-16 code unit as \u00HH, including \x80 through \xff; it is not a UTF-8 byte sequence. A following digit is ordinary text: \x414 denotes A4. Missing or non-hexadecimal digits are errors, including \x8?. This uses the existing shared lexer and cooked-value decoder, without a new AST or FAST node.

The language designer sergey-shandar approved the hexadecimal and vertical-tab increments in the working session. Hexadecimal and vertical-tab escapes are also admitted in single-quoted strings; double-quoted strings keep their existing escape subset. \v denotes U+000B, exactly as \u000b does, in every template chunk. Identity escapes, raw C0 controls other than CR/LF, and line continuations remain refused here.

The NUL shorthand \0 is intentionally prohibited, even when followed by an otherwise valid character. Use the fixed-width \u0000 or \x00 spelling instead. The codebase rule also applies to proofs, helpers and host adapters.

Refused template spellingAdmitted spelling with the same value
`\0${"key"}\0``\u0000${"key"}\u0000`

For a refused line continuation, join the lines without the continuation sequence to preserve the value. Before marking a module compiler-compatible with the .f.js extension, normalize any deferred spellings it uses. For example, serializer/names's _name uses `\0${key}\0`; its supported equivalent is `\u0000${key}\u0000`. Template support alone does not admit every existing template spelling.

Every substitution is converted with String, and its result is concatenated with the cooked chunks using left-associated binary +. For example, `hello ${a}!` has the same meaning and EDAG as "hello " + String(a) + "!":

['+', ['+', 'hello ', ['String', A]], '!']

Here A is the lowered expression for a. For chunks s0 through sn and substitutions e1 through en, lowering starts with r = s0. In source order, each substitution adds r = ['+', r, ['String', lower(ei)]], then r = ['+', r, si]. Every chunk, including an empty one, is retained, and conversion is never folded away. Thus `${1}${2}` expands to "" + String(1) + "" + String(2) + "", producing "12".

The result of a successful template evaluation is always a string. Evaluation or conversion failure propagates under failure is one outcome: the graph construction order does not impose evaluation-count or source-order barriers on failing computations. Function conversion follows the existing function-source representation exception.

Explicit string conversion matters for objects: String tries toString before valueOf, whereas raw + coercion tries them in the opposite order.

const a = { valueOf: () => 7, toString: () => "a" };
export default ["hello " + a + "!", `hello ${a}!`];
// ["hello 7!", "hello a!"]

Some further examples:

``;                      // ""
`abc`;                   // "abc"
`${1n}:${undefined}`;    // "1:undefined"
`sum: ${1 + 2}`;         // "sum: 3"
`${{ x: 1 }.x}`;         // "1"
`${`${1}`}!`;            // "1!"
`literal \${a}`;         // "literal ${a}"
`\``;                    // "`"
`\u0000${"key"}\u0000`;  // "\u0000key\u0000"
`line
break`;                  // "line\nbreak"

A template without substitutions lowers directly to its cooked string leaf, so `abc` and "abc" have the same EDAG. Every template is FJS source syntax, including this case; cooking does not classify it as JSON or DataJS. FunctionalScript output writes a string or the explicit String/+ expansion instead of reconstructing template spelling. EDAG and Rust outputs use those existing operations, and JSON and DataJS outputs evaluate them.

Examples

The compiler demo offers the programs templateLiterals in module.f.js, each with its real output.

The demo on this page runs sample.f.js, this page's example as a function of one number — a template literal with two substitutions — with every output fjs compile makes of it: the expression graph (EDAG), the Rust and the WebAssembly that Rust builds to. Its Run button calls the default export with 1 and 2, as JavaScript and as WebAssembly, and shows what each call returned or threw.

export default (...a) => `Hello, ${a[0]} world${a[0] > 1 ? "s" : ""}!`;

Reference

Demo

In FunctionalScript

fjs compile accepts this module, and it runs as JavaScript and as WebAssembly alike.

A FunctionalScript module and what fjs compile makes of it: the expression graph it lowers to, the Rust it compiles to on the NaNVM runtime, and the WebAssembly that Rust builds to. Run calls its default export with 1, then 2, first as the JavaScript it already is and then as WebAssembly, and shows what each call returned or threw and how long one call takes, timed over 1000 calls.

FunctionalScript source:

/**
 * The example of [`README.md`](./README.md) (Template Literals) as a
 * function of one number, for the page's WASM demo: a template literal with
 * two substitutions.
 *
 * @module
 */

export default (/** @type {readonly number[]} */ ...a) => `Hello, ${a[0]} world${a[0] > 1 ? "s" : ""}!`;

Expression graph (EDAG) that fjs compile lowers it to:

=>lengthbody0++leftright+"!"+leftright+leftright+" world"Stringoperand+leftright"Hello, "String?:condthenelse>"s"""Stringoperand>leftright.1.objidxrest0.objidxrest0

The same graph, as fjs compile writes it to a .edag.data.js file:

const $0=["rest"];export default ["{}",[[":","default",["=>",0,[],["+",["+",["+",["+","Hello, ",["String",[".",$0,0]]]," world"],["String",["?:",[">",[".",$0,0],1],"s",""]]],"!"]]]]];

Rust that fjs compile writes from it, on the NaNVM runtime:

// @generated by `fjs compile`. Do not edit: recompile the source module instead.

use nanvm_lib::vm::unstable::{f64_any, string_any, string_key};
use nanvm_lib::vm::{Any, Array, IStaticFunction, ToAny, ToObject};

#[rustfmt::skip]
#[allow(clippy::if_same_then_else)]
pub fn module<A: IStaticFunction>(_runtime: Any<A>) -> Result<Any<A>, Any<A>> {
    Ok([(string_key("default"), A::static_function(|_self, _args| {
        let _b524: Any<A> = _args.rest(0).to_any();
        (((string_any("Hello, ") + ((Any::dot(_b524.clone(), f64_any(0x0000000000000000)).end())?.to_string().map(|v| v.to_any()))?)? + string_any(" world"))? + ((if Any::<A>::to_boolean(&(Any::gt((Any::dot(_b524.clone(), f64_any(0x0000000000000000)).end())?, f64_any(0x3ff0000000000000)))?) { string_any("s") } else { string_any("") }).to_string().map(|v| v.to_any()))?)? + string_any("!")
    }, 0, Array::default(), Some("(...$0)=>\"Hello, \"+String($0[0])+\" world\"+String($0[0]>1?\"s\":\"\")+\"!\"")).to_any())].to_object().to_any())
}

WebAssembly text (WAT) of the functions compiled from this source, without the NaNVM runtime:

  (func $nanvm_demos::samples::template_literals::module::<nanvm_lib::naive::Naive> (;385;) (type 1) (param i32 i32)
    (local i32 i32 i32 i32 i32)
    global.get $__stack_pointer
    i32.const 96
    i32.sub
    local.tee 2
    global.set $__stack_pointer
    local.get 2
    i32.const 0
    i32.store16 offset=28
    local.get 2
    i32.const 1060844
    i32.store offset=24
    local.get 2
    i32.const 1060837
    i32.store offset=20
    local.get 2
    i32.const 48
    i32.add
    local.get 2
    i32.const 20
    i32.add
    call $"core::iter::adapters::try_process::<core::iter::adapters::map::Map<core::str::iter::EncodeUtf16, core::result::Result<u16, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>::Ok>, u16, core::result::Result<core::convert::Infallible, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>, <core::result::Result<alloc::rc::Rc<[u16]>, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>> as core::iter::traits::collect::FromIterator<core::result::Result<u16, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>>>::from_iter<core::iter::adapters::map::Map<core::str::iter::EncodeUtf16, core::result::Result<u16, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>::Ok>>::{closure#0}, alloc::rc::Rc<[u16]>>"
    block ;; label = @1
      block ;; label = @2
        block ;; label = @3
          local.get 2
          i32.load8_u offset=48
          local.tee 3
          i32.const 255
          i32.ne
          br_if 0 (;@3;)
          local.get 2
          i32.load offset=56
          local.set 4
          local.get 2
          i32.load offset=52
          local.set 5
          local.get 2
          i32.const 0
          i32.store8 offset=32
          local.get 2
          i32.const 8
          i32.add
          local.get 2
          i32.const 32
          i32.add
          call $"<core::iter::adapters::GenericShunt<core::iter::adapters::map::Map<core::iter::sources::empty::Empty<nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>, core::result::Result<nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>, ()>::Ok>, core::result::Result<core::convert::Infallible, ()>> as alloc::rc::ToRcSlice<nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>>::to_rc_slice"
          local.get 2
          local.get 2
          i32.load offset=12
          local.tee 6
          i32.store offset=52
          local.get 2
          local.get 2
          i32.load offset=8
          local.tee 3
          i32.store offset=48
          block ;; label = @4
            local.get 2
            i32.load8_u offset=32
            i32.const 1
            i32.ne
            br_if 0 (;@4;)
            local.get 3
            local.get 3
            i32.load
            i32.const -1
            i32.add
            local.tee 0
            i32.store
            local.get 0
            br_if 3 (;@1;)
            local.get 2
            i32.const 48
            i32.add
            call $"<alloc::rc::Rc<[nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>]>>::drop_slow"
            br 3 (;@1;)
          end
          local.get 3
          i32.eqz
          br_if 2 (;@1;)
          i32.const 73
          i32.const 0
          local.get 3
          local.get 6
          i32.const 1060900
          i32.const 68
          call $"<nanvm_lib::naive::Naive as nanvm_lib::vm::internal::IVm>::static_function"
          local.set 3
          local.get 2
          i32.const 0
          i32.store8 offset=20
          local.get 2
          local.get 3
          i32.store offset=68
          local.get 2
          i32.const 7
          i32.store8 offset=64
          local.get 2
          local.get 4
          i32.store offset=60
          local.get 2
          local.get 5
          i32.store offset=56
          local.get 2
          i64.const 4294967296
          i64.store offset=48
          local.get 2
          local.get 2
          i32.const 20
          i32.add
          i32.store offset=80
          local.get 2
          local.get 2
          i32.const 48
          i32.add
          call $"<core::iter::adapters::GenericShunt<core::iter::adapters::map::Map<core::array::iter::IntoIter<(nanvm_lib::vm::string::String<nanvm_lib::naive::Naive>, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>), 1>, core::result::Result<(nanvm_lib::vm::string::String<nanvm_lib::naive::Naive>, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>), ()>::Ok>, core::result::Result<core::convert::Infallible, ()>> as alloc::rc::ToRcSlice<(nanvm_lib::vm::string::String<nanvm_lib::naive::Naive>, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>)>>::to_rc_slice"
          local.get 2
          local.get 2
          i32.load offset=4
          local.tee 4
          i32.store offset=36
          local.get 2
          local.get 2
          i32.load
          local.tee 3
          i32.store offset=32
          block ;; label = @4
            local.get 2
            i32.load8_u offset=20
            i32.const 1
            i32.ne
            br_if 0 (;@4;)
            local.get 3
            local.get 3
            i32.load
            i32.const -1
            i32.add
            local.tee 0
            i32.store
            local.get 0
            br_if 2 (;@2;)
            local.get 2
            i32.const 32
            i32.add
            call $"<alloc::rc::Rc<[(nanvm_lib::vm::string::String<nanvm_lib::naive::Naive>, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>)]>>::drop_slow"
            br 2 (;@2;)
          end
          local.get 3
          i32.eqz
          br_if 1 (;@2;)
          local.get 0
          local.get 4
          i32.store offset=16
          local.get 0
          local.get 3
          i32.store offset=12
          local.get 0
          i32.const 5
          i32.store8 offset=8
          local.get 0
          i64.const 0
          i64.store
          local.get 1
          call $"#func379 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
          local.get 2
          i32.const 96
          i32.add
          global.set $__stack_pointer
          return
        end
        local.get 2
        local.get 2
        i32.load8_u offset=51
        i32.store8 offset=35
        local.get 2
        local.get 2
        i32.load16_u offset=49 align=1
        i32.store16 offset=33 align=1
        local.get 2
        local.get 2
        i32.load offset=60
        i32.store offset=44
        local.get 2
        local.get 2
        i64.load offset=52 align=4
        i64.store offset=36 align=4
        local.get 2
        local.get 3
        i32.store8 offset=32
        i32.const 1057960
        i32.const 43
        local.get 2
        i32.const 32
        i32.add
        i32.const 1057944
        i32.const 1058004
        call $core::result::unwrap_failed
        unreachable
      end
      i32.const 1064316
      i32.const 43
      local.get 2
      i32.const 95
      i32.add
      i32.const 1064300
      i32.const 1064360
      call $core::result::unwrap_failed
      unreachable
    end
    i32.const 1064316
    i32.const 43
    local.get 2
    i32.const 95
    i32.add
    i32.const 1064300
    i32.const 1064360
    call $core::result::unwrap_failed
    unreachable
  )
  (func $"<nanvm_demos::samples::template_literals::module<nanvm_lib::naive::Naive>::{closure#0} as core::ops::function::FnOnce<(&nanvm_lib::naive::function::Function, nanvm_lib::vm::array::Array<nanvm_lib::naive::Naive>)>>::call_once" (;386;) (type 4) (param i32 i32 i32 i32)
    (local i32 i32 i64 i32 i32)
    global.get $__stack_pointer
    i32.const 368
    i32.sub
    local.tee 4
    global.set $__stack_pointer
    local.get 4
    local.get 3
    i32.store offset=36
    local.get 4
    local.get 2
    i32.store offset=32
    local.get 2
    local.get 2
    i32.load
    i32.const 1
    i32.add
    local.tee 5
    i32.store
    block ;; label = @1
      local.get 5
      i32.eqz
      br_if 0 (;@1;)
      local.get 4
      local.get 3
      i32.store offset=48
      local.get 4
      local.get 2
      i32.store offset=44
      local.get 4
      i32.const 6
      i32.store8 offset=40
      local.get 4
      i32.const 0
      i32.store16 offset=360
      local.get 4
      i32.const 1060975
      i32.store offset=356
      local.get 4
      i32.const 1060968
      i32.store offset=352
      local.get 4
      i32.const 320
      i32.add
      local.get 4
      i32.const 352
      i32.add
      call $"core::iter::adapters::try_process::<core::iter::adapters::map::Map<core::str::iter::EncodeUtf16, core::result::Result<u16, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>::Ok>, u16, core::result::Result<core::convert::Infallible, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>, <core::result::Result<alloc::rc::Rc<[u16]>, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>> as core::iter::traits::collect::FromIterator<core::result::Result<u16, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>>>::from_iter<core::iter::adapters::map::Map<core::str::iter::EncodeUtf16, core::result::Result<u16, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>::Ok>>::{closure#0}, alloc::rc::Rc<[u16]>>"
      block ;; label = @2
        block ;; label = @3
          block ;; label = @4
            local.get 4
            i32.load8_u offset=320
            local.tee 3
            i32.const 255
            i32.ne
            br_if 0 (;@4;)
            local.get 4
            local.get 4
            i64.load offset=324 align=4
            i64.store offset=212 align=4
            local.get 4
            i32.const 3
            i32.store8 offset=208
            block ;; label = @5
              block ;; label = @6
                block ;; label = @7
                  block ;; label = @8
                    block ;; label = @9
                      block ;; label = @10
                        block ;; label = @11
                          block ;; label = @12
                            local.get 4
                            i32.load8_u offset=40
                            local.tee 5
                            br_table 6 (;@6;) 6 (;@6;) 0 (;@12;) 1 (;@11;) 2 (;@10;) 3 (;@9;) 4 (;@8;) 5 (;@7;) 6 (;@6;)
                          end
                          local.get 4
                          i64.load offset=48
                          local.set 6
                          br 9 (;@2;)
                        end
                        local.get 4
                        i32.load offset=44
                        local.tee 3
                        local.get 3
                        i32.load
                        i32.const 1
                        i32.add
                        local.tee 7
                        i32.store
                        local.get 7
                        i32.eqz
                        br_if 9 (;@1;)
                        br 7 (;@3;)
                      end
                      local.get 4
                      i32.load offset=44
                      local.tee 3
                      local.get 3
                      i32.load
                      i32.const 1
                      i32.add
                      local.tee 7
                      i32.store
                      local.get 7
                      i32.eqz
                      br_if 8 (;@1;)
                      local.get 4
                      i64.load8_u offset=52
                      i64.const 32
                      i64.shl
                      local.get 4
                      i64.load32_u offset=48
                      i64.or
                      local.set 6
                      br 7 (;@2;)
                    end
                    local.get 4
                    i32.load offset=44
                    local.tee 3
                    local.get 3
                    i32.load
                    i32.const 1
                    i32.add
                    local.tee 7
                    i32.store
                    local.get 7
                    br_if 5 (;@3;)
                    br 7 (;@1;)
                  end
                  local.get 4
                  i32.load offset=44
                  local.tee 3
                  local.get 3
                  i32.load
                  i32.const 1
                  i32.add
                  local.tee 7
                  i32.store
                  local.get 7
                  br_if 4 (;@3;)
                  br 6 (;@1;)
                end
                local.get 4
                i32.load offset=44
                local.tee 3
                local.get 3
                i32.load
                i32.const 1
                i32.add
                local.tee 7
                i32.store
                local.get 7
                i32.eqz
                br_if 5 (;@1;)
                br 1 (;@5;)
              end
              local.get 4
              i32.load8_u offset=41
              local.set 7
            end
            br 2 (;@2;)
          end
          local.get 4
          local.get 4
          i32.load8_u offset=323
          i32.store8 offset=243
          local.get 4
          local.get 4
          i32.load16_u offset=321 align=1
          i32.store16 offset=241 align=1
          local.get 4
          local.get 4
          i32.load offset=332
          i32.store offset=252
          local.get 4
          local.get 4
          i64.load offset=324 align=4
          i64.store offset=244 align=4
          local.get 4
          local.get 3
          i32.store8 offset=240
          i32.const 1057960
          i32.const 43
          local.get 4
          i32.const 240
          i32.add
          i32.const 1057944
          i32.const 1058004
          call $core::result::unwrap_failed
          unreachable
        end
        local.get 4
        i64.load32_u offset=48
        local.set 6
      end
      local.get 4
      local.get 6
      i64.store offset=360
      local.get 4
      local.get 3
      i32.store offset=356
      local.get 4
      local.get 7
      i32.store8 offset=353
      local.get 4
      local.get 5
      i32.store8 offset=352
      local.get 4
      i64.const 0
      i64.store offset=328
      local.get 4
      i32.const 2
      i32.store8 offset=320
      local.get 4
      i32.const 240
      i32.add
      local.get 4
      i32.const 352
      i32.add
      local.get 4
      i32.const 320
      i32.add
      call $<nanvm_lib::vm::lambda::member::Member<nanvm_lib::naive::Naive>>::new
      block ;; label = @2
        block ;; label = @3
          block ;; label = @4
            block ;; label = @5
              local.get 4
              i32.load8_u offset=240
              i32.const 255
              i32.ne
              br_if 0 (;@5;)
              local.get 0
              local.get 4
              i64.load offset=256
              i64.store offset=16
              local.get 0
              local.get 4
              i64.load offset=248
              i64.store offset=8
              local.get 0
              i64.const 1
              i64.store
              local.get 4
              i32.const 208
              i32.add
              call $"#func379 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
              br 1 (;@4;)
            end
            local.get 4
            local.get 4
            i64.load offset=264
            i64.store offset=344
            local.get 4
            local.get 4
            i64.load offset=256
            i64.store offset=336
            local.get 4
            local.get 4
            i64.load offset=248
            i64.store offset=328
            local.get 4
            local.get 4
            i64.load offset=240
            i64.store offset=320
            local.get 4
            i32.const 352
            i32.add
            local.get 4
            i32.const 320
            i32.add
            call $<nanvm_lib::vm::lambda::member::Member<nanvm_lib::naive::Naive>>::own
            block ;; label = @5
              block ;; label = @6
                local.get 4
                i32.load8_u offset=352
                i32.const 255
                i32.eq
                br_if 0 (;@6;)
                local.get 4
                local.get 4
                i64.load offset=360
                i64.store offset=280
                local.get 4
                local.get 4
                i64.load offset=352
                i64.store offset=272
                br 1 (;@5;)
              end
              local.get 4
              i32.const 256
              i32.store16 offset=272
            end
            local.get 4
            i32.const 320
            i32.add
            call $"#func693 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
            local.get 4
            i32.const 336
            i32.add
            call $"#func693 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
            local.get 4
            i32.const 224
            i32.add
            local.get 4
            i32.const 272
            i32.add
            call $<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>::dispatch::<nanvm_lib::vm::primitive_dispatch::ViaPrimitive<nanvm_lib::vm::string_coercion::StringCoercion>>
            block ;; label = @5
              local.get 4
              i32.load8_u offset=224
              local.tee 3
              i32.const 255
              i32.eq
              br_if 0 (;@5;)
              local.get 0
              local.get 4
              i32.load8_u offset=227
              i32.store8 offset=11
              local.get 0
              local.get 4
              i32.load16_u offset=225 align=1
              i32.store16 offset=9 align=1
              local.get 4
              i64.load offset=228 align=4
              local.set 6
              local.get 0
              local.get 4
              i32.load offset=236
              i32.store offset=20
              local.get 0
              local.get 6
              i64.store offset=12 align=4
              local.get 0
              local.get 3
              i32.store8 offset=8
              local.get 0
              i64.const 1
              i64.store
              local.get 4
              i32.const 208
              i32.add
              call $"#func379 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
              br 1 (;@4;)
            end
            local.get 4
            local.get 4
            i64.load offset=228 align=4
            i64.store offset=156 align=4
            local.get 4
            i32.const 3
            i32.store8 offset=152
            local.get 4
            i32.const 288
            i32.add
            local.get 4
            i32.const 208
            i32.add
            local.get 4
            i32.const 152
            i32.add
            call $"<nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive> as core::ops::arith::Add>::add"
            local.get 4
            local.get 4
            i64.load offset=296
            i64.store offset=136
            local.get 4
            local.get 4
            i64.load offset=304
            i64.store offset=144
            block ;; label = @5
              local.get 4
              i64.load offset=288
              i64.const 1
              i64.ne
              br_if 0 (;@5;)
              local.get 0
              local.get 4
              i64.load offset=144
              i64.store offset=16
              local.get 0
              local.get 4
              i64.load offset=136
              i64.store offset=8
              local.get 0
              i64.const 1
              i64.store
              br 1 (;@4;)
            end
            local.get 4
            local.get 4
            i64.load offset=144
            i64.store offset=176
            local.get 4
            local.get 4
            i64.load offset=136
            i64.store offset=168
            local.get 4
            i32.const 0
            i32.store16 offset=360
            local.get 4
            i32.const 1060981
            i32.store offset=356
            local.get 4
            i32.const 1060975
            i32.store offset=352
            local.get 4
            i32.const 320
            i32.add
            local.get 4
            i32.const 352
            i32.add
            call $"core::iter::adapters::try_process::<core::iter::adapters::map::Map<core::str::iter::EncodeUtf16, core::result::Result<u16, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>::Ok>, u16, core::result::Result<core::convert::Infallible, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>, <core::result::Result<alloc::rc::Rc<[u16]>, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>> as core::iter::traits::collect::FromIterator<core::result::Result<u16, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>>>::from_iter<core::iter::adapters::map::Map<core::str::iter::EncodeUtf16, core::result::Result<u16, nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>>::Ok>>::{closure#0}, alloc::rc::Rc<[u16]>>"
            block ;; label = @5
              block ;; label = @6
                block ;; label = @7
                  local.get 4
                  i32.load8_u offset=320
                  local.tee 3
                  i32.const 255
                  i32.ne
                  br_if 0 (;@7;)
                  local.get 4
                  local.get 4
                  i64.load offset=324 align=4
                  i64.store offset=292 align=4
                  local.get 4
                  i32.const 3
                  i32.store8 offset=288
                  local.get 4
                  i32.const 112
                  i32.add
                  local.get 4
                  i32.const 168
                  i32.add
                  local.get 4
                  i32.const 288
                  i32.add
                  call $"<nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive> as core::ops::arith::Add>::add"
                  local.get 4
                  local.get 4
                  i64.load offset=120
                  i64.store offset=96
                  local.get 4
                  local.get 4
                  i64.load offset=128
                  i64.store offset=104
                  block ;; label = @8
                    local.get 4
                    i64.load offset=112
                    i64.const 1
                    i64.ne
                    br_if 0 (;@8;)
                    local.get 0
                    local.get 4
                    i64.load offset=104
                    i64.store offset=16
                    local.get 0
                    local.get 4
                    i64.load offset=96
                    i64.store offset=8
                    local.get 0
                    i64.const 1
                    i64.store
                    br 4 (;@4;)
                  end
                  local.get 4
                  local.get 4
                  i64.load offset=104
                  i64.store offset=88
                  local.get 4
                  local.get 4
                  i64.load offset=96
                  i64.store offset=80
                  block ;; label = @8
                    block ;; label = @9
                      block ;; label = @10
                        block ;; label = @11
                          block ;; label = @12
                            block ;; label = @13
                              block ;; label = @14
                                block ;; label = @15
                                  local.get 4
                                  i32.load8_u offset=40
                                  local.tee 5
                                  br_table 6 (;@9;) 6 (;@9;) 0 (;@15;) 1 (;@14;) 2 (;@13;) 3 (;@12;) 4 (;@11;) 5 (;@10;) 6 (;@9;)
                                end
                                local.get 4
                                i64.load offset=48
                                local.set 6
                                br 9 (;@5;)
                              end
                              local.get 4
                              i32.load offset=44
                              local.tee 3
                              local.get 3
                              i32.load
                              i32.const 1
                              i32.add
                              local.tee 7
                              i32.store
                              local.get 7
                              i32.eqz
                              br_if 12 (;@1;)
                              br 7 (;@6;)
                            end
                            local.get 4
                            i32.load offset=44
                            local.tee 3
                            local.get 3
                            i32.load
                            i32.const 1
                            i32.add
                            local.tee 7
                            i32.store
                            local.get 7
                            i32.eqz
                            br_if 11 (;@1;)
                            local.get 4
                            i64.load8_u offset=52
                            i64.const 32
                            i64.shl
                            local.get 4
                            i64.load32_u offset=48
                            i64.or
                            local.set 6
                            br 7 (;@5;)
                          end
                          local.get 4
                          i32.load offset=44
                          local.tee 3
                          local.get 3
                          i32.load
                          i32.const 1
                          i32.add
                          local.tee 7
                          i32.store
                          local.get 7
                          i32.eqz
                          br_if 10 (;@1;)
                          br 5 (;@6;)
                        end
                        local.get 4
                        i32.load offset=44
                        local.tee 3
                        local.get 3
                        i32.load
                        i32.const 1
                        i32.add
                        local.tee 7
                        i32.store
                        local.get 7
                        i32.eqz
                        br_if 9 (;@1;)
                        br 4 (;@6;)
                      end
                      local.get 4
                      i32.load offset=44
                      local.tee 3
                      local.get 3
                      i32.load
                      i32.const 1
                      i32.add
                      local.tee 7
                      i32.store
                      local.get 7
                      i32.eqz
                      br_if 8 (;@1;)
                      br 1 (;@8;)
                    end
                    local.get 4
                    i32.load8_u offset=41
                    local.set 7
                  end
                  br 2 (;@5;)
                end
                local.get 4
                local.get 4
                i32.load8_u offset=323
                i32.store8 offset=291
                local.get 4
                local.get 4
                i32.load16_u offset=321 align=1
                i32.store16 offset=289 align=1
                local.get 4
                local.get 4
                i32.load offset=332
                i32.store offset=300
                local.get 4
                local.get 4
                i64.load offset=324 align=4
                i64.store offset=292 align=4
                local.get 4
                local.get 3
                i32.store8 offset=288
                i32.const 1057960
                i32.const 43
                local.get 4
                i32.const 288
                i32.add
                i32.const 1057944
                i32.const 1058004
                call $core::result::unwrap_failed
                unreachable
              end
              local.get 4
              i64.load32_u offset=48
              local.set 6
            end
            local.get 4
            local.get 6
            i64.store offset=120
            local.get 4
            local.get 3
            i32.store offset=116
            local.get 4
            local.get 7
            i32.store8 offset=113
            local.get 4
            local.get 5
            i32.store8 offset=112
            local.get 4
            i64.const 0
            i64.store offset=328
            local.get 4
            i32.const 2
            i32.store8 offset=320
            local.get 4
            i32.const 288
            i32.add
            local.get 4
            i32.const 112
            i32.add
            local.get 4
            i32.const 320
            i32.add
            call $<nanvm_lib::vm::lambda::member::Member<nanvm_lib::naive::Naive>>::new
            block ;; label = @5
              block ;; label = @6
                block ;; label = @7
                  local.get 4
                  i32.load8_u offset=288
                  i32.const 255
                  i32.ne
                  br_if 0 (;@7;)
                  local.get 0
                  local.get 4
                  i64.load offset=304
                  i64.store offset=16
                  local.get 0
                  local.get 4
                  i64.load offset=296
                  i64.store offset=8
                  br 1 (;@6;)
                end
                local.get 4
                local.get 4
                i64.load offset=312
                i64.store offset=344
                local.get 4
                local.get 4
                i64.load offset=304
                i64.store offset=336
                local.get 4
                local.get 4
                i64.load offset=296
                i64.store offset=328
                local.get 4
                local.get 4
                i64.load offset=288
                i64.store offset=320
                local.get 4
                i32.const 112
                i32.add
                local.get 4
                i32.const 320
                i32.add
                call $<nanvm_lib::vm::lambda::member::Member<nanvm_lib::naive::Naive>>::own
                block ;; label = @7
                  block ;; label = @8
                    local.get 4
                    i32.load8_u offset=112
                    i32.const 255
                    i32.eq
                    br_if 0 (;@8;)
                    local.get 4
                    local.get 4
                    i64.load offset=120
                    i64.store offset=216
                    local.get 4
                    local.get 4
                    i64.load offset=112
                    i64.store offset=208
                    br 1 (;@7;)
                  end
                  local.get 4
                  i32.const 256
                  i32.store16 offset=208
                end
                local.get 4
                i32.const 320
                i32.add
                call $"#func693 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
                local.get 4
                i32.const 336
                i32.add
                call $"#func693 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
                local.get 4
                i64.const 4607182418800017408
                i64.store offset=120
                local.get 4
                i32.const 2
                i32.store8 offset=112
                local.get 4
                i32.const 320
                i32.add
                local.get 4
                i32.const 208
                i32.add
                local.get 4
                i32.const 112
                i32.add
                call $nanvm_lib::vm::any::relational::compare::<nanvm_lib::naive::Naive>
                local.get 4
                i32.load8_u offset=321
                local.set 3
                local.get 4
                i32.load8_u offset=320
                local.tee 5
                i32.const 255
                i32.eq
                br_if 1 (;@5;)
                local.get 0
                local.get 4
                i64.load offset=328 align=2
                i64.store offset=16 align=2
                local.get 0
                local.get 4
                i64.load offset=322 align=2
                i64.store offset=10 align=2
                local.get 0
                local.get 3
                i32.store8 offset=9
                local.get 0
                local.get 5
                i32.store8 offset=8
              end
              local.get 0
              i64.const 1
              i64.store
              local.get 4
              i32.const 80
              i32.add
              call $"#func379 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
              br 1 (;@4;)
            end
            local.get 4
            i32.const 1
            i32.store8 offset=352
            local.get 4
            local.get 3
            i32.const 255
            i32.and
            i32.const 1
            i32.eq
            i32.store8 offset=353
            local.get 4
            i32.const 352
            i32.add
            call $"<nanvm_lib::naive::Naive as nanvm_lib::vm::internal::IVm>::with_unpacked::<bool, <nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>::to_boolean>"
            local.set 3
            local.get 4
            i32.const 352
            i32.add
            call $"#func379 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
            block ;; label = @5
              block ;; label = @6
                local.get 3
                br_if 0 (;@6;)
                local.get 4
                i32.const 0
                i32.store16 offset=328
                local.get 4
                i64.const 4294967297
                i64.store offset=320 align=4
                local.get 4
                i32.const 24
                i32.add
                local.get 4
                i32.const 320
                i32.add
                call $"<core::str::iter::EncodeUtf16 as nanvm_lib::vm::string::to_string::ToString>::to_string::<nanvm_lib::naive::Naive>"
                local.get 4
                i32.load offset=28
                local.set 3
                local.get 4
                i32.load offset=24
                local.set 5
                br 1 (;@5;)
              end
              local.get 4
              i32.const 0
              i32.store16 offset=328
              local.get 4
              i32.const 1060982
              i32.store offset=324
              local.get 4
              i32.const 1060981
              i32.store offset=320
              local.get 4
              i32.const 16
              i32.add
              local.get 4
              i32.const 320
              i32.add
              call $"<core::str::iter::EncodeUtf16 as nanvm_lib::vm::string::to_string::ToString>::to_string::<nanvm_lib::naive::Naive>"
              local.get 4
              i32.load offset=20
              local.set 3
              local.get 4
              i32.load offset=16
              local.set 5
            end
            local.get 4
            local.get 5
            i32.store offset=324
            local.get 4
            i32.const 3
            i32.store8 offset=320
            local.get 4
            local.get 3
            i32.store offset=328
            local.get 4
            i32.const 192
            i32.add
            local.get 4
            i32.const 320
            i32.add
            call $<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>::dispatch::<nanvm_lib::vm::primitive_dispatch::ViaPrimitive<nanvm_lib::vm::string_coercion::StringCoercion>>
            block ;; label = @5
              local.get 4
              i32.load8_u offset=192
              local.tee 5
              i32.const 255
              i32.eq
              br_if 0 (;@5;)
              local.get 4
              local.get 4
              i32.load8_u offset=195
              local.tee 3
              i32.store8 offset=190
              local.get 4
              local.get 4
              i32.load16_u offset=193 align=1
              local.tee 7
              i32.store16 offset=184
              local.get 4
              local.get 3
              i32.store8 offset=186
              local.get 4
              i64.load offset=196 align=4
              local.set 6
              local.get 4
              i32.load offset=204
              local.set 8
              local.get 0
              local.get 5
              i32.store8 offset=8
              local.get 0
              local.get 7
              i32.store16 offset=9 align=1
              local.get 0
              local.get 3
              i32.store8 offset=11
              local.get 0
              local.get 8
              i32.store offset=20
              local.get 0
              local.get 6
              i64.store offset=12 align=4
              local.get 0
              i64.const 1
              i64.store
              local.get 4
              i32.const 80
              i32.add
              call $"#func379 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
              br 1 (;@4;)
            end
            local.get 4
            i32.const 64
            i32.add
            local.set 3
            local.get 4
            local.get 4
            i32.load16_u offset=188
            local.tee 5
            i32.store16 offset=184
            local.get 4
            local.get 4
            i32.load8_u offset=190
            local.tee 7
            i32.store8 offset=186
            local.get 4
            i32.const 3
            i32.store8 offset=224
            local.get 4
            local.get 5
            i32.store16 offset=225 align=1
            local.get 4
            local.get 7
            i32.store8 offset=227
            local.get 4
            local.get 4
            i64.load offset=196 align=4
            i64.store offset=228 align=4
            local.get 4
            i32.const 56
            i32.add
            local.get 4
            i32.const 80
            i32.add
            local.get 4
            i32.const 224
            i32.add
            call $"<nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive> as core::ops::arith::Add>::add"
            block ;; label = @5
              local.get 4
              i64.load offset=56
              i64.const 1
              i64.ne
              br_if 0 (;@5;)
              local.get 0
              i64.const 1
              i64.store
              local.get 0
              local.get 3
              i64.load offset=8
              i64.store offset=16
              local.get 0
              local.get 3
              i64.load
              i64.store offset=8
              br 1 (;@4;)
            end
            local.get 4
            local.get 3
            i64.load offset=8
            i64.store offset=360
            local.get 4
            local.get 3
            i64.load
            i64.store offset=352
            local.get 4
            i32.const 0
            i32.store16 offset=200
            local.get 4
            i32.const 1060983
            i32.store offset=196
            local.get 4
            i32.const 1060982
            i32.store offset=192
            local.get 4
            i32.const 8
            i32.add
            local.get 4
            i32.const 192
            i32.add
            call $"<core::str::iter::EncodeUtf16 as nanvm_lib::vm::string::to_string::ToString>::to_string::<nanvm_lib::naive::Naive>"
            local.get 4
            i32.const 3
            i32.store8 offset=112
            local.get 4
            local.get 4
            i64.load offset=8
            i64.store offset=116 align=4
            local.get 0
            local.get 4
            i32.const 352
            i32.add
            local.get 4
            i32.const 112
            i32.add
            call $"<nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive> as core::ops::arith::Add>::add"
            local.get 4
            i32.const 40
            i32.add
            call $"#func379 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
            local.get 2
            local.get 2
            i32.load
            i32.const -1
            i32.add
            local.tee 0
            i32.store
            local.get 0
            br_if 2 (;@2;)
            br 1 (;@3;)
          end
          local.get 4
          i32.const 40
          i32.add
          call $"#func379 core::ptr::drop_glue::<nanvm_lib::vm::unpacked::Unpacked<nanvm_lib::naive::Naive>>"
          local.get 2
          local.get 2
          i32.load
          i32.const -1
          i32.add
          local.tee 0
          i32.store
          local.get 0
          br_if 1 (;@2;)
        end
        local.get 4
        i32.const 32
        i32.add
        call $"<alloc::rc::Rc<[nanvm_lib::vm::any::Any<nanvm_lib::naive::Naive>]>>::drop_slow"
      end
      local.get 4
      i32.const 368
      i32.add
      global.set $__stack_pointer
      return
    end
    unreachable
  )

Emergent Testing

Idle. Press Run to start the suite.

  • ./proof.f.mjs