WIP
This commit is contained in:
parent
afc0738a31
commit
06f1e3195f
4 changed files with 75 additions and 15 deletions
|
@ -1,23 +1,28 @@
|
||||||
defmodule Lytlang do
|
defmodule Lytlang do
|
||||||
|
@root_module :Lytlang
|
||||||
|
|
||||||
def eval(string) do
|
def eval(string) do
|
||||||
{value, _} =
|
{value, _} =
|
||||||
string
|
string
|
||||||
|> from_lytlang()
|
|> from_lytlang()
|
||||||
|> IO.inspect()
|
|
||||||
|> Code.eval_quoted()
|
|> Code.eval_quoted()
|
||||||
|> IO.inspect()
|
|
||||||
|
|
||||||
value
|
value
|
||||||
end
|
end
|
||||||
|
|
||||||
def from_lytlang(string, binding \\ [], opts \\ []) do
|
def from_lytlang(string, binding \\ [], opts \\ []) do
|
||||||
string |> String.to_charlist() |> tokenize() |> parse() |> transform(binding, opts)
|
string
|
||||||
|
|> String.to_charlist()
|
||||||
|
|> tokenize()
|
||||||
|
|> parse()
|
||||||
|
|> to_ast_node(binding, opts)
|
||||||
|
|> to_elixir_ast(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
def tokenize(string) do
|
def tokenize(string) do
|
||||||
{:ok, tokens, _} =
|
{:ok, tokens, _} =
|
||||||
:lytlang_lexer.string(string)
|
:lytlang_lexer.string(string)
|
||||||
|> IO.inspect()
|
|> IO.inspect(label: "Tokens")
|
||||||
|
|
||||||
tokens
|
tokens
|
||||||
end
|
end
|
||||||
|
@ -25,28 +30,77 @@ defmodule Lytlang do
|
||||||
def parse(tokens) do
|
def parse(tokens) do
|
||||||
{:ok, tree} =
|
{:ok, tree} =
|
||||||
:lytlang_parser.parse(tokens)
|
:lytlang_parser.parse(tokens)
|
||||||
|> IO.inspect()
|
|> IO.inspect(label: "Parsed")
|
||||||
|
|
||||||
tree
|
tree
|
||||||
end
|
end
|
||||||
|
|
||||||
def transform(ast, binding \\ [], opts \\ [])
|
@type astnode :: {any, {keyword, keyword, keyword}, list}
|
||||||
|
@type ex_astnode :: {any, keyword, any}
|
||||||
|
|
||||||
def transform([] = _expr_list, _binding, _opts), do: []
|
# @spec to_elixir_ast(astnode, keyword) :: ex_astnode
|
||||||
|
def to_elixir_ast(astnode, opts \\ [])
|
||||||
|
|
||||||
def transform([expr | rest] = _expr_list, binding, opts) do
|
def to_elixir_ast(s, opts) when is_list(s) do
|
||||||
[transform(expr, binding, opts) | transform(rest, binding, opts)]
|
Enum.map(s, fn node ->
|
||||||
|
to_elixir_ast(node, opts)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def transform({:binary_op, _line, op, left, right}, binding, _) do
|
def to_elixir_ast({{:literal, expr}, {_meta, _binding, _ast_opts}, _leaves}, _opts) do
|
||||||
{op, binding, [transform(left), transform(right)]}
|
expr
|
||||||
|
|> IO.inspect(label: "EX AST")
|
||||||
end
|
end
|
||||||
|
|
||||||
def transform({:unary_op, line, op, left}, _, _) do
|
def to_elixir_ast({s, {_meta, binding, _ast_opts}, leaves}, _opts) do
|
||||||
{:op, line, op, transform(left)}
|
{s, binding, to_elixir_ast(leaves)}
|
||||||
|
|> IO.inspect(label: "EX AST")
|
||||||
end
|
end
|
||||||
|
|
||||||
def transform({:integer, _, n} = _expr, _, _), do: n
|
@spec to_ast_node(any, keyword, keyword) :: astnode
|
||||||
|
def to_ast_node(ast, binding \\ [], opts \\ [])
|
||||||
|
|
||||||
|
def to_ast_node([], binding, opts), do: {[], {binding, opts}}
|
||||||
|
|
||||||
|
def to_ast_node(expr_list, binding, opts) when is_list(expr_list) do
|
||||||
|
Enum.reduce(expr_list, {nil, {[], binding, opts}, []}, fn expr,
|
||||||
|
{_s, {_meta, binding, opts},
|
||||||
|
_operands} ->
|
||||||
|
{s, {nmeta, nbinding, nopts}, operands} = to_ast_node(expr, binding, opts)
|
||||||
|
|
||||||
|
{s, {nmeta, Keyword.merge(binding, nbinding), Keyword.merge(opts, nopts)}, operands}
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_ast_node({:list_op, line, op, operands}, binding, opts) when is_list(operands) do
|
||||||
|
{op, {[line: line], binding, opts},
|
||||||
|
[Enum.map(operands, fn o -> to_ast_node(o, binding, opts) end)]}
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_ast_node({:binary_op, line, op, left, right}, binding, opts) do
|
||||||
|
{op, {[line: line], binding, opts}, [to_ast_node(left), to_ast_node(right)]}
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_ast_node({:unary_op, line, op, left}, binding, opts) do
|
||||||
|
{op, {[line: line], binding, opts}, [to_ast_node(left)]}
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_ast_node({:var, line, left} = _expr, binding, opts) do
|
||||||
|
# TODO: probably need to look in bindings? or shadowing so maybe not?
|
||||||
|
to_ast_node({:unary_op, line, left, {:literal, line, @root_module}}, binding, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_ast_node({:match, line, left, right} = _expr, binding, opts) do
|
||||||
|
to_ast_node({:binary_op, line, :=, left, right}, binding, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_ast_node({:integer, line, val} = _expr, binding, opts) do
|
||||||
|
to_ast_node({:literal, line, val}, binding, opts)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_ast_node({:literal, line, val} = _expr, binding, opts) do
|
||||||
|
{{:literal, val}, {[line: line], binding, opts}, []}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -7,6 +7,7 @@ D = [0-9]
|
||||||
U = [A-Z]
|
U = [A-Z]
|
||||||
L = [a-z]
|
L = [a-z]
|
||||||
WS = [\s]
|
WS = [\s]
|
||||||
|
LF = \n
|
||||||
|
|
||||||
Rules.
|
Rules.
|
||||||
|
|
||||||
|
@ -22,10 +23,13 @@ Rules.
|
||||||
\) : { token, { ')', TokenLine } }.
|
\) : { token, { ')', TokenLine } }.
|
||||||
= : { token, { '=', TokenLine } }.
|
= : { token, { '=', TokenLine } }.
|
||||||
-> : { token, { '->', TokenLine } }.
|
-> : { token, { '->', TokenLine } }.
|
||||||
; : { token, { ';', TokenLine } }.
|
; : { token, { eol, TokenLine } }.
|
||||||
|
{LF} : { token, { eol, TokenLine } }.
|
||||||
|
|
||||||
{Comment} : skip_token.
|
{Comment} : skip_token.
|
||||||
{WS}+ : skip_token.
|
{WS}+ : skip_token.
|
||||||
|
% {LF}+ : skip_token.
|
||||||
|
% {CRLF}+ : skip_token.
|
||||||
% ({Comment}|{Whitespace})*(\n({Comment}|{Whitespace})*)+ : { token, { eol, TokenLine } }.
|
% ({Comment}|{Whitespace})*(\n({Comment}|{Whitespace})*)+ : { token, { eol, TokenLine } }.
|
||||||
|
|
||||||
Erlang code.
|
Erlang code.
|
||||||
|
|
|
@ -63,6 +63,7 @@ fun_expr -> stabber eol body :
|
||||||
fun_expr -> max_expr : '$1'.
|
fun_expr -> max_expr : '$1'.
|
||||||
|
|
||||||
%% Minimum expressions
|
%% Minimum expressions
|
||||||
|
max_expr -> var : '$1'.
|
||||||
max_expr -> number : '$1'.
|
max_expr -> number : '$1'.
|
||||||
max_expr -> '(' expr ')' : '$2'.
|
max_expr -> '(' expr ')' : '$2'.
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ defmodule LytlangTest do
|
||||||
{"2 + (3 * 8)", 26},
|
{"2 + (3 * 8)", 26},
|
||||||
{"8 - 3", 5},
|
{"8 - 3", 5},
|
||||||
{"8 / 4", 2.0},
|
{"8 / 4", 2.0},
|
||||||
|
{"a = 8\na + 9", 17},
|
||||||
{"2 + 3", 5}
|
{"2 + 3", 5}
|
||||||
]
|
]
|
||||||
|> Enum.map(fn {string, val} ->
|
|> Enum.map(fn {string, val} ->
|
||||||
|
|
Loading…
Reference in a new issue