Diverso

Layout de las variables de estado en almacenamiento

Variables de tamaño estáticas (todo menos mapping y tipos arrays de tamaño variable) se disponen contiguamente en almacenamiento empezando de la posición 0. Cuando múltiples elementos necesitan menos de 32 bytes, son empaquetados en un slot de almacenamiento cuando es posible de acuerdo a las reglas:

  • El primer elemento en un slot de almacenamiento es almacenado alineado en lower-order.
  • Tipos elementales sólo usan la cantidad de bytes que se necesita para almacenarlos.
  • Si un tipo elemental no cabe en la parte restante de un slot de almacenamiento, es movido al próximo slot de almacenamiento.
  • Structs y datos de array siempre comienzan en un nuevo slot y ocupan slots enteros (pero elementos dentro de un struct o array son empacados estrechamente de acuerdo a estas reglas).

Advertencia

Cuando se usan elementos que son más pequeños que 32 bytes, el uso del gas del contrato puede ser más alto. Esto es porque la EVM opera en 32 bytes a la vez. Por lo tanto, si el elemento es más pequeño que eso, la EVM usa más operaciones para reducir el tamaño del elemento de 32 bytes al tamaño deseado.

Sólo es beneficioso reducir el tamaño de los argumentos si estás tratando con valores de almacenamiento porque el compilador empacará múltiples elementos en un slot de almacenamiento, y entonces, combina múltiples lecturas y escrituras en una sóla operación. Cuando se trata con argumentos de función o valores de memoria, no hay beneficio inherente porque el compilador no empaca estos valores.

Finalmente, para permitir a la EVM optimizar esto, asegúrate de ordenar las variables de almacenamiento y miembros struct para que puedan ser empacados estrechamente. Por ejemplo, declarando tus variables de almacenamiento en el orden de uint128, uint128, uint256 en vez de uint128, uint256, uint128, ya que el primero utilizará sólo dos slots de almacenamiento y éste último tres.

Los elementos de structs y arrays son almacenados después de ellos mismos, como si fueran dados explícitamente.

Dado a su tamaño impredecible, los tipos de array dinámicos y de mapping usan computación hash Keccak-256 para encontrar la posición de inicio del valor o del dato del array. Estas posiciones de inicio son siempre slots completos.

El mapping o el array dinámico en sí ocupa un slot (sin llenar) en alguna posición p de acuerdo a la regla de arriba (o por aplicar esta regla de mappings a mappings o arrays de arrays). Para un array dinámico, este slot guarda el número de elementos en el array (los byte arrays y cadenas son excepciones aquí, mirar abajo). Para un mapping, el slot no es utilizado (pero es necesario para que dos mappings iguales seguidos usen diferentes distribuciones de hash). Datos de array son ubicados en kecakk256(p) y el valor correspondiente a una clave de mapping k es ubicada en kecakk256(k . p) donde . es una concatenación. Si el valor de nuevo es un tipo no elemental, las posiciones son encontradas agregando un offset de keccak256(k . p).

bytes y string almacenan sus datos en el mismo slot junto con su longitud si es corta. En particular: si los datos son al menos 31 bytes de largo, es almacenado en bytes de orden mayor (alineados a la izquierda) y el byte de orden menor almacena length * 2. Si es más largo, el slot principal almacena length * 2 + 1 y los datos son almacenados como siempre en keccak256(slot).

Entonces para el siguiente sinppet de contrato:

contract C {
  struct s { uint a; uint b; }
  uint x;
  mapping(uint => mapping(uint => s)) data;
}

La posición de data[4][9].b está en keccak256(uint256(9) . keccak256(uint256(4) . uint256(1))) + 1.

Layout en memoria

Solidity reserva tres slots de 256-bits:

  • 0 - 64: espacio de scratch para métodos de hash
  • 64 - 96: tamaño de memoria actualmente asignada (también conocida como free memory pointer)

El espacio de scratch puede ser usado entre declaraciones (ej. dento de inline assembly).

Solidity siempre emplaza los nuevos objetos en el puntero de memoria libre y la memoria nunca es liberada (esto puede cambiar en el futuro).

Advertencia

Hay algunas operaciones en Solidity que necesitan un área temporal de memoria mas grande que 64 bytes y por lo tanto no caben en el espacio scratch. Estas operaciones serán emplazadas donde apunta la memoria libre, pero dado su corta vida, el puntero no es actualizado. La memoria puede o no ser puesta a cero. Por esto, uno no debiera esperar que la memoria libre sea puesta a cero.

Layout de Call Data

Cuando un contrato de Solidity es desplegado y cuando es llamado desde una cuenta, los datos de entrada se asume que están en el formato de la especificación ABI. La especificación ABI requiere que los argumentos sean ajustados a múltiplos de 32 bytes. Las llamadas de función internas usan otra convención.

Internas - Limpiando variables

Cuando un valor es más corto que 256-bit, en algunos casos los bits restantes tienen que ser limpiados. El compilador de Solidity está diseñado para limpiar estos bits restantes antes de cualquier operación que pueda ser afectada adversamente por la potencial basura en los bits restantes. Por ejemplo, antes de escribir un valor en la memoria, los bits restantes tienen que ser limpiados porque los contenidos de la memoria pueden ser usados para computar hashes o ser enviados como datos en una llamada. De manera similar, antes de almacenar un valor en el almacenamiento, los bits restantes tienen que ser limpiados porque si no, el valor ilegible puede ser observado.

Por otro lado, no limpiamos los bits si la operación siguiente no es afectada. Por ejemplo, ya que cualquier valor no-cero es considerado true por una instrucción JUMPI, no limpiamos los valores booleanos antes de que sean utilizados como condición para JUMPI.

Además de este principio de diseño, el compilador de Solidity limpia los datos de entrada cuando está cargado en el stack.

Diferentes tipos tienen diferentes reglas para limpiar valores inválidos:

Tipo Valores válidos Val. inv. significan
enum de n miembros 0 hasta n - 1 excepción
bool 0 o 1 1
enteros con signo palabra extendida por signo por ahora envuelve silenciosamente; en el futuro esto arrojará excepciones
enteros sin signos altos bits a cero por ahora envuelve silenciosamente; en el futuro esto arrojará excepciones

Internos - El optimizador

El optimizador de solidity funciona con ensamblador, así que puede y es usado con otros lenguajes. Divide la secuencia de las instrucciones en bloques básicos de JUMPs y JUMPDESTs. Dentro de estos bloques, las instrucciones son analizadas y cada modificación al stack, a la memoria o al almacenamiento son guardadas como una expresión que consiste en una instrucción y una lista de argumentos que son esencialmente punteros a otras expresiones. La idea principal es encontrar expresiones que sean siempre iguales (en cada entrada) y combinarlas a una clase de expresión. El optimizador primero intenta encontrar una nueva expresión en una lista de expresiones conocidas. Si esto no funciona, la expresión es simplificada de acuerdo a reglas como constante + constante = suma_de_constantes o X * 1 = X. Ya que esto es hecho recursivamente, también podemos aplicar la última regla si el segundo factor es una expresión más compleja donde sabemos que siempre evaluará a uno. Modificaciones al almacenamiento y ubicaciones de memoria tienen que borrar el conocimiento de almacenamiento y ubicaciones de memoria que no son conocidas como diferentes: Si primero escribimos a ubicación x y luego a ubicación y y ambas son variables de entrada, la segunda puede sobrescribir la primera, entonces no sabemos realmente lo que es almacenado en x después de escribir a y. Por otro lado, si una simplificación de la expresión x - y evalúa a una constante distinta de cero, sabemos que podemos mantener nuestro conocimiento de lo que es almacenado en x.

