Current section

Files

Jump to
zig_parser lib zig.parser control.ex
Raw

lib/zig.parser/control.ex

defmodule Zig.Parser.IfOptions do
defstruct [:position]
end
defmodule Zig.Parser.ForOptions do
defstruct [:position, :label, inline: false]
end
defmodule Zig.Parser.WhileOptions do
defstruct [:position, :label, inline: false]
end
defmodule Zig.Parser.SwitchOptions do
defstruct [:position, :label, comptime: false]
end
defmodule Zig.Parser.Control do
@moduledoc false
alias Zig.Parser.IfOptions
alias Zig.Parser.ForOptions
alias Zig.Parser.SwitchOptions
alias Zig.Parser.WhileOptions
# control flow parsers: if, for, while, switch
def parse_for([:LPAREN, expr, :RPAREN | rest]) do
parse_for_payload(rest, enum: expr)
end
defp parse_for_payload([:|, :*, payload | rest], parts) do
parse_for_index(rest, Keyword.merge(parts, ptr_payload: payload))
end
defp parse_for_payload([:|, payload | rest], parts) do
parse_for_index(rest, Keyword.merge(parts, payload: payload))
end
defp parse_for_index([:COMMA, index, :| | rest], parts) do
parse_for_code(rest, Keyword.merge(parts, index: index))
end
defp parse_for_index([:| | rest], parts) do
parse_for_code(rest, parts)
end
@stop [[], [:SEMICOLON]]
defp parse_for_code([body | stop], parts) when stop in @stop do
{:for, %ForOptions{}, Keyword.merge(parts, do: body)}
end
defp parse_for_code([body, :else, elsebody], parts) do
{:for, %ForOptions{}, Keyword.merge(parts, do: body, else: elsebody)}
end
# for parsing if statements
def parse_if([:LPAREN, condition, :RPAREN, :|, :*, payload, :|, consequence | rest]) do
parse_else(rest, condition: condition, ptr_payload: payload, consequence: consequence)
end
def parse_if([:LPAREN, condition, :RPAREN, :|, payload, :|, consequence | rest]) do
parse_else(rest, condition: condition, payload: payload, consequence: consequence)
end
def parse_if([:LPAREN, condition, :RPAREN, consequence | rest]) do
parse_else(rest, condition: condition, consequence: consequence)
end
defp parse_else(tail, parts) when tail in @stop do
{:if, %IfOptions{}, parts}
end
defp parse_else([:else, :|, payload, :|, contrast], parts) do
{:if, %IfOptions{}, Keyword.merge(parts, else_payload: payload, else: contrast)}
end
defp parse_else([:else, contrast | _], parts) do
{:if, %IfOptions{}, Keyword.merge(parts, else: contrast)}
end
# while loop parsing
def parse_while([:LPAREN, condition, :RPAREN | rest]) do
parse_while_payload(rest, condition: condition)
end
defp parse_while_payload([:|, payload, :| | rest], parts) do
parse_while_continue(rest, Keyword.merge(parts, payload: payload))
end
defp parse_while_payload([:|, :*, payload, :| | rest], parts) do
parse_while_continue(rest, Keyword.merge(parts, ptr_payload: payload))
end
defp parse_while_payload(rest, parts) do
parse_while_continue(rest, parts)
end
defp parse_while_continue([:LPAREN, continue, :RPAREN | rest], parts) do
parse_while_body(rest, Keyword.merge(parts, continue: continue))
end
defp parse_while_continue(rest, parts) do
parse_while_body(rest, parts)
end
defp parse_while_body([:COLON, :LPAREN, next, :RPAREN | rest], parts) do
parse_while_body(rest, Keyword.merge(parts, next: next))
end
defp parse_while_body([body | stop], parts) when stop in @stop do
{:while, %WhileOptions{}, Keyword.merge(parts, do: body)}
end
defp parse_while_body([body, :else, else_body], parts) do
{:while, %WhileOptions{}, Keyword.merge(parts, do: body, else: else_body)}
end
defp parse_while_body([body, :else, :|, else_payload, :|, else_body], parts) do
{:while, %WhileOptions{},
Keyword.merge(parts, do: body, else_payload: else_payload, else: else_body)}
end
def parse_switch([:LPAREN, condition, :RPAREN, :LBRACE | rest]) do
{:switch, %SwitchOptions{},
Keyword.merge([condition: condition], parse_switch_prongs(rest, []))}
end
defp parse_switch_prongs([expr, :"=>", :|, capture, :|, expr2 | rest], so_far) do
parse_switch_prongs(rest, [{expr, capture, expr2} | so_far])
end
defp parse_switch_prongs([expr, :"=>", expr2 | rest], so_far) do
parse_switch_prongs(rest, [{expr, expr2} | so_far])
end
defp parse_switch_prongs([:COMMA | rest], so_far), do: parse_switch_prongs(rest, so_far)
defp parse_switch_prongs([:RBRACE], so_far), do: [switches: Enum.reverse(so_far)]
end