-
-
Notifications
You must be signed in to change notification settings - Fork 405
New concept exercise top-secret (concept: ast)
#930
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 6 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
ec3fabe
AST exercise idea - top secret
angelikatyborska 8285581
Add to_ast tests
angelikatyborska 68fa46b
Use function arity for encoding too
angelikatyborska 4365437
Merge branch 'main' into new-concept-exercise-ast-top-secret
angelikatyborska b1e0b2d
Write instructions and all tests
angelikatyborska 85c8789
Add stub
angelikatyborska 0990439
Apply suggestions from code review
angelikatyborska 88fa3e1
Add test for arity 0 and no parentheses
angelikatyborska 3f0f8f4
Differentiate between AST and AST node
angelikatyborska 1150d07
Merge branch 'main' into new-concept-exercise-ast-top-secret
angelikatyborska 46c2af7
Add step for `when`
angelikatyborska f6eef8d
Add hints
angelikatyborska 9e50fb7
Add exercise blurb
angelikatyborska bc72872
Add introduction
angelikatyborska 4582a74
Add concept files
angelikatyborska b6fbbfd
Write config
angelikatyborska 862c8dd
Split acc and ast assertion for better diffs when fail
angelikatyborska 42b6cc7
Add more hints
angelikatyborska 0840b8b
Remove too revealing hints
angelikatyborska 559dcd1
Fix grammar known -> know
angelikatyborska 7ff4437
Fix concept doc headings; add links to about.md
angelikatyborska e6ec12f
Add ast as a prereq to dot-dsl
angelikatyborska File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| # Hints | ||
|
|
||
| ## General |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| # Instructions | ||
|
|
||
| You're part of a task force fighting against corporate espionage. You have a secret informer at Shady Company X, which you suspect of stealing secrets from its competitors. | ||
|
|
||
| Your informer, Agent Ex, is an Elixir developer. She is encoding secret messages in her code. | ||
angelikatyborska marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| To decode the secret message: | ||
angelikatyborska marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| - Take all functions (public and private) in the order they're defined in. | ||
| - For each function, take the first `n` characters from its name, where `n` is the function's arity. | ||
|
|
||
| ## 1. Turn code into data | ||
|
|
||
| Implement the `TopSecret.to_ast/1` function. It should take a string with Elixir code and return its AST. | ||
|
|
||
| ```elixir | ||
| TopSecret.to_ast("div(4, 3)") | ||
| # => {:div, [line: 1], [4, 3]} | ||
| ``` | ||
|
|
||
| ## 2. Parse a single AST node | ||
|
|
||
| Implement the `TopSecret.decode_secret_message_part/2` function. It should take an AST and an accumulator for the secret message (a list). It should return a tuple with the AST unchanged as the first element, and the accumulator as the second element. | ||
angelikatyborska marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| If the top-most operation in the AST is defining a function (`def` or `defp`), prepend the function name (changed to a string) to the accumulator. If the top-most operation is something else, return the accumulator unchanged. | ||
|
|
||
| ```elixir | ||
| ast = TopSecret.to_ast("defp cat(a, b, c), do: nil") | ||
| TopSecret.decode_secret_message_part(ast, ["day"]) | ||
| # => {ast, ["cat", "day"]} | ||
|
|
||
| ast = TopSecret.to_ast("10 + 3") | ||
| TopSecret.decode_secret_message_part(ast, ["day"]) | ||
| # => {ast, ["day"]} | ||
| ``` | ||
|
|
||
| This function doesn't need to do any recursive calls to check the whole AST, only the top-most operation. We will traverse the whole AST with built-in tools in the last step. | ||
|
|
||
| ## 3. Decode the secret message part from function definition | ||
|
|
||
| Extend the `TopSecret.decode_secret_message_part/2` function. If the top-most operation in the AST is defining a function, don't return the whole function name. Instead, check the function's arity. Then, return only first `n` character from the name, where `n` is the arity. | ||
|
|
||
| ```elixir | ||
| ast = TopSecret.to_ast("defp cat(a, b), do: nil") | ||
| TopSecret.decode_secret_message_part(ast, ["day"]) | ||
| # => {ast, ["ca", "day"]} | ||
|
|
||
| ast = TopSecret.to_ast("defp cat(), do: nil") | ||
| TopSecret.decode_secret_message_part(ast, ["day"]) | ||
| # => {ast, ["", "day"]} | ||
| ``` | ||
|
|
||
| ## 4. Decode the full secret message | ||
|
|
||
| Implement the `TopSecret.decode_secret_message/1` function. It should take a string with Elixir code and return the secret message as a string decoded from all function definitions found in the code. Make sure to reuse functions defined in previous steps. | ||
angelikatyborska marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ```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" | ||
| ``` | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| # Introduction | ||
|
|
||
| ## AST | ||
|
|
||
| to write: | ||
|
|
||
| AST, also called a quoted expression in Elixir | ||
|
|
||
| necessary for metaprogramming | ||
|
|
||
| what is arity |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| # Used by "mix format" | ||
| [ | ||
| inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # The directory Mix will write compiled artifacts to. | ||
| /_build/ | ||
|
|
||
| # If you run "mix test --cover", coverage assets end up here. | ||
| /cover/ | ||
|
|
||
| # The directory Mix downloads your dependencies sources to. | ||
| /deps/ | ||
|
|
||
| # Where third-party dependencies like ExDoc output generated docs. | ||
| /doc/ | ||
|
|
||
| # Ignore .fetch files in case you like to edit your project deps locally. | ||
| /.fetch | ||
|
|
||
| # If the VM crashes, it generates a dump, let's ignore it too. | ||
| erl_crash.dump | ||
|
|
||
| # Also ignore archive artifacts (built via "mix archive.build"). | ||
| *.ez | ||
|
|
||
| # Ignore package tarball (built via "mix hex.build"). | ||
| maps-*.tar | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| { | ||
| "blurb": "TODO", | ||
| "icon": "TODO", | ||
| "authors": [ | ||
| "jiegillet", | ||
| "angelikatyborska" | ||
| ], | ||
| "files": { | ||
| "solution": [ | ||
| "lib/top_secret.ex" | ||
| ], | ||
| "test": [ | ||
| "test/top_secret_test.exs" | ||
| ], | ||
| "exemplar": [ | ||
| ".meta/exemplar.ex" | ||
| ] | ||
| }, | ||
| "language_versions": ">=1.10" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| # Design | ||
|
|
||
| ## Learning objectives | ||
|
|
||
| - How to parse a string to AST | ||
| - Understanding ASTs | ||
| - Traversing ASTs | ||
|
|
||
| ## Out of scope | ||
|
|
||
| - `quote`/`unquote` | ||
| - macros | ||
|
|
||
| ## Concepts | ||
|
|
||
| - `ast` | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - `enum` | ||
| - `strings` | ||
| - `tuples` | ||
| - `pattern-matching` | ||
|
|
||
| ## Analyzer | ||
|
|
||
| - function reuse: `decode_secret_message` should use `decode_secret_message_part` and `to_ast`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| defmodule TopSecret do | ||
| def to_ast(string) do | ||
| Code.string_to_quoted!(string) | ||
| end | ||
|
|
||
| def decode_secret_message_part({keyword, _, children} = ast, acc) | ||
| when keyword in [:def, :defp] do | ||
| [{function_name, _, arguments} | _] = children | ||
|
|
||
| arity = length(arguments) | ||
angelikatyborska marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| message_part = | ||
| function_name | ||
| |> to_string() | ||
| |> String.slice(0, arity) | ||
|
|
||
| {ast, [message_part | acc]} | ||
| end | ||
|
|
||
| def decode_secret_message_part(ast, acc) do | ||
| {ast, acc} | ||
| end | ||
|
|
||
| def decode_secret_message(string) do | ||
| ast = to_ast(string) | ||
| {_, acc} = Macro.prewalk(ast, [], &decode_secret_message_part/2) | ||
|
|
||
| acc | ||
| |> Enum.reverse() | ||
| |> Enum.join("") | ||
| end | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| defmodule TopSecret do | ||
| def to_ast(string) do | ||
| # Please implement the to_ast/1 function | ||
| end | ||
|
|
||
| def decode_secret_message_part(ast, acc) do | ||
| # Please implement the decode_secret_message_part/2 function | ||
| end | ||
|
|
||
| def decode_secret_message(string) do | ||
| # Please implement the decode_secret_message/1 function | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| defmodule TopSecret.MixProject do | ||
| use Mix.Project | ||
|
|
||
| def project do | ||
| [ | ||
| app: :top_secret, | ||
| version: "0.1.0", | ||
| # elixir: "~> 1.10", | ||
| start_permanent: Mix.env() == :prod, | ||
| deps: deps() | ||
| ] | ||
| end | ||
|
|
||
| # Run "mix help compile.app" to learn about applications. | ||
| def application do | ||
| [ | ||
| extra_applications: [:logger] | ||
| ] | ||
| end | ||
|
|
||
| # Run "mix help deps" to learn about dependencies. | ||
| defp deps do | ||
| [ | ||
| # {:dep_from_hexpm, "~> 0.3.0"}, | ||
| # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} | ||
| ] | ||
| end | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| ExUnit.start() | ||
| ExUnit.configure(exclude: :pending, trace: true, seed: 0) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.