Al final de este proceso, sabemos qué expresiones tienen que estar al final del stack y tienen una lista de modificaciones a la memoria y almacenamiento. Esta información es almacenada junto con los bloques básicos y es usada para unirlas. Además, información sobre el stack, almacenamiento y configuración de memoria es enviada al (los) próximo(s) bloque(s). Si sabemos los objetivos de cada una de las instrucciones JUMP y JUMPI, podemos construir un gráfico de flujo completo del programa. Si hay un sólo objetivo que no conocemos (esto puede pasar ya que en principio, los objetivos de jumps pueden ser computados de las entradas), tenemos que borrar toda información sobre los estados de entrada de un bloque ya que puede ser el objetivo del JUMP desconocido. Si se encuentra un JUMPI cuya condición evalúa a una constante, es transformado en un jump incondicional.

Como en el último paso, el código en cada bloque es completamente regenerado. Un gráfico de dependencias es creado de la expresión en el stack al final del bloque y cada operación que no es parte de este gráfico es esencialmente olvidada. Ahora se genera código que aplica las modificaciones a la memoria y al almacenamiento en el orden en que fueron hechas en el código original (olvidando modificaciones que fueron encontradas innecesarias) y finalmente, genera todos los valores que son requeridos para estar en el stack en el lugar correcto.

Estos pasos son aplicados a cada bloque básico y el nuevo código generado se usa como reemplazo si es más pequeño. Si un bloque básico es dividido en un JUMPI y durante el análisis la condición evalúa a una constante, el JUMPI es reemplazado dependiendo del valor de la constante, y por lo tanto código como

var x = 7;
data[7] = 9;
if (data[x] != x + 2)
  return 2;
else
  return 1;

es simplificado a código que también puede ser compilado de

data[7] = 9;
return 1;

aunque las instrucciones contenían un jump en el inicio.

Mappings de fuente

Como parte del AST (Abstract syntax tree) de salida, el compilador provee el rango del código fuente que es representado por el nodo respecto al AST. Esto puede ser usado para varios propósitos desde herramientas de análisis estático que reportan errores basados en el AST y herramientas de debugging que demarcan variables locales y sus usos.

Además, el compilador también puede generar un mapping del bytecode al rango en el código fuente que generó la instrucción. Esto es importante para herramientas de análisis estático que operan a nivel bytecode y para mostrar la posición actual en el código fuente dentro del debugger o para manejar los breakpoints.

Ambos tipos de mappings de fuente usan identificadores enteros para referirse a archivos fuente. Estos son índices de arrays regulares en una lista de archivos fuente habitualmente llamados "sourcelist", que es parte del combined-json y el output del compilador json / npm.

Los mappings de fuente dentro del AST usan la siguiente notación:

s:l:f

Donde s es el byte-offset de el inicio del rango en el archivo fuente, l es el largo del rango de la fuente en bytes y f es el índice de fuente mencionado arriba.

La codificación en el mapping de fuente para el bytecode es más complicada: Es una lista de s:l:f:j separada por ;. Cada una de estos elementos corresponde a una instrucción, i.e. no puedes usar el byte-offset si no que tienes que usar la instrucción offset (las instrucciones push son mas largas que un sólo byte). Los campos s, l y f son como detallamos arriba y j puede ser i, o o - y significa si una instrucción jump va en la función, devuelve desde una función o si es un jump regular como parte de un (ej) bucle.

A fin de comprimir estos mappings de fuente especialmente para bytecode, las siguientes reglas son usadas:

  • Si un campo está vacío, el valor del elemento precedente es usado.
  • Si falta un :, todos los campos siguientes son considerados vacíos.

Esto significa que los siguientes mappings de fuente representan la misma información:

1:2:1;1:9:1;2:1:2;2:1:2;2:1:2

1:2:1;:9;2::2;;

Metadata del contrato

El compilador de Solidity genera automáticamente un archivo JSON, el metadata del contrato, que contiene información sobre el contrato actual. Se puede usar para consultar la versión del compilador, las fuentes usadas, el ABI y documentación NatSpec a fin de interactuar con más seguridad con el contrato y verificar su código fuente.

El compilador agrega un hash Swarm del archivo metadata al final del bytecode (para detalles, mirar abajo) de cada contrato, para que se pueda recuperar el archivo en una manera autentificada sin tener que usar un proveedor de datos centrales.

Sin embargo, se tiene que publicar el archivo metadata a Swarm (o otro servicio) para que otros puedan verlo. El archivo puede ser producido usando solc --metadata y el archivo será llamado NombreContrato_meta.json. Contendrá referencias Swarm al código fuente, así que tienes que subir todos los archivos de código fuente y el archivo metadata.

El archivo metadata tiene el formato siguiente. El ejemplo de abajo es presentado de manera legible por humanos. Los metadatos formateados correctamente deben usar comillas correctamente, reducir el espacio en blanco a un mínimo y ordenarse de manera diferente. Los comentarios obviamente tampoco son permitidos y son usados aquí sólo por razones explicativos.

{
  // Requerido: La versión del formato de metadata
  version: "1",
  // Requerido: lenguaje de código fuente, settea una "sub-versión"
  // de la especificación
  language: "Solidity",
  // Requerido: Detalles del compilador, los contenidos son específicos
  // al lenguaje
  compiler: {
    // Requerido para Solidity: Version del compilador
    version: "0.4.6+commit.2dabbdf0.Emscripten.clang",
    // Opcional: Hash del compilador binario que produjo este resultado
    keccak256: "0x123..."
  },
  // Requerido: Compilación de archivos fuente/unidades fuente, las claves son
  // nombres de archivos
  sources:
  {
    "myFile.sol": {
      // Requerido: keccak256 hash del archivo fuente
      "keccak256": "0x123...",
      // Requerido (al menos que "content" sea usado, ver abajo): URL(s) ordenadas
      // al archivo fuente, el protocolo es menos arbitrario, pero se recomienda una
      // URL de Swarm
      "urls": [ "bzzr://56ab..." ]
    },
    "mortal": {
      // Requerido: hash keccak256 del archivo fuente
      "keccak256": "0x234...",
      // Requerido (al menos que "url" sea usado): contenidos literales del archivo fuente
      "content": "contract mortal is owned { function kill() { if (msg.sender == owner) selfdestruct(owner); } }"
    }
  },
  // Requerido: Configuración del compilador
  settings:
  {
    // Requerido para Solidity: Lista ordenada de remappeos
    remappings: [ ":g/dir" ],
    // Opcional: Configuración del optimizador (por defecto falso)
    optimizer: {
      enabled: true,
      runs: 500
    },
    // Requerido para Solidity: Archivo y nombre del contrato o librería para
    // la librería para el cual es creado este archivo metadata.
    compilationTarget: {
      "myFile.sol": "MyContract"
    },
    // Requerido para Solidity: Direcciones de las librerías usadas
    libraries: {
      "MyLib": "0x123123..."
    }
  },
  // Requerido: Información generada sobre el contrato.
  output:
  {
    // Requerido: definición ABI del contrato
    abi: [ ... ],
    // Requerido: documentación de usuario del contrato de NatSpec
    userdoc: [ ... ],
    // Requerido: documentación de desarrollador del contrato de NatSpec
    devdoc: [ ... ],
  }
}

