diff --git a/README.md b/README.md index 204cfb1..62d2920 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ probably never even happen. ## Development Resources ++ http://erlang.org/doc/man/yecc.html ++ http://erlang.org/doc/man/leex.html + https://hexdocs.pm/elixir/syntax-reference.html#the-elixir-ast + https://medium.com/cirru-project/resources-on-elixir-ast-e045b613f284 + https://elixir-lang.org/getting-started/meta/quote-and-unquote.html diff --git a/lib/lytlang.ex b/lib/lytlang.ex index 0c6de13..055274f 100644 --- a/lib/lytlang.ex +++ b/lib/lytlang.ex @@ -31,7 +31,7 @@ defmodule Lytlang do end def parse(tokens, _opts \\ []) do - {:ok, [tree]} = + {:ok, tree} = :lytlang_parser.parse(tokens) |> IO.inspect(label: "Parsed") @@ -40,10 +40,16 @@ defmodule Lytlang do def eval_elixir(ast, opts \\ []) + def eval_elixir(ast, _opts) when is_list(ast) do + {:__block__, [], ast} + |> IO.inspect(label: "Wrapped in Block") + |> eval_elixir() + end + def eval_elixir(ast, _opts) do - {:__block__, [], [ast]} + ast |> Code.eval_quoted() - |> IO.inspect() + |> IO.inspect(label: "Evaluated as Elixir") end end diff --git a/src/lytlang_lexer.xrl b/src/lytlang_lexer.xrl index 77153c3..45720a2 100644 --- a/src/lytlang_lexer.xrl +++ b/src/lytlang_lexer.xrl @@ -13,7 +13,7 @@ Rules. {D}+\.{D}+ : { token, { float, TokenLine, list_to_float(TokenChars) } }. {D}+ : { token, { integer, TokenLine, list_to_integer(TokenChars) } }. -({L}|_)({U}{L}{D}|_)* : { token, var(TokenChars, TokenLine) }. +[{L}|_][{U}{L}{D}|_]+ : { token, var(TokenChars, TokenLine) }. \+ : { token, { '+', TokenLine } }. - : { token, { '-', TokenLine } }. @@ -22,8 +22,18 @@ Rules. // : { token, { '//', TokenLine } }. \( : { token, { '(', TokenLine } }. \) : { token, { ')', TokenLine } }. +\[ : { token, { '[', TokenLine } }. +\] : { token, { ']', TokenLine } }. +\< : { token, { '<', TokenLine } }. +\> : { token, { '>', TokenLine } }. +\{ : { token, { '{', TokenLine } }. +\} : { token, { '}', TokenLine } }. +\" : { token, { '"', TokenLine } }. +\' : { token, { '\'', TokenLine } }. +, : { token, { ',', TokenLine } }. = : { token, { '=', TokenLine } }. -> : { token, { '->', TokenLine } }. +: : { token, { ':', TokenLine } }. ; : { token, { eol, TokenLine } }. {LF} : { token, { eol, TokenLine } }. diff --git a/src/lytlang_parser.yrl b/src/lytlang_parser.yrl index d348650..8f66e46 100644 --- a/src/lytlang_parser.yrl +++ b/src/lytlang_parser.yrl @@ -1,22 +1,8 @@ Nonterminals - grammar - e_list - e - assignment - add - sub - mult - div - idiv - unary - number - unary - . + grammar e_list e assignment add sub mult div idiv unary number list map_el map. Terminals - var float integer eol - '+' '-' '*' '/' '//' '(' ')' '=' - . + var float integer eol '+' '-' '*' '/' '//' '(' ')' '=' '"' '\'' '{' '}' '[' ']' '<' '>' ',' ':'. Rootsymbol grammar. Endsymbol '$end'. @@ -35,17 +21,15 @@ e_list -> eol : []. e_list -> e : ['$1']. e_list -> e eol : ['$1']. e_list -> eol e_list : '$2'. -e_list -> e eol e_list : ['$1'|'$3']. +e_list -> e eol e_list : ['$1' | '$3']. -%% Minimum expressions -e -> var : '$1'. +e -> '<' e ',' e '>' : {'$2', '$4'}. +e -> '<' list '>' : {'{}', [], '$2'}. + +e -> '[' ']' : []. +e -> var : ?var('$1'). e -> number : '$1'. e -> '(' e ')' : '$2'. - -%% Numbers -number -> float : '$1'. -number -> integer : ?e(3, '$1'). - e -> mult : '$1'. e -> div : '$1'. e -> idiv : '$1'. @@ -53,26 +37,29 @@ e -> assignment : '$1'. e -> add : '$1'. e -> sub : '$1'. e -> unary : '$1'. +e -> '"' '"' : list_to_binary([]). +e -> '"' var '"' : list_to_binary('$2'). +e -> '[' list ']' : '$2'. +e -> '{' map '}' : '$2'. -assignment -> var '=' e : - { '=', ?meta('$2'), [?var('$1'), '$3'] }. +list -> '$empty' : []. +list -> e : ['$1']. +list -> e ',' list : ['$1' | '$3']. -%% Arithmetic operations -add -> e '+' e : - { '+', ?meta('$2'), ['$1', '$3'] }. +map_el -> var ':' e : {?e(3, '$1'), '$3'}. -sub -> e '-' e : - { '-', ?meta('$2'), ['$1', '$3'] }. - -mult -> e '*' e : - { '*', ?meta('$2'), ['$1', '$3'] }. - -div -> e '/' e : - { '/', ?meta('$2'), ['$1', '$3'] }. - -idiv -> e '//' e : - { 'div', ?meta('$2'), ['$1', '$3'] }. +map -> '$empty' : {'%{}', [], []}. +map -> map_el : {'%{}', [], ['$1']}. +map -> map_el ',' map : {'%{}', [], ['$1' | '$3']}. +number -> float : ?e(3, '$1'). +number -> integer : ?e(3, '$1'). +assignment -> var '=' e : { '=', ?meta('$2'), [?var('$1'), '$3'] }. +add -> e '+' e : { '+', ?meta('$2'), ['$1', '$3'] }. +sub -> e '-' e : { '-', ?meta('$2'), ['$1', '$3'] }. +mult -> e '*' e : { '*', ?meta('$2'), ['$1', '$3'] }. +div -> e '/' e : { '/', ?meta('$2'), ['$1', '$3'] }. +idiv -> e '//' e : { 'div', ?meta('$2'), ['$1', '$3'] }. unary -> '+' e : { '+', ?meta('$1'), ?op('$1'), '$2' }. unary -> '-' e : { '-', ?meta('$1'), ?op('$1'), '$2' }. diff --git a/test/lytlang_test.exs b/test/lytlang_test.exs index 4d25af8..33063e0 100644 --- a/test/lytlang_test.exs +++ b/test/lytlang_test.exs @@ -1,5 +1,5 @@ defmodule LytlangTest do - use ExUnit.Case + use ExUnit.Case, async: false doctest Lytlang test "arithmetic" do @@ -16,10 +16,59 @@ defmodule LytlangTest do {"8 / 4", 2.0}, {"8 // 4", 2}, {"a = 8\na + 9", 17}, + {"a_number = 8\na_number + 9", 17}, {"2 + 3", 5} ] |> Enum.map(fn {string, val} -> assert Lytlang.eval(string) == val end) end + + test "lists" do + [ + {"[]", []}, + {"[2]", [2]}, + {"[2, 3]", [2, 3]}, + {"[2, [3, 4], [5, [6, [7]]]]", [2, [3, 4], [5, [6, [7]]]]}, + {"[2, 3, 4, 5, 6, 7]", [2, 3, 4, 5, 6, 7]} + ] + |> Enum.map(fn {string, val} -> + assert Lytlang.eval(string) == val + end) + end + + test "tuples" do + [ + {"<>", {}}, + {"<2>", {2}}, + {"<2, 3>", {2, 3}}, + {"<2, <3, 4>, <5, <6, <7>>>>", {2, {3, 4}, {5, {6, {7}}}}}, + {"<2, 3, 4, 5, 6, 7>", {2, 3, 4, 5, 6, 7}} + ] + |> Enum.map(fn {string, val} -> + assert Lytlang.eval(string) == val + end) + end + + test "strings" do + [ + {"\"\"", ""}, + {"\"abcd\"", "abcd"} + ] + |> Enum.map(fn {string, val} -> + assert Lytlang.eval(string) == val + end) + end + + test "maps" do + [ + {"{}", %{}}, + {"{x : 9}", %{:x => 9}}, + {"{x : 9}", %{x: 9}}, + {"{x: 9}", %{x: 9}} + ] + |> Enum.map(fn {string, val} -> + assert Lytlang.eval(string) == val + end) + end end