Current section
Files
Jump to
Current section
Files
lib/renewex.ex
defmodule Renewex do
@moduledoc """
The `Renewex` module provides functionality for parsing [Renew](http://renew.de) source files (*.rnw).
"""
alias Renewex.Serializer
alias Renewex.Grammar
alias Renewex.Document
alias Renewex.Parser
alias Renewex.Tokenizer
@doc """
Parses the content of a .rnw file saved by [Renew](http://renew.de).
## Parameters
- `input`: The content of an .rnw file as string
## Returns
- `{:ok, root, refs}`: On success, returns the root of the parsed document tree and a list of references.
- `{:error, reason}`: On failure, returns an error tuple with the reason for failure.
"""
def parse_document(input) do
with {:ok, document, parser} <-
input
|> Tokenizer.scan()
|> Tokenizer.skip_whitespace()
|> Parser.detect_document_version()
|> Parser.parse_storable(nil, false) do
with {parser, size} <- parse_size(parser),
version <- Parser.get_version(parser),
{:ok, refs} <- Parser.finalize(parser) do
{:ok, Document.new(version, document, refs, size)}
end
else
e -> e
end
end
@doc """
Convert a document into a serialized binary string according to the [Renew](http://renew.de) (*.rnw) file format.
## Parameters
- `document`: The renew document to serialize
## Returns
- `{:ok, string}`: On success, returns the serialized document as string.
- `{:error, reason}`: On failure, returns an error tuple with the reason for failure.
"""
def serialize_document(%Document{version: version, root: root, refs: refs, size: size}) do
serializer = Serializer.new(refs, Grammar.new(version))
with {:ok, ser} <- Serializer.serialize_storable(serializer, root) do
ser =
if version == -1,
do: ser,
else: Serializer.prepend_token(ser, {:int, version})
ser =
if size == nil,
do: ser,
else:
Enum.reduce(Tuple.to_list(size), ser, fn s, ser ->
Serializer.append_token(ser, {:int, s})
end)
{:ok, Serializer.get_output_string(ser)}
else
err -> err
end
end
# Parses the integers at the end of a renew document.
# These integers represent the position and size of the renew
# application window while the document was saved.
#
# But renew files are NOT REQUIRED to contains the window dimensions.
# This function tries to read for integer tokens or nothing at all.
defp parse_size(parser) do
case Parser.try_parse(parser, [:int, :int, :int, :int]) do
{:none, parser} -> {parser, nil}
{[{:int, x}, {:int, y}, {:int, w}, {:int, h}], parser} -> {parser, {x, y, w, h}}
end
end
end