Nota

Nótese que la definición ABI de arriba no tiene orden fijo. Puede cambiar en distintas versiones del compilador.

Nota

Ya que el bytecode del contrato resultante contiene el hash del metadata, cualquier cambio a la metadata resultará en un cambio en el bytecode. Además, ya que la metadata incluye un hash de todos los fuentes usados, un simple espacio en blanco en cualquiera de los archivos de fuente resultará en un metadata diferente, y posteriormente en bytecode diferente.

Codificación del hash de metadata en el bytecode

Ya que en el futuro puede que soportemos otras maneras de consultar el archivo metadata, el mapping {"bzzr0": <Swarm hash>} es guardado codificado en [CBOR](https://tools.ietf.org/html/rfc7049). Ya que el principio de esa codificación no es fácil de encontrar, la longitud se añade en una codificación two-byte big-endian. La versión actual del compilador de Solidity entonces agrega lo siguiente al final del bytecode desplegado:

0xa1 0x65 'b' 'z' 'z' 'r' '0' 0x58 0x20 <32 bytes swarm hash> 0x00 0x29

Para recuperar estos datos, el final del bytecode desplegado puede ser revisado para ver si coincide con ese patrón y usar el hash de Swarm para recuperar el archivo.

Uso para generar automáticamente la interfaz y NatSpec

El metadata es usado de la siguiente forma: un componente que quiere interactuar con un contrato (ej. Mist) obtiene el código del contrato, a partir de eso el hash de Swarm de un archivo que luego es recuperado. Ese archivo es un JSON con la estructura como la de arriba.

El componente puede luego usar el ABI para generar automáticamente una rudimentaria interfaz de usuario para el contrato.

Además, Mist puede usar el userdoc para mostrar un mensaje de confirmación al usuario cuando interactúe con el contrato.

Uso para la verificación de código fuente

A fin de verificar la compilación, el código fuente pueden ser recuperado de Swarm desde el enlace en el archivo metadata. La versión correcta del compilador (que se comprueba que sea parte de los compiladores “oficiales”) es invocada en esa entrada con la configuración específicada. El resultado bytecode es comparado a los datos de la transacción de creación o a datos del opcode CREATE. Esto verifica automáticamente la metadata ya que su hash es parte del bytecode. Datos en exceso corresponden a los datos de entrada del constructor, que deben ser decodificados de acuerdo a la interfaz y presentados al usuario.

Trucos y consejos

  • Usar delete en arrays para borrar sus elementos.
  • Usar tipos mas cortos para elementos struct y ordenarlos para que los elementos mas cortos estén agrupados. Esto puede disminuir los costes de gas ya que múltiples operaciones SSTORE puden ser combinadas en una sóla (SSTORE cuesta 5000 o 20000 gas, así que esto es lo que se optimiza). ¡Usa el estimador de precio de gas (con optimizador activado) para probar!
  • Hacer las variables de estado públicas - el compilador creará getters automáticamente.
  • Si revisa las condiciones de entrada o de estado muchas veces en el inicio de las funciones, intenta usar Modificadores de funciones.
  • Si tu contrato tiene una función llamada send pero quieres usar la función interna de envío, usa address(contractVariable).send(amount).
  • Inicia structs de almacenamiento con una sola asignación: x = MyStruct({a: 1, b: 2});

Cheatsheet

Orden de preferencia de operadores

El siguiente es el orden de precedencia para operadores, listado en orden de evaluación.

Precedencia Descripción Operador
1 Postfix incremento y decremento ++, --
llamada de tipo función <func>(<args...>)
subíndice de array <array>[<index>]
Acceso de miembro <object>.<member>
Paréntesis (<statement>)
2 Prefijo incremento y decremento ++, --
Más y menos unarios +, -
Operaciones unarias delete
NOT lógico !
NOT a nivel de bits ~
3 Exponenciación **
4 Multiplicación, división and módulo *, /, %
5 Adición and sustracción +, -
6 Desplazamiento de bits <<, >>
7 AND a nivel de bits &
8 XOR a nivel de bits ^
9 OR a nivel de bits |
10 Operadores de desigualdad <, >, <=, >=
11 Operadores de igualdad ==, !=
12 AND lógico &&
13 OR lógico ||
14 Operador ternario <conditional> ? <if-true> : <if-false>
15 Operador de asignación =, |=, ^=, &=, <<=, >>=, +=, -=, *=, /=, %=
16 Operador de coma ,

Variables globales

  • block.blockhash(uint blockNumber) returns (bytes32): hash del bloque dado - sólo funciona para los últimos 256 bloques
  • block.coinbase (address): address del minero del bloque actual
  • block.difficulty (uint): dificultad del bloque actual
  • block.gaslimit (uint): gaslimit del bloque actual
  • block.number (uint): número del bloque actual
  • block.timestamp (uint): timestamp del bloque actual
  • msg.data (bytes): calldata completa
  • msg.gas (uint): gas restante
  • msg.sender (address): sender del mensaje (llamada actual)
  • msg.value (uint): número de wei enviados con el mensaje
  • now (uint): timestamp del bloque actual (alias para block.timestamp)
  • tx.gasprice (uint): precio de gas de la transacción
  • tx.origin (address): sender de la transacción (cadena de llamada completa)
  • assert(bool condition): abortar ejecución y deshacer cambios de estado si la condición es false (uso para error interno)
  • require(bool condition): abortar ejecución y deshacer cambios de estado si la condición es false (uso para entradas erróneas)
  • revert(): abortar ejecución y deshacer cambios de estado
  • keccak256(...) returns (bytes32): computar el hash Ethereum-SHA-3 (Keccak-256) de los argumentos (empacados)
  • sha3(...) returns (bytes32): un alias a keccak256()
  • sha256(...) returns (bytes32): computar el hash SHA-256 de los argumentos (empacados)
  • ripemd160(...) returns (bytes20): computar el hash RIPEMD-160 de los argumentos (empacados)
  • ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address): recuperar address asociada con la llave pública desde la firma de la curva elíptica, devuelve cero en caso de error
  • addmod(uint x, uint y, uint k) returns (uint): computa (x + y) % k donde la suma es hecha con precisión arbitraria y no envuelve 2**256
  • mulmod(uint x, uint y, uint k) returns (uint): computa (x * y) % k donde la multiplicación es hecha con precisión arbitraria y no envuelve 2**256
  • this (tipo del contrato actual): el contrato actual, explícitamente convertible a address
  • super: el contrato un nivel más alto en la jerarquía de herencia
  • selfdestruct(address recipient): destruir el contrato actual, enviando sus fondos al address dada
  • <address>.balance (uint256): saldo de Address en Wei
  • <address>.send(uint256 amount) returns (bool): enviar monto dado de Wei a Address, devuelve false en caso de error
  • <address>.transfer(uint256 amount): enviar monto dado de Wei a Address, arroja excepción si falla

Especificadores de visibilidad de función

function myFunction() <visibility specifier> returns (bool) {
    return true;
}
  • public: visible externa e internamente (crea función getter para almacenamiento/variables de estado)
  • private: sólo visible en el contrato actual
  • external: sólo visible desde el exterior (sólo para funciones) - e.j. sólo puede ser llamado mediante mensajes (via this.func)
  • internal: sólo visible internamente

