Current section
Files
Jump to
Current section
Files
lib/zig/parser/imports.ex
defmodule Zig.Parser.Imports do
@moduledoc """
For parsing, looking for imports, cimports, and usingnamespace directives.
To be completed later
"""
import NimbleParsec
defstruct imports: [], identifier: nil, pub: false
@typep identifier_t :: :usingnamespace | String.t
@type t :: %__MODULE__{
imports: [{identifier_t, Path.t} | {:pub, identifier_t, Path.t}],
identifier: atom,
pub: boolean
}
# designed to ninja in this struct as necessary.
@type line_info :: {non_neg_integer, non_neg_integer}
@type parsec_retval :: {[String.t], t}
initialize = post_traverse(empty(), :initializer)
@spec initializer(String.t, [String.t], t, line_info, non_neg_integer)
:: parsec_retval
defp initializer(_, _, context, _, _), do: {[], struct(__MODULE__, context)}
whitespace = ascii_string([?\s, ?\n], min: 1)
filename = ascii_string([not: ?"], min: 1)
identifier = ascii_char([?a..?z, ?A..?Z, ?_])
|> optional(ascii_string([?a..?z, ?A..?Z, ?0..?9, ?_], min: 1))
|> reduce({IO, :iodata_to_binary, []})
usingnamespace = optional(
string("pub")
|> concat(ignore(whitespace)))
|> string("usingnamespace")
|> ignore(whitespace)
import_const = optional(
string("pub")
|> concat(ignore(whitespace)))
|> ignore(
string("const")
|> concat(whitespace))
|> concat(identifier)
|> ignore(
optional(whitespace)
|> string("=")
|> optional(whitespace))
prefix = choice(
[usingnamespace, import_const])
|> post_traverse(:register_identifier)
import_stmt =
prefix
|> ignore(
string("@import")
|> optional(whitespace)
|> string("(")
|> optional(whitespace)
|> string("\""))
|> concat(filename)
|> ignore(
string("\"")
|> optional(whitespace)
|> string(")"))
|> post_traverse(:register_import)
include_stmt =
ignore(
string("@cInclude")
|> optional(whitespace)
|> string("(")
|> optional(whitespace)
|> string("\""))
|> concat(filename)
|> ignore(
string("\"")
|> optional(whitespace)
|> string(")"))
|> post_traverse(:register_include)
defp register_identifier(_rest, ["usingnamespace" | rest], context, _, _) do
{[], %{context | identifier: :usingnamespace, pub: pub?(rest)}}
end
defp register_identifier(_rest, [identifier | rest], context, _, _) do
{[], %{context | identifier: identifier, pub: pub?(rest)}}
end
defp pub?([]), do: false
defp pub?(["pub"]), do: true
defp register_import(_rest, [path], context, _, _) do
{[],
%{context |
imports: [make_identifier(path, context) | context.imports],
identifier: nil,
pub: false}}
end
defp make_identifier(path, context) do
if context.pub do
{:pub, context.identifier, path}
else
{context.identifier, path}
end
end
defp register_include(_rest, [path], context, _, _) do
{[], %{context | imports: [{:cinclude, path} | context.imports]}}
end
if Mix.env == :test do
defparsec :parse_import_const, concat(initialize, import_const)
defparsec :parse_import_stmt, concat(initialize, import_stmt)
defparsec :parse_include_stmt, concat(initialize, include_stmt)
end
parse_imports =
initialize
|> repeat(choice([
import_stmt,
include_stmt,
ascii_char([0..255])
]))
defparsec :parse_imports, parse_imports
def parse(code) do
{:ok, _, _, %Zig.Parser.Imports{imports: imports}, _, _} = parse_imports(code)
imports
end
end