Track
/
Elixir
Elixir
/
Esercizi
/
Top secret
Top secret

Top secret

Esercizio di apprendimento

Introduzione

AST

L'albero sintattico astratto (AST), detto anche espressione quotata, è un modo per rappresentare il codice come dati.

Ogni nodo dell'AST è una tupla di tre elementi.

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

Il primo elemento, un atomo, è l'operazione. Il secondo elemento, una keyword list, contiene i metadati. Il terzo elemento è una lista di argomenti, che contiene altri nodi. I valori letterali, come i numeri interi, gli atomi e le stringhe, sono rappresentati nell'AST direttamente, invece che come tuple di tre elementi.

Trasformare il codice in AST

Trasformare il codice Elixir in AST e gli AST di nuovo in codice fa parte della libreria standard. Puoi trovare le funzioni per lavorare con gli AST nei moduli Code (ad esempio per trasformare una stringa di codice in un AST) e Macro (ad esempio per attraversare l'AST o trasformarlo in una stringa).

Tieni presente che tutte le funzioni della libreria standard usano il nome «quoted» per indicare l'AST (abbreviazione di quoted expression).

La forma speciale per trasformare il codice in un AST si chiama quote. Accetta un blocco di codice e restituisce il suo AST.

quote do
  2 + 3 - 1
end

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

Casi d'uso

La capacità di rappresentare il codice come AST è al cuore della metaprogrammazione in Elixir. Le macro, che sono un modo per scrivere codice Elixir che produce codice Elixir, funzionano restituendo come output degli AST.

Un altro caso d'uso degli AST è l'analisi statica del codice, come l'Analyzer, lo strumento di Exercism che potresti già conoscere come il piccolo bot che lascia commenti sulle soluzioni che invii.

Istruzioni

Fai parte di una task force che combatte contro lo spionaggio aziendale. Hai un'informatrice segreta presso Shady Company X, che sospetti rubi segreti ai suoi concorrenti.

La tua informatrice, l'agente Ex, è una sviluppatrice Elixir. Sta codificando messaggi segreti nel suo codice.

Per decodificare i suoi messaggi segreti:

  • Prendi tutte le funzioni (pubbliche e private) nell'ordine in cui sono definite.
  • Per ogni funzione, prendi i primi n caratteri del suo nome, dove n è l'arità della funzione.

1. Trasforma il codice in dati

Implementa la funzione TopSecret.to_ast/1. Deve prendere una stringa con codice Elixir e restituirne l'AST.

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

2. Analizza un singolo nodo AST

Implementa la funzione TopSecret.decode_secret_message_part/2. Deve prendere un nodo AST e un accumulatore per il messaggio segreto (un array). Deve restituire una tupla con il nodo AST invariato come primo elemento e l'accumulatore come secondo elemento.

Se l'operazione del nodo AST definisce una funzione (def o defp), anteponi all'accumulatore il nome della funzione (convertito in stringa). Se l'operazione è qualcos'altro, restituisci l'accumulatore invariato.

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"]}

Questa funzione non ha bisogno di fare chiamate ricorsive per controllare l'intero AST, ma solo il nodo dato. Attraverseremo l'intero AST con strumenti integrati nell'ultimo passaggio.

3. Decodifica la parte del messaggio segreto dalla definizione di funzione

Estendi la funzione TopSecret.decode_secret_message_part/2. Se l'operazione nel nodo AST definisce una funzione, non restituire l'intero nome della funzione. Controlla invece l'arità della funzione. Poi restituisci solo i primi n caratteri del nome, dove n è l'arità.

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. Correggi la decodifica per le funzioni con guardie

Estendi la funzione TopSecret.decode_secret_message_part/2. Assicurati che il nome e l'arità della funzione siano rilevati correttamente per le definizioni di funzione che usano guardie.

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 il messaggio segreto completo

Implementa la funzione TopSecret.decode_secret_message/1. Deve prendere una stringa con codice Elixir e restituire il messaggio segreto come stringa decodificata da tutte le definizioni di funzione trovate nel codice. Assicurati di riutilizzare le funzioni definite nei passaggi precedenti.

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"
Modifica tramite GitHub Il link si apre in una nuova finestra o scheda
Elixir Exercism

Vuoi iniziare Top secret?

Iscriviti a Exercism per imparare e padroneggiare Elixir con 58 concetti168 esercizi e il mentoring di persone reali, tutto gratis.