Modificadores

  • constant para variables de estado: no permite asignaciones (excepto inicialización), no ocupa un slot de almacenamiento.
  • constant para funciones: no permite modificación de estado - no está forzado aún.
  • anonymous para eventos: no guarda la firma del evento como topic.
  • indexed para parámetros de eventos: guarda el parámetro como topic.
  • payable para funciones: les permite recibir ether junto a una llamada.

Keywords reservadas

Estas palabras están reservadas en Solidity. Pueden incorporarse a la sintaxis en el futuro:

abstract, after, case, catch, default, final, in, inline, interface, let, match, null, of, pure, relocatable, static, switch, try, type, typeof, view.

Gramática del lenguaje

SourceUnit = (PragmaDirective | ImportDirective | ContractDefinition)*

// Pragma actually parses anything up to the trailing ';' to be fully forward-compatible.
PragmaDirective = 'pragma' Identifier ([^;]+) ';'

ImportDirective = 'import' StringLiteral ('as' Identifier)? ';'
        | 'import' ('*' | Identifier) ('as' Identifier)? 'from' StringLiteral ';'
        | 'import' '{' Identifier ('as' Identifier)? ( ',' Identifier ('as' Identifier)? )* '}' 'from' StringLiteral ';'

ContractDefinition = ( 'contract' | 'library' | 'interface' ) Identifier
                     ( 'is' InheritanceSpecifier (',' InheritanceSpecifier )* )?
                     '{' ContractPart* '}'

ContractPart = StateVariableDeclaration | UsingForDeclaration
             | StructDefinition | ModifierDefinition | FunctionDefinition | EventDefinition | EnumDefinition

InheritanceSpecifier = UserDefinedTypeName ( '(' Expression ( ',' Expression )* ')' )?

StateVariableDeclaration = TypeName ( 'public' | 'internal' | 'private' )? Identifier ('=' Expression)? ';'
UsingForDeclaration = 'using' Identifier 'for' ('*' | TypeName) ';'
StructDefinition = 'struct' Identifier '{'
                     ( VariableDeclaration ';' (VariableDeclaration ';')* )? '}'
ModifierDefinition = 'modifier' Identifier ParameterList? Block
FunctionDefinition = 'function' Identifier? ParameterList
                     ( FunctionCall | Identifier | 'constant' | 'payable' | 'external' | 'public' | 'internal' | 'private' )*
                     ( 'returns' ParameterList )? ( ';' | Block )
EventDefinition = 'event' Identifier IndexedParameterList 'anonymous'? ';'

EnumValue = Identifier
EnumDefinition = 'enum' Identifier '{' EnumValue? (',' EnumValue)* '}'

IndexedParameterList = '(' ( TypeName 'indexed'? Identifier? (',' TypeName 'indexed'? Identifier?)* )? ')'
ParameterList =        '(' ( TypeName            Identifier? (',' TypeName            Identifier?)* )? ')'
TypeNameList =         '(' ( TypeName (',' TypeName )* )? ')'

// semantic restriction: mappings and structs (recursively) containing mappings
// are not allowed in argument lists
VariableDeclaration = TypeName StorageLocation? Identifier

TypeName = ElementaryTypeName
         | UserDefinedTypeName
         | Mapping
         | ArrayTypeName
         | FunctionTypeName

UserDefinedTypeName = Identifier ( '.' Identifier )*

Mapping = 'mapping' '(' ElementaryTypeName '=>' TypeName ')'
ArrayTypeName = TypeName '[' Expression? ']'
FunctionTypeName = 'function' TypeNameList ( 'internal' | 'external' | 'constant' | 'payable' )*
                   ( 'returns' TypeNameList )?
StorageLocation = 'memory' | 'storage'

Block = '{' Statement* '}'
Statement = IfStatement | WhileStatement | ForStatement | Block | InlineAssemblyStatement |
            ( DoWhileStatement | PlaceholderStatement | Continue | Break | Return |
              Throw | SimpleStatement ) ';'

ExpressionStatement = Expression
IfStatement = 'if' '(' Expression ')' Statement ( 'else' Statement )?
WhileStatement = 'while' '(' Expression ')' Statement
PlaceholderStatement = '_'
SimpleStatement = VariableDefinition | ExpressionStatement
ForStatement = 'for' '(' (SimpleStatement)? ';' (Expression)? ';' (ExpressionStatement)? ')' Statement
InlineAssemblyStatement = 'assembly' StringLiteral? InlineAssemblyBlock
DoWhileStatement = 'do' Statement 'while' '(' Expression ')'
Continue = 'continue'
Break = 'break'
Return = 'return' Expression?
Throw = 'throw'
VariableDefinition = ('var' IdentifierList | VariableDeclaration) ( '=' Expression )?
IdentifierList = '(' ( Identifier? ',' )* Identifier? ')'

// Precedence by order (see github.com/ethereum/solidity/pull/732)
Expression =
  ( Expression ('++' | '--') | FunctionCall | IndexAccess | MemberAccess | '(' Expression ')' )
  | ('!' | '~' | 'delete' | '++' | '--' | '+' | '-') Expression
  | Expression '**' Expression
  | Expression ('*' | '/' | '%') Expression
  | Expression ('+' | '-') Expression
  | Expression ('<<' | '>>') Expression
  | Expression '&' Expression
  | Expression '^' Expression
  | Expression '|' Expression
  | Expression ('<' | '>' | '<=' | '>=') Expression
  | Expression ('==' | '!=') Expression
  | Expression '&&' Expression
  | Expression '||' Expression
  | Expression '?' Expression ':' Expression
  | Expression ('=' | '|=' | '^=' | '&=' | '<<=' | '>>=' | '+=' | '-=' | '*=' | '/=' | '%=') Expression
  | Expression? (',' Expression)
  | PrimaryExpression

PrimaryExpression = Identifier
                  | BooleanLiteral
                  | NumberLiteral
                  | HexLiteral
                  | StringLiteral
                  | ElementaryTypeNameExpression

ExpressionList = Expression ( ',' Expression )*
NameValueList = Identifier ':' Expression ( ',' Identifier ':' Expression )*

FunctionCall = ( PrimaryExpression | NewExpression | TypeName ) ( ( '.' Identifier ) | ( '[' Expression ']' ) )* '(' FunctionCallArguments ')'
FunctionCallArguments = '{' NameValueList? '}'
                      | ExpressionList?

NewExpression = 'new' TypeName
MemberAccess = Expression '.' Identifier
IndexAccess = Expression '[' Expression? ']'

BooleanLiteral = 'true' | 'false'
NumberLiteral = ( HexNumber | DecimalNumber ) (' ' NumberUnit)?
NumberUnit = 'wei' | 'szabo' | 'finney' | 'ether'
           | 'seconds' | 'minutes' | 'hours' | 'days' | 'weeks' | 'years'
