Current section

Files

Jump to
solid src solid_parser.peg
Raw

src/solid_parser.peg

text <- (object:object / tag:tag / string:blob)* ~;
blob <- (!open_object !open_tag .)* `iolist_to_binary(Node)`;
object <- open_object:open_object space (argument:argument filters:filters / argument:argument)? space close_object:close_object `
case Node of
[_, _, Block, _, _] -> lists:flatten([Block])
end
`;
tag <- cond_if_tag / cond_unless_tag / cond_case_tag / assign_tag / comment_tag / for_tag / counter_tag ~;
counter_tag <- open_tag space (increment / decrement) space field space close_tag `
case Node of
[_, _, <<"increment">>, _, Field, _, _] -> {counter_exp, Field, 1, 0};
[_, _, <<"decrement">>, _, Field, _, _] -> {counter_exp, Field, -1, -1}
end
`;
comment_tag <- open_tag space comment space close_tag text:text
open_tag space endcomment space close_tag `comment`;
assign_tag <- open_tag space assign space field space "=" space argument space close_tag `
case Node of
[_, _, _, _, Field, _, _, _, Argument, _, _] -> {assign_exp, Field, Argument}
end
`;
for_tag <- open_tag space for space argument space "in" space field space close_tag text:text open_tag space endfor space close_tag `
case Node of
[_, _, _, _, Field, _, _, _, Argument, _, _, Text, _, _, _, _, _] -> {for_exp, [Argument, Field, Text]}
end
`;
cond_case_tag <- case_tag
when_tag+
else_tag?
open_tag space endcase space close_tag `
case Node of
[Case, Whens, Else, _, _, _, _, _] ->
WhenMap = lists:foldl(fun({ Value, Text }, Map) -> maps:put(Value, Text, Map) end, #{}, Whens),
[Case, {whens, WhenMap}, Else]
end
`;
case_tag <- open_tag space case space argument space close_tag text:text `
case Node of
[_, _, _Case, _, Arg, _, _, _Text] -> {case_exp, [Arg]}
end
`;
when_tag <- open_tag space when value close_tag text:text `
case Node of
[_, _, _When, Value, _, Text] -> { Value, [Text] }
end
`;
cond_if_tag <- if_tag
elsif_tag*
else_tag?
open_tag space endif space close_tag `
case Node of
[IfExp, [], [], _, _, _EndIf, _, _] -> [IfExp];
[IfExp, [], ElseExp, _, _, _EndIf, _, _] -> [IfExp, ElseExp];
[IfExp, Elsifs, [], _, _, _EndIf, _, _] -> [IfExp, {elsif_exps, Elsifs}];
[IfExp, Elsifs, ElseExp, _, _, _EndIf, _, _] -> [IfExp, Elsifs, ElseExp]
end
`;
if_tag <- open_tag space if expression:boolean_expression close_tag text:text `
case Node of
[_, _, _If, Exp, _, Text] -> {if_exp, [Exp, Text]}
end
`;
elsif_tag <- open_tag space elsif expression:boolean_expression close_tag text:text `
case Node of
[_, _, _Elsif, Exp, _, Text] -> {elsif_exp, [Exp, Text]}
end
`;
else_tag <- (open_tag space else space close_tag text:text) `
case Node of
[_, _, _Else, _, _, ElseText] -> {else_exp, [ElseText]}
end
`;
unless_tag <- open_tag space unless expression:boolean_expression close_tag text:text `
case Node of
[_, _, _Unless, Exp, _, Text] -> {unless_exp, [Exp, Text]}
end
`;
cond_unless_tag <- unless_tag
elsif_tag*
else_tag?
open_tag space endunless space close_tag `
case Node of
[UnlessExp, [], _, _, _EndUnless, _, _] -> [UnlessExp];
[UnlessExp, [], ElseExp, _, _, _EndUnless, _, _] -> [UnlessExp, ElseExp];
[UnlessExp, Elsifs, [], _, _, _EndUnless, _, _] -> [UnlessExp, {elsif_exps, Elsifs}];
[UnlessExp, Elsifs, ElseExp, _, _, _EndUnless, _, _] -> [UnlessExp, Elsifs, ElseExp]
end
`;
expression <- space (argument space operator space argument / boolean) space `
case Node of
[_, [Arg1, _, Op, _, Arg2], _] -> {Arg1, Op, Arg2};
[_, Bool, _] -> Bool
end
`;
boolean_expression <- expression ((and / or) expression)* `
case Node of
[Exp, Exps] -> [Exp | Exps]
end
`;
filters <- (space "|" space filter (":" space arguments)? )+`
[case N of
[_, _, _, Filter, [_, _, Args]] -> {Filter, Args};
[_, _, _, Filter, _] -> {Filter, []}
end || N <- Node]
`;
arguments <- argument (space "," space argument)* `
case Node of
[Arg1, Args] -> [Arg1 | [Arg || [_, _, _, Arg] <- Args]]
end
`;
argument <- value:value / field ~;
field <- [0-9a-zA-Z\._]* access* `
case Node of
[FieldName | [[]]] -> {field, string:split(iolist_to_binary(FieldName), ".", all)};
[FieldName | [Accesses]] ->
{field, string:split(iolist_to_binary(FieldName), ".", all), Accesses}
end
`;
access <- "[" int "]" `
case Node of
[_, Integer, _] -> {access, list_to_integer(binary_to_list(iolist_to_binary(Integer)))}
end
`;
value <- space (string / number / true / false / null) space `lists:nth(2, Node)`;
string <- single_quoted_string / double_quoted_string `
iolist_to_binary(proplists:get_value(string, Node))
`;
%% Terminals
operator <- "==" / "!=" / ">=" / "<=" / ">" / "<" / "contains" `
binary_to_existing_atom(Node, utf8)
`;
open_object <- "{{" ~;
close_object <- "}}" ~;
open_tag <- "{%" ~;
close_tag <- "%}" ~;
if <- "if" ~;
else <- "else" ~;
elsif <- "elsif" ~;
endif <- "endif" ~;
unless <- "unless" ~;
endunless <- "endunless" ~;
case <- "case" ~;
when <- "when" ~;
endcase <- "endcase" ~;
increment <- "increment" ~;
decrement <- "decrement" ~;
assign <- "assign" ~;
for <- "for" ~;
endfor <- "endfor" ~;
comment <- "comment" ~;
endcomment <- "endcomment" ~;
filter <- [a-zA-Z_]* `iolist_to_binary(Node)`;
space <- [ \t\n\s\r]* `{space, iolist_to_binary(Node)}`;
double_quoted_string <- '"' string:(!'"' ("\\\\" / '\\"' / .))* '"' ~;
single_quoted_string <- "'" string:(!"'" ("\\\\" / "\\'" / .))* "'" ~;
number <- int frac? exp?
`
case Node of
[Int, [], []] -> list_to_integer(binary_to_list(iolist_to_binary(Int)));
[Int, Frac, []] -> list_to_float(binary_to_list(iolist_to_binary([Int, Frac])));
[Int, [], Exp] -> list_to_float(binary_to_list(iolist_to_binary([Int, ".0", Exp])));
_ -> list_to_float(binary_to_list(iolist_to_binary(Node)))
end
`;
int <- '-'? ((non_zero_digit digit+) / digit) ~;
frac <- '.' digit+ ~;
exp <- e digit+ ~;
e <- [eE] ('+' / '-')? ~;
non_zero_digit <- [1-9] ~;
digit <- [0-9] ~;
boolean <- true / false ~;
true <- 'true' `true`;
false <- 'false' `false`;
null <- 'nil' `nil`;
and <- 'and' `bool_and`;
or <- 'or' `bool_or`;