commit ab74e2a25ebb14d209c426f7f62ce334b356ec4e Author: Daniel Flanagan Date: Sat May 11 13:01:39 2019 -0500 Initial commit diff --git a/.formatter.exs b/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..930abcb --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# 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"). +lytlang-*.tar + +# Elixir language server files +/.elixir_ls/* + +# Temporary files +*.tmp +*.swp diff --git a/README.md b/README.md new file mode 100644 index 0000000..405fe4d --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# Lytlang + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `lytlang` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:lytlang, "~> 0.1.0"} + ] +end +``` + +Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) +and published on [HexDocs](https://hexdocs.pm). Once published, the docs can +be found at [https://hexdocs.pm/lytlang](https://hexdocs.pm/lytlang). + diff --git a/config/config.exs b/config/config.exs new file mode 100644 index 0000000..841338b --- /dev/null +++ b/config/config.exs @@ -0,0 +1,30 @@ +# This file is responsible for configuring your application +# and its dependencies with the aid of the Mix.Config module. +use Mix.Config + +# This configuration is loaded before any dependency and is restricted +# to this project. If another project depends on this project, this +# file won't be loaded nor affect the parent project. For this reason, +# if you want to provide default values for your application for +# third-party users, it should be done in your "mix.exs" file. + +# You can configure your application as: +# +# config :lytlang, key: :value +# +# and access this configuration in your application as: +# +# Application.get_env(:lytlang, :key) +# +# You can also configure a third-party app: +# +# config :logger, level: :info +# + +# It is also possible to import configuration files, relative to this +# directory. For example, you can emulate configuration per environment +# by uncommenting the line below and defining dev.exs, test.exs and such. +# Configuration from the imported file will override the ones defined +# here (which is why it is important to import them last). +# +# import_config "#{Mix.env()}.exs" diff --git a/lib/lytlang.ex b/lib/lytlang.ex new file mode 100644 index 0000000..fe5455a --- /dev/null +++ b/lib/lytlang.ex @@ -0,0 +1,29 @@ +defmodule Lytlang do + @moduledoc """ + Documentation for Lytlang. + """ + + @doc """ + Hello world. + + ## Examples + + iex> Lytlang.hello() + :world + + """ + def hello do + :world + end + + @spec transpile_file(String.t()) :: String.t() + def transpile_file(file_path) do + file_path + |> File.read!() + |> transpile_block() + end + + def transpile_block(s) do + "ayy#{s}" + end +end diff --git a/mix.exs b/mix.exs new file mode 100644 index 0000000..6a4143a --- /dev/null +++ b/mix.exs @@ -0,0 +1,28 @@ +defmodule Lytlang.MixProject do + use Mix.Project + + def project do + [ + app: :lytlang, + version: "0.1.0", + elixir: "~> 1.8", + 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 diff --git a/test/fixtures/example.ex b/test/fixtures/example.ex new file mode 100644 index 0000000..36b529a --- /dev/null +++ b/test/fixtures/example.ex @@ -0,0 +1,23 @@ +defmodule Leetcode do + @doc """ + LeetCode #1: two_sum + + TODO: store a map of complements (differences) as iterating for O(n) + """ + + @spec two_sum(list, int, int) :: any + def two_sum(_, _, i \\ 0) + + def two_sum(nums, target, current_index \\ 0) + + def two_sum([], _target, _i), do: nil + + def two_sum([cur | rest], target, current_index) do + case Enum.find_index(rest, fn x -> cur + x == target end) do + nil -> two_sum(rest, target, current_index + 1) + i -> [current_index, 1 + current_index + i] + end + end + + # ... +end diff --git a/test/fixtures/example.lyt b/test/fixtures/example.lyt new file mode 100644 index 0000000..cca7230 --- /dev/null +++ b/test/fixtures/example.lyt @@ -0,0 +1,51 @@ +!mod Leetcode + +@doc + LeetCode #1: two_sum + + TODO: store a map of complements (differences) as iterating for O(n) + +fn two_sum _:list _:int i=0 :: + [] _ _ -> nil + [cur | rest] target current_index + Enum.find_index rest, fn x -> cur + x == target :: + nil -> two_sum rest target current_index + i -> [current_index, 1 + current_index + i] + +@doc LeetCode #2: add_two_numbers + +fn add_two_numbers _:list _:list _=[] i=0 :: + [] _ l m, _ [] l m -> finish_add_two_numbers l m + [n1 | r1] [n2 | r2] l carry + add_two_numbers r1 r2 [rem (carry + n1 + n2) 10) | l] (div n1 + n2 10) + +fn finish_add_two_numbers l:list m:int -> m == 0 ? l : [m | l] + +@doc + LeetCode #3: longest non-repeating susbtring + + TODO: better utility function names? + +fn longest_non_repeating_substring s + s |> String.codepoints |> Enum.reduce {0 0 0 %{}} &ln3_reducer/2 |> elem 0 + +fn ln3_new_least least map char + Map.has_key? map char ? max least ((Map.get map char) + 1) : least + +fn ln3_reducer char {mx i least map} + least = ln3_new_least least map char + {(max mx (i - least + 1) (i + 1) least (Map.put map char i)} + +@doc + LeetCode #4: median of sorted arrays + + TODO: solution should me O(log(m+n)) + TODO: finish an actual solution? + +fn median_of_sorted_arrays _ _ -> 3 + +@doc LeetCode #65: Valid Number + +@valid_decimal_number_regex ~r/^\s*(?:\+|-)?\d+(?:\.(?=\d))?\d*(?:e(?=[\d\+-]))?(?:\+|-)?\d*(?:\.(?=\d))?\s*$/ + +fn valid_decimal_number s -> Regex.match? @valid_decimal_number_regex s diff --git a/test/fixtures/tiny.exs b/test/fixtures/tiny.exs new file mode 100644 index 0000000..31ac871 --- /dev/null +++ b/test/fixtures/tiny.exs @@ -0,0 +1,19 @@ +defmodule Leetcode do + @doc """ + LeetCode #1: two_sum + + TODO: store a map of complements (differences) as iterating for O(n) + """ + + @spec two_sum(list, int, int) :: any + def two_sum(_, _, i \\ 0) + + def two_sum([], _, _), do: nil + + def two_sum([cur | rest], target, current_index) do + case Enum.find_index(rest, fn x -> cur + x == target end) do + nil -> two_sum(rest, target, current_index + 1) + i -> [current_index, 1 + current_index + i] + end + end +end diff --git a/test/fixtures/tiny.lyt b/test/fixtures/tiny.lyt new file mode 100644 index 0000000..66f256f --- /dev/null +++ b/test/fixtures/tiny.lyt @@ -0,0 +1,13 @@ +!mod Leetcode + +@doc + LeetCode #1: two_sum + + TODO: store a map of complements (differences) as iterating for O(n) + +fn two_sum _:list _:int i=0 :: + [] _ _ -> nil + [cur | rest] target current_index + Enum.find_index rest, fn x -> cur + x == target :: + nil -> two_sum rest target current_index + i -> [current_index, 1 + current_index + i] diff --git a/test/lytlang_test.exs b/test/lytlang_test.exs new file mode 100644 index 0000000..779aee4 --- /dev/null +++ b/test/lytlang_test.exs @@ -0,0 +1,27 @@ +defmodule LytlangTest do + use ExUnit.Case + doctest Lytlang + + test "greets the world" do + assert Lytlang.hello() == :world + end + + test "transpiles module" do + input = """ + !mod EmptyModule + """ + + output = """ + defmodule EmptyModule + end + """ + + assert Lytlang.transpile_block(input) == output + end + + @tag :skip + test "transpiles example tiny module file correctly" do + output = File.read!("./test/fixtures/tiny.exs") + assert Lytlang.transpile_file("./test/fixtures/tiny.lyt") == output + end +end diff --git a/test/test_helper.exs b/test/test_helper.exs new file mode 100644 index 0000000..d13e5fc --- /dev/null +++ b/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start(exclude: [:skip])