HexLiteral = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')
StringLiteral = '"' ([^"\r\n\\] | '\\' .)* '"'
Identifier = [a-zA-Z_$] [a-zA-Z_$0-9]*

HexNumber = '0x' [0-9a-fA-F]+
DecimalNumber = [0-9]+

ElementaryTypeNameExpression = ElementaryTypeName

ElementaryTypeName = 'address' | 'bool' | 'string' | 'var'
                   | Int | Uint | Byte | Fixed | Ufixed

Int = 'int' | 'int8' | 'int16' | 'int24' | 'int32' | 'int40' | 'int48' | 'int56' | 'int64' | 'int72' | 'int80' | 'int88' | 'int96' | 'int104' | 'int112' | 'int120' | 'int128' | 'int136' | 'int144' | 'int152' | 'int160' | 'int168' | 'int176' | 'int184' | 'int192' | 'int200' | 'int208' | 'int216' | 'int224' | 'int232' | 'int240' | 'int248' | 'int256'

Uint = 'uint' | 'uint8' | 'uint16' | 'uint24' | 'uint32' | 'uint40' | 'uint48' | 'uint56' | 'uint64' | 'uint72' | 'uint80' | 'uint88' | 'uint96' | 'uint104' | 'uint112' | 'uint120' | 'uint128' | 'uint136' | 'uint144' | 'uint152' | 'uint160' | 'uint168' | 'uint176' | 'uint184' | 'uint192' | 'uint200' | 'uint208' | 'uint216' | 'uint224' | 'uint232' | 'uint240' | 'uint248' | 'uint256'

Byte = 'byte' | 'bytes' | 'bytes1' | 'bytes2' | 'bytes3' | 'bytes4' | 'bytes5' | 'bytes6' | 'bytes7' | 'bytes8' | 'bytes9' | 'bytes10' | 'bytes11' | 'bytes12' | 'bytes13' | 'bytes14' | 'bytes15' | 'bytes16' | 'bytes17' | 'bytes18' | 'bytes19' | 'bytes20' | 'bytes21' | 'bytes22' | 'bytes23' | 'bytes24' | 'bytes25' | 'bytes26' | 'bytes27' | 'bytes28' | 'bytes29' | 'bytes30' | 'bytes31' | 'bytes32'

Fixed = 'fixed' | 'fixed0x8' | 'fixed0x16' | 'fixed0x24' | 'fixed0x32' | 'fixed0x40' | 'fixed0x48' | 'fixed0x56' | 'fixed0x64' | 'fixed0x72' | 'fixed0x80' | 'fixed0x88' | 'fixed0x96' | 'fixed0x104' | 'fixed0x112' | 'fixed0x120' | 'fixed0x128' | 'fixed0x136' | 'fixed0x144' | 'fixed0x152' | 'fixed0x160' | 'fixed0x168' | 'fixed0x176' | 'fixed0x184' | 'fixed0x192' | 'fixed0x200' | 'fixed0x208' | 'fixed0x216' | 'fixed0x224' | 'fixed0x232' | 'fixed0x240' | 'fixed0x248' | 'fixed0x256' | 'fixed8x8' | 'fixed8x16' | 'fixed8x24' | 'fixed8x32' | 'fixed8x40' | 'fixed8x48' | 'fixed8x56' | 'fixed8x64' | 'fixed8x72' | 'fixed8x80' | 'fixed8x88' | 'fixed8x96' | 'fixed8x104' | 'fixed8x112' | 'fixed8x120' | 'fixed8x128' | 'fixed8x136' | 'fixed8x144' | 'fixed8x152' | 'fixed8x160' | 'fixed8x168' | 'fixed8x176' | 'fixed8x184' | 'fixed8x192' | 'fixed8x200' | 'fixed8x208' | 'fixed8x216' | 'fixed8x224' | 'fixed8x232' | 'fixed8x240' | 'fixed8x248' | 'fixed16x8' | 'fixed16x16' | 'fixed16x24' | 'fixed16x32' | 'fixed16x40' | 'fixed16x48' | 'fixed16x56' | 'fixed16x64' | 'fixed16x72' | 'fixed16x80' | 'fixed16x88' | 'fixed16x96' | 'fixed16x104' | 'fixed16x112' | 'fixed16x120' | 'fixed16x128' | 'fixed16x136' | 'fixed16x144' | 'fixed16x152' | 'fixed16x160' | 'fixed16x168' | 'fixed16x176' | 'fixed16x184' | 'fixed16x192' | 'fixed16x200' | 'fixed16x208' | 'fixed16x216' | 'fixed16x224' | 'fixed16x232' | 'fixed16x240' | 'fixed24x8' | 'fixed24x16' | 'fixed24x24' | 'fixed24x32' | 'fixed24x40' | 'fixed24x48' | 'fixed24x56' | 'fixed24x64' | 'fixed24x72' | 'fixed24x80' | 'fixed24x88' | 'fixed24x96' | 'fixed24x104' | 'fixed24x112' | 'fixed24x120' | 'fixed24x128' | 'fixed24x136' | 'fixed24x144' | 'fixed24x152' | 'fixed24x160' | 'fixed24x168' | 'fixed24x176' | 'fixed24x184' | 'fixed24x192' | 'fixed24x200' | 'fixed24x208' | 'fixed24x216' | 'fixed24x224' | 'fixed24x232' | 'fixed32x8' | 'fixed32x16' | 'fixed32x24' | 'fixed32x32' | 'fixed32x40' | 'fixed32x48' | 'fixed32x56' | 'fixed32x64' | 'fixed32x72' | 'fixed32x80' | 'fixed32x88' | 'fixed32x96' | 'fixed32x104' | 'fixed32x112' | 'fixed32x120' | 'fixed32x128' | 'fixed32x136' | 'fixed32x144' | 'fixed32x152' | 'fixed32x160' | 'fixed32x168' | 'fixed32x176' | 'fixed32x184' | 'fixed32x192' | 'fixed32x200' | 'fixed32x208' | 'fixed32x216' | 'fixed32x224' | 'fixed40x8' | 'fixed40x16' | 'fixed40x24' | 'fixed40x32' | 'fixed40x40' | 'fixed40x48' | 'fixed40x56' | 'fixed40x64' | 'fixed40x72' | 'fixed40x80' | 'fixed40x88' | 'fixed40x96' | 'fixed40x104' | 'fixed40x112' | 'fixed40x120' | 'fixed40x128' | 'fixed40x136' | 'fixed40x144' | 'fixed40x152' | 'fixed40x160' | 'fixed40x168' | 'fixed40x176' | 'fixed40x184' | 'fixed40x192' | 'fixed40x200' | 'fixed40x208' | 'fixed40x216' | 'fixed48x8' | 'fixed48x16' | 'fixed48x24' | 'fixed48x32' | 'fixed48x40' | 'fixed48x48' | 'fixed48x56' | 'fixed48x64' | 'fixed48x72' | 'fixed48x80' | 'fixed48x88' | 'fixed48x96' | 'fixed48x104' | 'fixed48x112' | 'fixed48x120' | 'fixed48x128' | 'fixed48x136' | 'fixed48x144' | 'fixed48x152' | 'fixed48x160' | 'fixed48x168' | 'fixed48x176' | 'fixed48x184' | 'fixed48x192' | 'fixed48x200' | 'fixed48x208' | 'fixed56x8' | 'fixed56x16' | 'fixed56x24' | 'fixed56x32' | 'fixed56x40' | 'fixed56x48' | 'fixed56x56' | 'fixed56x64' | 'fixed56x72' | 'fixed56x80' | 'fixed56x88' | 'fixed56x96' | 'fixed56x104' | 'fixed56x112' | 'fixed56x120' | 'fixed56x128' | 'fixed56x136' | 'fixed56x144' | 'fixed56x152' | 'fixed56x160' | 'fixed56x168' | 'fixed56x176' | 'fixed56x184' | 'fixed56x192' | 'fixed56x200' | 'fixed64x8' | 'fixed64x16' | 'fixed64x24' | 'fixed64x32' | 'fixed64x40' | 'fixed64x48' | 'fixed64x56' | 'fixed64x64' | 'fixed64x72' | 'fixed64x80' | 'fixed64x88' | 'fixed64x96' | 'fixed64x104' | 'fixed64x112' | 'fixed64x120' | 'fixed64x128' | 'fixed64x136' | 'fixed64x144' | 'fixed64x152' | 'fixed64x160' | 'fixed64x168' | 'fixed64x176' | 'fixed64x184' | 'fixed64x192' | 'fixed72x8' | 'fixed72x16' | 'fixed72x24' | 'fixed72x32' | 'fixed72x40' | 'fixed72x48' | 'fixed72x56' | 'fixed72x64' | 'fixed72x72' | 'fixed72x80' | 'fixed72x88' | 'fixed72x96' | 'fixed72x104' | 'fixed72x112' | 'fixed72x120' | 'fixed72x128' | 'fixed72x136' | 'fixed72x144' | 'fixed72x152' | 'fixed72x160' | 'fixed72x168' | 'fixed72x176' | 'fixed72x184' | 'fixed80x8' | 'fixed80x16' | 'fixed80x24' | 'fixed80x32' | 'fixed80x40' | 'fixed80x48' | 'fixed80x56' | 'fixed80x64' | 'fixed80x72' | 'fixed80x80' | 'fixed80x88' | 'fixed80x96' | 'fixed80x104' | 'fixed80x112' | 'fixed80x120' | 'fixed80x128' | 'fixed80x136' | 'fixed80x144' | 'fixed80x152' | 'fixed80x160' | 'fixed80x168' | 'fixed80x176' | 'fixed88x8' | 'fixed88x16' | 'fixed88x24' | 'fixed88x32' | 'fixed88x40' | 'fixed88x48' | 'fixed88x56' | 'fixed88x64' | 'fixed88x72' | 'fixed88x80' | 'fixed88x88' | 'fixed88x96' | 'fixed88x104' | 'fixed88x112' | 'fixed88x120' | 'fixed88x128' | 'fixed88x136' | 'fixed88x144' | 'fixed88x152' | 'fixed88x160' | 'fixed88x168' | 'fixed96x8' | 'fixed96x16' | 'fixed96x24' | 'fixed96x32' | 'fixed96x40' | 'fixed96x48' | 'fixed96x56' | 'fixed96x64' | 'fixed96x72' | 'fixed96x80' | 'fixed96x88' | 'fixed96x96' | 'fixed96x104' | 'fixed96x112' | 'fixed96x120' | 'fixed96x128' | 'fixed96x136' | 'fixed96x144' | 'fixed96x152' | 'fixed96x160' | 'fixed104x8' | 'fixed104x16' | 'fixed104x24' | 'fixed104x32' | 'fixed104x40' | 'fixed104x48' | 'fixed104x56' | 'fixed104x64' | 'fixed104x72' | 'fixed104x80' | 'fixed104x88' | 'fixed104x96' | 'fixed104x104' | 'fixed104x112' | 'fixed104x120' | 'fixed104x128' | 'fixed104x136' | 'fixed104x144' | 'fixed104x152' | 'fixed112x8' | 'fixed112x16' | 'fixed112x24' | 'fixed112x32' | 'fixed112x40' | 'fixed112x48' | 'fixed112x56' | 'fixed112x64' | 'fixed112x72' | 'fixed112x80' | 'fixed112x88' | 'fixed112x96' | 'fixed112x104' | 'fixed112x112' | 'fixed112x120' | 'fixed112x128' | 'fixed112x136' | 'fixed112x144' | 'fixed120x8' | 'fixed120x16' | 'fixed120x24' | 'fixed120x32' | 'fixed120x40' | 'fixed120x48' | 'fixed120x56' | 'fixed120x64' | 'fixed120x72' | 'fixed120x80' | 'fixed120x88' | 'fixed120x96' | 'fixed120x104' | 'fixed120x112' | 'fixed120x120' | 'fixed120x128' | 'fixed120x136' | 'fixed128x8' | 'fixed128x16' | 'fixed128x24' | 'fixed128x32' | 'fixed128x40' | 'fixed128x48' | 'fixed128x56' | 'fixed128x64' | 'fixed128x72' | 'fixed128x80' | 'fixed128x88' | 'fixed128x96' | 'fixed128x104' | 'fixed128x112' | 'fixed128x120' | 'fixed128x128' | 'fixed136x8' | 'fixed136x16' | 'fixed136x24' | 'fixed136x32' | 'fixed136x40' | 'fixed136x48' | 'fixed136x56' | 'fixed136x64' | 'fixed136x72' | 'fixed136x80' | 'fixed136x88' | 'fixed136x96' | 'fixed136x104' | 'fixed136x112' | 'fixed136x120' | 'fixed144x8' | 'fixed144x16' | 'fixed144x24' | 'fixed144x32' | 'fixed144x40' | 'fixed144x48' | 'fixed144x56' | 'fixed144x64' | 'fixed144x72' | 'fixed144x80' | 'fixed144x88' | 'fixed144x96' | 'fixed144x104' | 'fixed144x112' | 'fixed152x8' | 'fixed152x16' | 'fixed152x24' | 'fixed152x32' | 'fixed152x40' | 'fixed152x48' | 'fixed152x56' | 'fixed152x64' | 'fixed152x72' | 'fixed152x80' | 'fixed152x88' | 'fixed152x96' | 'fixed152x104' | 'fixed160x8' | 'fixed160x16' | 'fixed160x24' | 'fixed160x32' | 'fixed160x40' | 'fixed160x48' | 'fixed160x56' | 'fixed160x64' | 'fixed160x72' | 'fixed160x80' | 'fixed160x88' | 'fixed160x96' | 'fixed168x8' | 'fixed168x16' | 'fixed168x24' | 'fixed168x32' | 'fixed168x40' | 'fixed168x48' | 'fixed168x56' | 'fixed168x64' | 'fixed168x72' | 'fixed168x80' | 'fixed168x88' | 'fixed176x8' | 'fixed176x16' | 'fixed176x24' | 'fixed176x32' | 'fixed176x40' | 'fixed176x48' | 'fixed176x56' | 'fixed176x64' | 'fixed176x72' | 'fixed176x80' | 'fixed184x8' | 'fixed184x16' | 'fixed184x24' | 'fixed184x32' | 'fixed184x40' | 'fixed184x48' | 'fixed184x56' | 'fixed184x64' | 'fixed184x72' | 'fixed192x8' | 'fixed192x16' | 'fixed192x24' | 'fixed192x32' | 'fixed192x40' | 'fixed192x48' | 'fixed192x56' | 'fixed192x64' | 'fixed200x8' | 'fixed200x16' | 'fixed200x24' | 'fixed200x32' | 'fixed200x40' | 'fixed200x48' | 'fixed200x56' | 'fixed208x8' | 'fixed208x16' | 'fixed208x24' | 'fixed208x32' | 'fixed208x40' | 'fixed208x48' | 'fixed216x8' | 'fixed216x16' | 'fixed216x24' | 'fixed216x32' | 'fixed216x40' | 'fixed224x8' | 'fixed224x16' | 'fixed224x24' | 'fixed224x32' | 'fixed232x8' | 'fixed232x16' | 'fixed232x24' | 'fixed240x8' | 'fixed240x16' | 'fixed248x8'

Ufixed = 'ufixed' | 'ufixed0x8' | 'ufixed0x16' | 'ufixed0x24' | 'ufixed0x32' | 'ufixed0x40' | 'ufixed0x48' | 'ufixed0x56' | 'ufixed0x64' | 'ufixed0x72' | 'ufixed0x80' | 'ufixed0x88' | 'ufixed0x96' | 'ufixed0x104' | 'ufixed0x112' | 'ufixed0x120' | 'ufixed0x128' | 'ufixed0x136' | 'ufixed0x144' | 'ufixed0x152' | 'ufixed0x160' | 'ufixed0x168' | 'ufixed0x176' | 'ufixed0x184' | 'ufixed0x192' | 'ufixed0x200' | 'ufixed0x208' | 'ufixed0x216' | 'ufixed0x224' | 'ufixed0x232' | 'ufixed0x240' | 'ufixed0x248' | 'ufixed0x256' | 'ufixed8x8' | 'ufixed8x16' | 'ufixed8x24' | 'ufixed8x32' | 'ufixed8x40' | 'ufixed8x48' | 'ufixed8x56' | 'ufixed8x64' | 'ufixed8x72' | 'ufixed8x80' | 'ufixed8x88' | 'ufixed8x96' | 'ufixed8x104' | 'ufixed8x112' | 'ufixed8x120' | 'ufixed8x128' | 'ufixed8x136' | 'ufixed8x144' | 'ufixed8x152' | 'ufixed8x160' | 'ufixed8x168' | 'ufixed8x176' | 'ufixed8x184' | 'ufixed8x192' | 'ufixed8x200' | 'ufixed8x208' | 'ufixed8x216' | 'ufixed8x224' | 'ufixed8x232' | 'ufixed8x240' | 'ufixed8x248' | 'ufixed16x8' | 'ufixed16x16' | 'ufixed16x24' | 'ufixed16x32' | 'ufixed16x40' | 'ufixed16x48' | 'ufixed16x56' | 'ufixed16x64' | 'ufixed16x72' | 'ufixed16x80' | 'ufixed16x88' | 'ufixed16x96' | 'ufixed16x104' | 'ufixed16x112' | 'ufixed16x120' | 'ufixed16x128' | 'ufixed16x136' | 'ufixed16x144' | 'ufixed16x152' | 'ufixed16x160' | 'ufixed16x168' | 'ufixed16x176' | 'ufixed16x184' | 'ufixed16x192' | 'ufixed16x200' | 'ufixed16x208' | 'ufixed16x216' | 'ufixed16x224' | 'ufixed16x232' | 'ufixed16x240' | 'ufixed24x8' | 'ufixed24x16' | 'ufixed24x24' | 'ufixed24x32' | 'ufixed24x40' | 'ufixed24x48' | 'ufixed24x56' | 'ufixed24x64' | 'ufixed24x72' | 'ufixed24x80' | 'ufixed24x88' | 'ufixed24x96' | 'ufixed24x104' | 'ufixed24x112' | 'ufixed24x120' | 'ufixed24x128' | 'ufixed24x136' | 'ufixed24x144' | 'ufixed24x152' | 'ufixed24x160' | 'ufixed24x168' | 'ufixed24x176' | 'ufixed24x184' | 'ufixed24x192' | 'ufixed24x200' | 'ufixed24x208' | 'ufixed24x216' | 'ufixed24x224' | 'ufixed24x232' | 'ufixed32x8' | 'ufixed32x16' | 'ufixed32x24' | 'ufixed32x32' | 'ufixed32x40' | 'ufixed32x48' | 'ufixed32x56' | 'ufixed32x64' | 'ufixed32x72' | 'ufixed32x80' | 'ufixed32x88' | 'ufixed32x96' | 'ufixed32x104' | 'ufixed32x112' | 'ufixed32x120' | 'ufixed32x128' | 'ufixed32x136' | 'ufixed32x144' | 'ufixed32x152' | 'ufixed32x160' | 'ufixed32x168' | 'ufixed32x176' | 'ufixed32x184' | 'ufixed32x192' | 'ufixed32x200' | 'ufixed32x208' | 'ufixed32x216' | 'ufixed32x224' | 'ufixed40x8' | 'ufixed40x16' | 'ufixed40x24' | 'ufixed40x32' | 'ufixed40x40' | 'ufixed40x48' | 'ufixed40x56' | 'ufixed40x64' | 'ufixed40x72' | 'ufixed40x80' | 'ufixed40x88' | 'ufixed40x96' | 'ufixed40x104' | 'ufixed40x112' | 'ufixed40x120' | 'ufixed40x128' | 'ufixed40x136' | 'ufixed40x144' | 'ufixed40x152' | 'ufixed40x160' | 'ufixed40x168' | 'ufixed40x176' | 'ufixed40x184' | 'ufixed40x192' | 'ufixed40x200' | 'ufixed40x208' | 'ufixed40x216' | 'ufixed48x8' | 'ufixed48x16' | 'ufixed48x24' | 'ufixed48x32' | 'ufixed48x40' | 'ufixed48x48' | 'ufixed48x56' | 'ufixed48x64' | 'ufixed48x72' | 'ufixed48x80' | 'ufixed48x88' | 'ufixed48x96' | 'ufixed48x104' | 'ufixed48x112' | 'ufixed48x120' | 'ufixed48x128' | 'ufixed48x136' | 'ufixed48x144' | 'ufixed48x152' | 'ufixed48x160' | 'ufixed48x168' | 'ufixed48x176' | 'ufixed48x184' | 'ufixed48x192' | 'ufixed48x200' | 'ufixed48x208' | 'ufixed56x8' | 'ufixed56x16' | 'ufixed56x24' | 'ufixed56x32' | 'ufixed56x40' | 'ufixed56x48' | 'ufixed56x56' | 'ufixed56x64' | 'ufixed56x72' | 'ufixed56x80' | 'ufixed56x88' | 'ufixed56x96' | 'ufixed56x104' | 'ufixed56x112' | 'ufixed56x120' | 'ufixed56x128' | 'ufixed56x136' | 'ufixed56x144' | 'ufixed56x152' | 'ufixed56x160' | 'ufixed56x168' | 'ufixed56x176' | 'ufixed56x184' | 'ufixed56x192' | 'ufixed56x200' | 'ufixed64x8' | 'ufixed64x16' | 'ufixed64x24' | 'ufixed64x32' | 'ufixed64x40' | 'ufixed64x48' | 'ufixed64x56' | 'ufixed64x64' | 'ufixed64x72' | 'ufixed64x80' | 'ufixed64x88' | 'ufixed64x96' | 'ufixed64x104' | 'ufixed64x112' | 'ufixed64x120' | 'ufixed64x128' | 'ufixed64x136' | 'ufixed64x144' | 'ufixed64x152' | 'ufixed64x160' | 'ufixed64x168' | 'ufixed64x176' | 'ufixed64x184' | 'ufixed64x192' | 'ufixed72x8' | 'ufixed72x16' | 'ufixed72x24' | 'ufixed72x32' | 'ufixed72x40' | 'ufixed72x48' | 'ufixed72x56' | 'ufixed72x64' | 'ufixed72x72' | 'ufixed72x80' | 'ufixed72x88' | 'ufixed72x96' | 'ufixed72x104' | 'ufixed72x112' | 'ufixed72x120' | 'ufixed72x128' | 'ufixed72x136' | 'ufixed72x144' | 'ufixed72x152' | 'ufixed72x160' | 'ufixed72x168' | 'ufixed72x176' | 'ufixed72x184' | 'ufixed80x8' | 'ufixed80x16' | 'ufixed80x24' | 'ufixed80x32' | 'ufixed80x40' | 'ufixed80x48' | 'ufixed80x56' | 'ufixed80x64' | 'ufixed80x72' | 'ufixed80x80' | 'ufixed80x88' | 'ufixed80x96' | 'ufixed80x104' | 'ufixed80x112' | 'ufixed80x120' | 'ufixed80x128' | 'ufixed80x136' | 'ufixed80x144' | 'ufixed80x152' | 'ufixed80x160' | 'ufixed80x168' | 'ufixed80x176' | 'ufixed88x8' | 'ufixed88x16' | 'ufixed88x24' | 'ufixed88x32' | 'ufixed88x40' | 'ufixed88x48' | 'ufixed88x56' | 'ufixed88x64' | 'ufixed88x72' | 'ufixed88x80' | 'ufixed88x88' | 'ufixed88x96' | 'ufixed88x104' | 'ufixed88x112' | 'ufixed88x120' | 'ufixed88x128' | 'ufixed88x136' | 'ufixed88x144' | 'ufixed88x152' | 'ufixed88x160' | 'ufixed88x168' | 'ufixed96x8' | 'ufixed96x16' | 'ufixed96x24' | 'ufixed96x32' | 'ufixed96x40' | 'ufixed96x48' | 'ufixed96x56' | 'ufixed96x64' | 'ufixed96x72' | 'ufixed96x80' | 'ufixed96x88' | 'ufixed96x96' | 'ufixed96x104' | 'ufixed96x112' | 'ufixed96x120' | 'ufixed96x128' | 'ufixed96x136' | 'ufixed96x144' | 'ufixed96x152' | 'ufixed96x160' | 'ufixed104x8' | 'ufixed104x16' | 'ufixed104x24' | 'ufixed104x32' | 'ufixed104x40' | 'ufixed104x48' | 'ufixed104x56' | 'ufixed104x64' | 'ufixed104x72' | 'ufixed104x80' | 'ufixed104x88' | 'ufixed104x96' | 'ufixed104x104' | 'ufixed104x112' | 'ufixed104x120' | 'ufixed104x128' | 'ufixed104x136' | 'ufixed104x144' | 'ufixed104x152' | 'ufixed112x8' | 'ufixed112x16' | 'ufixed112x24' | 'ufixed112x32' | 'ufixed112x40' | 'ufixed112x48' | 'ufixed112x56' | 'ufixed112x64' | 'ufixed112x72' | 'ufixed112x80' | 'ufixed112x88' | 'ufixed112x96' | 'ufixed112x104' | 'ufixed112x112' | 'ufixed112x120' | 'ufixed112x128' | 'ufixed112x136' | 'ufixed112x144' | 'ufixed120x8' | 'ufixed120x16' | 'ufixed120x24' | 'ufixed120x32' | 'ufixed120x40' | 'ufixed120x48' | 'ufixed120x56' | 'ufixed120x64' | 'ufixed120x72' | 'ufixed120x80' | 'ufixed120x88' | 'ufixed120x96' | 'ufixed120x104' | 'ufixed120x112' | 'ufixed120x120' | 'ufixed120x128' | 'ufixed120x136' | 'ufixed128x8' | 'ufixed128x16' | 'ufixed128x24' | 'ufixed128x32' | 'ufixed128x40' | 'ufixed128x48' | 'ufixed128x56' | 'ufixed128x64' | 'ufixed128x72' | 'ufixed128x80' | 'ufixed128x88' | 'ufixed128x96' | 'ufixed128x104' | 'ufixed128x112' | 'ufixed128x120' | 'ufixed128x128' | 'ufixed136x8' | 'ufixed136x16' | 'ufixed136x24' | 'ufixed136x32' | 'ufixed136x40' | 'ufixed136x48' | 'ufixed136x56' | 'ufixed136x64' | 'ufixed136x72' | 'ufixed136x80' | 'ufixed136x88' | 'ufixed136x96' | 'ufixed136x104' | 'ufixed136x112' | 'ufixed136x120' | 'ufixed144x8' | 'ufixed144x16' | 'ufixed144x24' | 'ufixed144x32' | 'ufixed144x40' | 'ufixed144x48' | 'ufixed144x56' | 'ufixed144x64' | 'ufixed144x72' | 'ufixed144x80' | 'ufixed144x88' | 'ufixed144x96' | 'ufixed144x104' | 'ufixed144x112' | 'ufixed152x8' | 'ufixed152x16' | 'ufixed152x24' | 'ufixed152x32' | 'ufixed152x40' | 'ufixed152x48' | 'ufixed152x56' | 'ufixed152x64' | 'ufixed152x72' | 'ufixed152x80' | 'ufixed152x88' | 'ufixed152x96' | 'ufixed152x104' | 'ufixed160x8' | 'ufixed160x16' | 'ufixed160x24' | 'ufixed160x32' | 'ufixed160x40' | 'ufixed160x48' | 'ufixed160x56' | 'ufixed160x64' | 'ufixed160x72' | 'ufixed160x80' | 'ufixed160x88' | 'ufixed160x96' | 'ufixed168x8' | 'ufixed168x16' | 'ufixed168x24' | 'ufixed168x32' | 'ufixed168x40' | 'ufixed168x48' | 'ufixed168x56' | 'ufixed168x64' | 'ufixed168x72' | 'ufixed168x80' | 'ufixed168x88' | 'ufixed176x8' | 'ufixed176x16' | 'ufixed176x24' | 'ufixed176x32' | 'ufixed176x40' | 'ufixed176x48' | 'ufixed176x56' | 'ufixed176x64' | 'ufixed176x72' | 'ufixed176x80' | 'ufixed184x8' | 'ufixed184x16' | 'ufixed184x24' | 'ufixed184x32' | 'ufixed184x40' | 'ufixed184x48' | 'ufixed184x56' | 'ufixed184x64' | 'ufixed184x72' | 'ufixed192x8' | 'ufixed192x16' | 'ufixed192x24' | 'ufixed192x32' | 'ufixed192x40' | 'ufixed192x48' | 'ufixed192x56' | 'ufixed192x64' | 'ufixed200x8' | 'ufixed200x16' | 'ufixed200x24' | 'ufixed200x32' | 'ufixed200x40' | 'ufixed200x48' | 'ufixed200x56' | 'ufixed208x8' | 'ufixed208x16' | 'ufixed208x24' | 'ufixed208x32' | 'ufixed208x40' | 'ufixed208x48' | 'ufixed216x8' | 'ufixed216x16' | 'ufixed216x24' | 'ufixed216x32' | 'ufixed216x40' | 'ufixed224x8' | 'ufixed224x16' | 'ufixed224x24' | 'ufixed224x32' | 'ufixed232x8' | 'ufixed232x16' | 'ufixed232x24' | 'ufixed240x8' | 'ufixed240x16' | 'ufixed248x8'

InlineAssemblyBlock = '{' AssemblyItem* '}'

AssemblyItem = Identifier | FunctionalAssemblyExpression | InlineAssemblyBlock | AssemblyLocalBinding | AssemblyAssignment | AssemblyLabel | NumberLiteral | StringLiteral | HexLiteral
AssemblyLocalBinding = 'let' Identifier ':=' FunctionalAssemblyExpression
AssemblyAssignment = ( Identifier ':=' FunctionalAssemblyExpression ) | ( '=:' Identifier )
AssemblyLabel = Identifier ':'
FunctionalAssemblyExpression = Identifier '(' AssemblyItem? ( ',' AssemblyItem )* ')'