Rutas
/
Elixir
Elixir
/
Ejercicios
/
Top secret
Top secret

Top secret

Ejercicio de aprendizaje

Introducción

AST

El Abstract Syntax Tree (AST), también llamada quoted expression, es una forma de representar el código como datos.

Cada nodo del AST es una tupla de tres elementos.

# AST representation of:
# 2 + 3
{:+, [], [2, 3]}

El primer elemento, un átomo, es la operación. El segundo elemento, una lista de palabras clave, son los metadatos. El tercer elemento es una lista de argumentos, que contiene otros nodos. Los valores literales, como los números enteros, los átomos y los strings, se representan en el AST como ellos mismos en lugar de como tuplas de tres elementos.

Convertir código en AST

Cambiar código de Elixir a AST y los AST de nuevo a código forma parte de la biblioteca estándar. Puedes encontrar funciones para trabajar con AST en los módulos Code (por ejemplo, para cambiar una string con código a un AST) y Macro (por ejemplo, para recorrer el AST o cambiarlo a una string).

Ten en cuenta que todas las funciones de la biblioteca estándar usan el nombre «quoted» para referirse al AST (abreviatura de quoted expression).

La forma especial para convertir código en un AST se llama quote. Acepta un bloque de código y devuelve su AST.

quote do
  2 + 3 - 1
end

# => {:-, [], [
#      {:+, [], [2, 3]},
#      1
#    ]}

Casos de uso

La capacidad de representar código como un AST está en el corazón de la metaprogramación en Elixir. Las macros, que son una forma de escribir código de Elixir que produce código de Elixir, funcionan devolviendo AST como resultado.

Otro caso de uso de los AST es el análisis estático de código, como la propia herramienta de Exercism, el Analyzer, que quizá ya conozcas como el pequeño bot que deja comentarios en tus soluciones.

Instrucciones

Formas parte de un grupo de trabajo que lucha contra el espionaje empresarial. Tienes un informante secreto en Shady Company X, a la que sospechas de robar secretos a sus competidores.

Tu informante, la agente Ex, es desarrolladora de Elixir. Está codificando mensajes secretos en su código.

Para decodificar sus mensajes secretos:

  • Toma todas las funciones (públicas y privadas) en el orden en que están definidas.
  • Para cada función, toma los primeros n caracteres de su nombre, donde n es la aridad de la función.

1. Convierte el código en datos

Implementa la función TopSecret.to_ast/1. Debe recibir un string con código Elixir y devolver su AST.

TopSecret.to_ast("div(4, 3)")
# => {:div, [line: 1], [4, 3]}

2. Decodifica un único nodo del AST

Implementa la función TopSecret.decode_secret_message_part/2. Debe recibir un nodo del AST y un acumulador para el mensaje secreto (una lista). Debe devolver una tupla con el nodo del AST sin cambios como primer elemento y el acumulador como segundo elemento.

Si la operación del nodo del AST es definir una función (def o defp), antepón el nombre de la función (convertido a string) al acumulador. Si la operación es otra cosa, devuelve el acumulador sin cambios.

ast_node = TopSecret.to_ast("defp cat(a, b, c), do: nil")
TopSecret.decode_secret_message_part(ast_node, ["day"])
# => {ast_node, ["cat", "day"]}

ast_node = TopSecret.to_ast("10 + 3")
TopSecret.decode_secret_message_part(ast_node, ["day"])
# => {ast_node, ["day"]}

Esta función no necesita hacer ninguna llamada recursiva para comprobar todo el AST, solo el nodo dado. Recorreremos todo el AST con herramientas integradas en el último paso.

3. Decodifica la parte del mensaje secreto a partir de la definición de la función

Amplía la función TopSecret.decode_secret_message_part/2. Si la operación del nodo del AST es definir una función, no devuelvas el nombre completo de la función. En su lugar, comprueba la aridad de la función. Después, devuelve solo los primeros n caracteres del nombre, donde n es la aridad.

ast_node = TopSecret.to_ast("defp cat(a, b), do: nil")
TopSecret.decode_secret_message_part(ast_node, ["day"])
# => {ast_node, ["ca", "day"]}

ast_node = TopSecret.to_ast("defp cat(), do: nil")
TopSecret.decode_secret_message_part(ast_node, ["day"])
# => {ast_node, ["", "day"]}

4. Corrige la decodificación para funciones con guardas

Amplía la función TopSecret.decode_secret_message_part/2. Asegúrate de que el nombre y la aridad de la función se detectan correctamente en las definiciones de funciones que usan guardas.

ast_node = TopSecret.to_ast("defp cat(a, b) when is_nil(a), do: nil")
TopSecret.decode_secret_message_part(ast_node, ["day"])
# => {ast_node, ["ca", "day"]}

5. Decodifica el mensaje secreto completo

Implementa la función TopSecret.decode_secret_message/1. Debe recibir un string con código Elixir y devolver el mensaje secreto como un string decodificado a partir de todas las definiciones de funciones que se encuentren en el código. Asegúrate de reutilizar las funciones definidas en los pasos anteriores.

code = """
defmodule MyCalendar do
  def busy?(date, time) do
    Date.day_of_week(date) != 7 and
      time.hour in 10..16
  end

  def yesterday?(date) do
    Date.diff(Date.utc_today, date)
  end
end
"""

TopSecret.decode_secret_message(code)
# => "buy"
Editar en GitHub El enlace se abre en una ventana o pestaña nueva
Elixir Exercism

¿Listo para empezar Top secret?

Regístrate en Exercism para aprender y dominar Elixir con 58 conceptos168 ejercicios y mentoría humana real, todo gratis.