Fundamentos del lenguaje
28 pasos en 9 series de WebAssembly.
WebAssembly es el cuarto lenguaje de la web y el destino de compilación portable en el que todos los demás acordaron: una máquina de pila con memoria lineal, cuatro tipos numéricos y un sandbox que no confía en nada. Rust, C, Go y Kotlin compilan a él; navegadores, bordes serverless y sistemas de plugins lo corren. El formato de texto — WAT — es su cara honesta: cada s-expresión de aquí es exactamente una instrucción que el motor ejecuta, lo que lo hace el raro ensamblador que se lee como Lisp.
Este tour teclea el núcleo completo: módulos y exports, estilo de pila contra estilo plegado, instrucciones enteras y flotantes con sus sufijos de signo, locales y tee, if tipado y el trío block/loop/br que construye toda estructura de control, llamadas directas e indirectas por tablas, memoria lineal con segmentos de datos y operaciones en bloque, globales y la función start, imports, y las conversiones que cruzan anchos. El Bis son tres módulos completos — una criba de primos, una cacería del récord de Collatz y un conteo de vocales sobre un segmento de datos — cada uno ejecutable con nada más que wasmtime.
Módulos
- La forma del móduloEl WebAssembly de texto más pequeño: un módulo, una función exportada.
- Parámetros y resultadosLas firmas declaran todo; los $nombres apodan los índices.
- Estilo de pila y estilo plegadoLa misma función dos veces: empujes crudos, luego s-expresiones anidadas.
Números
- Aritmética enteraSin operadores, solo instrucciones — y la división declara su signo.
- ComparacionesLas pruebas devuelven un i32: uno para verdadero, cero para falso.
- Matemática flotanteInstrucciones f64, más el cruce explícito desde los enteros.
Locales y la pila
- LocalesDeclarados al frente, arrancan en cero, se mueven con get y set.
- local.teeGuarda un valor y sigue usándolo, en una sola instrucción.
- drop y selectTira un valor, o elige entre dos sin ramificar.
Control de flujo
- if y elseLas ramas van tipadas: un if con resultado debe llenar ambos brazos.
- block y br_ifLas etiquetas son salidas: br sobre un block salta más allá de su fin.
- loop y brSobre un loop, br salta al tope: esa es toda la historia del while.
Llamadas
- callAyudantes privados por $nombre; solo los exports miran al host.
- RecursiónUna función se llama a sí misma por su propio $nombre.
- Tablas y call_indirectPunteros a función: una tabla de funcref elegida por índice en runtime.
Memoria
- Memoria linealUna corrida plana de bytes, direccionada con aritmética propia.
- Segmentos de datosBytes horneados en la memoria antes de que nada corra.
- memory.size y memory.growLa memoria se cuenta en páginas de 64 KiB, y crece en runtime.
- Memoria en bloqueCopia o rellena corridas enteras de bytes en una instrucción.
Globales y arranque
- GlobalesEstado a nivel de módulo; solo los (mut ...) aceptan escrituras.
- La función startInicialización que corre antes de que un export pueda llamarse.
- ImportsEl módulo declara sus necesidades; el host las provee o no hay trato.
Tipos más anchos
- i64 y cambios de anchoDoblar el ancho es explícito en ambas direcciones.
- Conversionesdestino.op_origen, signo incluido — nada es implícito.
- Resultados múltiplesUna función puede dejar varios valores; quien llama los usa en orden.
Bis
- prime_sieve.watLa criba de Eratóstenes en memoria lineal: 25 primos hasta 100.
- collatz_record.watCorre cada cadena de Collatz bajo 100 y devuelve el récord: 97.
- vowel_count.watRecorre un pasaje en un segmento de datos byte a byte y suma vocales.