Διαδρομές
/
Elixir
Elixir
/
Ασκήσεις
/
Άκρως απόρρητο
Άκρως απόρρητο

Άκρως απόρρητο

Άσκηση εκμάθησης

Εισαγωγή

AST

Το Abstract Syntax Tree (AST), που λέγεται και παρατιθέμενη έκφραση, είναι ένας τρόπος να αναπαραστήσεις τον κώδικα ως δεδομένα.

Κάθε κόμβος στο AST είναι μια πλειάδα τριών στοιχείων.

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

Το πρώτο στοιχείο, ένα άτομο, είναι η πράξη. Το δεύτερο στοιχείο, μια λίστα λέξεων-κλειδιών, είναι τα μεταδεδομένα. Το τρίτο στοιχείο είναι μια λίστα ορισμάτων, που περιέχει άλλους κόμβους. Οι κυριολεκτικές τιμές, όπως οι ακέραιοι, τα άτομα και οι συμβολοσειρές, αναπαρίστανται στο AST ως οι ίδιες αντί για πλειάδες τριών στοιχείων.

Μετατροπή κώδικα σε AST

Η μετατροπή κώδικα Elixir σε AST και η μετατροπή AST πίσω σε κώδικα είναι μέρος της βασικής βιβλιοθήκης. Μπορείς να βρεις συναρτήσεις για να δουλέψεις με AST στα αρθρώματα Code (π.χ. για να μετατρέψεις μια συμβολοσειρά με κώδικα σε AST) και Macro (π.χ. για να διατρέξεις το AST ή να το μετατρέψεις σε συμβολοσειρά).

Σημείωσε ότι όλες οι συναρτήσεις της βασικής βιβλιοθήκης χρησιμοποιούν το όνομα "quoted" για να δηλώσουν το AST (συντομογραφία της παρατιθέμενης έκφρασης).

Η ειδική μορφή για τη μετατροπή κώδικα σε AST ονομάζεται quote. Δέχεται ένα μπλοκ κώδικα και επιστρέφει το AST του.

quote do
  2 + 3 - 1
end

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

Περιπτώσεις χρήσης

Η δυνατότητα να αναπαραστήσεις τον κώδικα ως AST βρίσκεται στην καρδιά του μεταπρογραμματισμού στην Elixir. Οι μακροεντολές, που είναι ένας τρόπος να γράφεις κώδικα Elixir ο οποίος παράγει κώδικα Elixir, λειτουργούν επιστρέφοντας AST ως έξοδο.

Μια άλλη περίπτωση χρήσης των AST είναι η στατική ανάλυση κώδικα, όπως το εργαλείο της ίδιας της Exercism, το Analyzer, που ίσως το ξέρεις ήδη ως το μικρό bot που αφήνει σχόλια στις λύσεις σου.

Οδηγίες

Είσαι μέλος μιας ειδικής ομάδας που μάχεται ενάντια στην εταιρική κατασκοπεία. Έχεις έναν μυστικό πληροφοριοδότη στη Shady Company X, την οποία υποψιάζεσαι ότι κλέβει μυστικά από τους ανταγωνιστές της.

Ο πληροφοριοδότης σου, ο Πράκτορας Ex, είναι προγραμματιστής Elixir. Κωδικοποιεί μυστικά μηνύματα μέσα στον κώδικά της.

Για να αποκωδικοποιήσεις τα μυστικά της μηνύματα:

  • Πάρε όλες τις συναρτήσεις (δημόσιες και ιδιωτικές) με τη σειρά που ορίζονται.
  • Για κάθε συνάρτηση, πάρε τους πρώτους n χαρακτήρες από το όνομά της, όπου n είναι το πλήθος ορισμάτων της συνάρτησης.

1. Μετέτρεψε τον κώδικα σε δεδομένα

Υλοποίησε τη συνάρτηση TopSecret.to_ast/1. Πρέπει να δέχεται μια συμβολοσειρά με κώδικα Elixir και να επιστρέφει το AST της.

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

2. Ανάλυσε έναν μεμονωμένο κόμβο AST

Υλοποίησε τη συνάρτηση TopSecret.decode_secret_message_part/2. Πρέπει να δέχεται έναν κόμβο AST και έναν συσσωρευτή για το μυστικό μήνυμα (μια λίστα). Πρέπει να επιστρέφει μια πλειάδα με τον κόμβο AST αμετάβλητο ως πρώτο στοιχείο και τον συσσωρευτή ως δεύτερο στοιχείο.

Αν η πράξη του κόμβου AST ορίζει μια συνάρτηση (def ή defp), πρόσθεσε στην αρχή του συσσωρευτή το όνομα της συνάρτησης (μετατρεμμένο σε συμβολοσειρά). Αν η πράξη είναι κάτι άλλο, επέστρεψε τον συσσωρευτή αμετάβλητο.

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

Αυτή η συνάρτηση δεν χρειάζεται να κάνει αναδρομικές κλήσεις για να ελέγξει ολόκληρο το AST, μόνο τον δοσμένο κόμβο. Θα διασχίσουμε ολόκληρο το AST με ενσωματωμένα εργαλεία στο τελευταίο βήμα.

3. Αποκωδικοποίησε το τμήμα του μυστικού μηνύματος από τον ορισμό συνάρτησης

Επέκτεινε τη συνάρτηση TopSecret.decode_secret_message_part/2. Αν η πράξη στον κόμβο AST ορίζει μια συνάρτηση, μην επιστρέψεις ολόκληρο το όνομα της συνάρτησης. Αντ' αυτού, έλεγξε το πλήθος ορισμάτων της συνάρτησης. Μετά, επέστρεψε μόνο τους πρώτους n χαρακτήρες από το όνομα, όπου n είναι το πλήθος ορισμάτων.

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. Διόρθωσε την αποκωδικοποίηση για συναρτήσεις με guards

Επέκτεινε τη συνάρτηση TopSecret.decode_secret_message_part/2. Βεβαιώσου ότι το όνομα και το πλήθος ορισμάτων της συνάρτησης εντοπίζονται σωστά για ορισμούς συναρτήσεων που χρησιμοποιούν guards.

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. Αποκωδικοποίησε ολόκληρο το μυστικό μήνυμα

Υλοποίησε τη συνάρτηση TopSecret.decode_secret_message/1. Πρέπει να δέχεται μια συμβολοσειρά με κώδικα Elixir και να επιστρέφει το μυστικό μήνυμα ως συμβολοσειρά, αποκωδικοποιημένο από όλους τους ορισμούς συναρτήσεων που βρίσκονται στον κώδικα. Φρόντισε να επαναχρησιμοποιήσεις τις συναρτήσεις που ορίστηκαν στα προηγούμενα βήματα.

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"
Επεξεργασία μέσω GitHub Ο σύνδεσμος ανοίγει σε νέο παράθυρο ή καρτέλα
Elixir Exercism

Έτοιμος να ξεκινήσεις την άσκηση Άκρως απόρρητο;

Γράψου στο Exercism για να μάθεις και να κατακτήσεις Elixir με 58 έννοιες168 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.