-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathparser.ex
95 lines (64 loc) · 2.47 KB
/
parser.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
defmodule Awake.Parser do
use Awake.Types
alias Minipeg.Parser
alias Awake.Grammar
import Minipeg.{Combinators, Mappers, Parsers}
@moduledoc ~S"""
Parse a pattern into an AST
"""
@doc ~S"""
Parses the pattern
### Verbatim chunks
If we want to print a fixed text for each line of input from stdin, we can use
a verbatim pattern
iex(1)> parse("hello world")
[{:verb, "hello world"}]
but need to escape `%`
iex(2)> parse("%%")
[{:verb, "%"}]
and also "("
iex(3)> parse("((")
[{:verb, "("}]
verbs are glued together
iex(4)> parse("hello ((%%")
[{:verb, "hello (%"}]
### Field chunks
verbs are seperated by fields
iex(5)> parse("hello %c and more%%")
[{:verb, "hello "}, {:field, "c"}, {:verb, " and more%"}]
fields are either predefined, or indices into fields
iex(6)> parse("%c%tm%2%-1%t or %")
[{:field, "c"}, {:field, "tm"}, {:field, 2}, {:field, -1}, {:field, "t"}, {:verb, " or "}, {:field, 0}]
### Ambigous patterns
Assumeing we want to parse the input into `[{:field, 0}, {:field, 0}]`
but, `"%%"` would be parsed into `[{:verb, "%"}]`.
And we want to parse the input into `[{:field, "t"}, {:verb, "s"}]` but `"%ts"` would be parsed into `[{:field, "ts"}]`
How can we fix this?
Enter the empty function, "`()`"
**N.B.** that we can get `[{:verb, "()"}]` easily enough from
the input `"(()"` and also that it is not part of the ast.
iex(7)> parse("%()%")
[{:field, 0}, {:field, 0}]
iex(8)> parse("%t()s")
[{:field, "t"}, {:verb, "s"}]
### Function Pipelines
The syntax of function pipelines is simply a list of s-expressions, however
the preceding field is integrated into the function ast tuple
iex(9)> parse("%(+ 1 2)(tos 16) %c(lpad 5 0)")
[{:pipe, 0, [[:+, 1, 2], [:tos, 16]]}, {:verb, " "}, {:pipe, "c", [[:lpad, 5, 0]]}]
"""
@spec parse(binary()) :: augmented_t()
def parse(pattern) do
with {:ok, ast} <- Parser.parse_string(Grammar.pattern, pattern) do
combine_chunks(ast)
end
end
@spec combine_chunks(ast_t(), ast_t()) :: augmented_t()
defp combine_chunks(ast, result \\ [])
defp combine_chunks([], result), do: Enum.reverse(result)
defp combine_chunks([{:field, field}, {:func, args} | rest], result) do
combine_chunks(rest, [{:pipe, field, args}|result])
end
defp combine_chunks([h|t], result), do: combine_chunks(t, [h|result])
end
# SPDX-License-Identifier: AGPL-3.0-or-later