2015-10-02 to 2015-10-03
Luke Imhoff
Kronic.Deth@gmail.com | |
@KronicDeth | |
@KronicDeth |
Date | Days | Commits | Version | |||
---|---|---|---|---|---|---|
Delta | Total | Delta | Total | Commits/Day | Name | |
2014-07-27 | 0 | 0 | 1 | 1 | 1.00 | Initial |
2014‑08‑02 | 6 | 6 | 18 | 19 | 3.00 | 0.0.1 |
2014‑08‑03 | 1 | 7 | 14 | 33 | 14.00 | 0.0.2 |
2014‑08‑08 | 5 | 12 | 10 | 43 | 2.00 | 0.0.3 |
2014‑09‑13 | 36 | 48 | 64 | 107 | 1.78 | 0.1.0 |
2014‑09‑20 | 7 | 55 | 4 | 111 | 0.57 | 0.1.1 |
2014‑09‑25 | 5 | 60 | 12 | 123 | 2.50 | 0.1.2 |
2014‑10‑14 | 19 | 79 | 23 | 146 | 1.21 | 0.1.3 |
2014‑11‑30 | 47 | 126 | 226 | 373 | 4.81 | 0.2.0 |
2015‑04‑03 | 124 | 250 | 521 | 894 | 4.20 | 0.2.1 |
2015‑04‑10 | 7 | 257 | 27 | 921 | 3.86 | 0.3.0 |
2015‑04‑27 | 17 | 274 | 66 | 987 | 3.88 | 0.3.1 |
2015‑05‑01 | 4 | 278 | 8 | 995 | 2.00 | 0.3.2 |
2015‑05‑15 | 14 | 292 | 34 | 1029 | 2.43 | 0.3.3 |
2015‑06‑04 | 20 | 312 | 86 | 1115 | 4.30 | 0.3.4 |
2015‑07‑08 | 34 | 346 | 83 | 1198 | 2.44 | 0.3.5 |
2015‑07‑27 | 19 | 365 | 158 | 1356 | 2.44 | 1.0.0 |
Read as | Symbol |
---|---|
Metasyntactic Variable |
|
is defined as |
|
or |
|
<expr> ::= <integer> | <expr> <op> <integer>
grammar -> eoe : nil.
grammar -> expr_list : to_block('$1').
grammar -> eoe expr_list : to_block('$2').
grammar -> expr_list eoe : to_block('$1').
grammar -> eoe expr_list eoe : to_block('$2').
grammar -> '$empty' : nil.
private elixirFile ::= endOfExpression? (expressionList endOfExpression?)?
private expressionList ::= expression (endOfExpression expression | adjacentExpression)*
Date | Days | Commits | Version | |||
---|---|---|---|---|---|---|
Delta | Total | Delta | Total | Commits/Day | ||
2014‑08‑02 | 6 | 6 | 18 | 19 | 3.00 |
Step | Elixir | IntelliJ Elixir |
---|---|---|
Lexing | Erlang | JFlex |
Parsing | YECC | GrammarKit |
iex> greeting = "Hello #{"W#{"or"}ld"}"
"Hello World"
iex> tuple = "A tuple #{inspect {"Containing an #{:interpolated} string"}}"
"A tuple {\"Containing an interpolated string\"}"
#{
and ends with }
Language Class | Computational Model | Example |
---|---|---|
Regular | Finite Automaton/State Machine | Multiples of 3 in binary |
Context-Free | Pushdown Automaton | Balanced Parentheses |
Decidable | (Always-halting) Turing machine | anbncn |
Semidecidable | Turing machine | Halting Problem |
lib/elixir/src/elixir_tokenizer.erl
tokenize([$"|T], Line, Scope, Tokens) ->
handle_strings(T, Line, $", Scope, Tokens);
tokenize([$'|T], Line, Scope, Tokens) ->
handle_strings(T, Line, $', Scope, Tokens);
handle_strings(T, Line, H, Scope, Tokens) ->
case elixir_interpolation:extract(Line, Scope, true, T, H) of
{error, Reason} ->
interpolation_error(Reason, [H|T], Tokens, " (for string starting at line ~B)", [Line]);
{NewLine, Parts, [$:|Rest]} when ?is_space(hd(Rest)) ->
Unescaped = unescape_tokens(Parts),
Key = case Scope#elixir_tokenizer.existing_atoms_only of
true -> kw_identifier_safe;
false -> kw_identifier_unsafe
end,
tokenize(Rest, NewLine, Scope, [{Key, Line, Unescaped}|Tokens]);
{NewLine, Parts, Rest} ->
Token = {string_type(H), Line, unescape_tokens(Parts)},
tokenize(Rest, NewLine, Scope, [Token|Tokens])
end.
lib/elixir/src/elixir_interpolation.erl
extract(Line, Scope, true, [$#, ${|Rest], Buffer, Output, Last) ->
Output1 = build_string(Line, Buffer, Output),
case elixir_tokenizer:tokenize(Rest, Line, Scope) of
{error, {EndLine, _, "}"}, [$}|NewRest], Tokens} ->
Output2 = build_interpol(Line, Tokens, Output1),
extract(EndLine, Scope, true, NewRest, [], Output2, Last);
{error, Reason, _, _} ->
{error, Reason};
{ok, _EndLine, _} ->
{error, {string, Line, "missing interpolation terminator:}", []}}
end;
src/org/elixir_lang/Elixr.flex
%{
private java.util.Stack<Integer> lexicalStateStack = new java.util.Stack<Integer>();
%}
<YYINITIAL> {
{DOUBLE_QUOTES} { lexicalStateStack.push(BODY);
yybegin(DOUBLE_QUOTED_STRING);
return ElixirTypes.DOUBLE_QUOTES; }
}
<DOUBLE_QUOTED_STRING> {
{INTERPOLATION_START} { lexicalStateStack.push(yystate());
yybegin(INTERPOLATION);
return ElixirTypes.INTERPOLATION_START; }
{DOUBLE_QUOTES} { int previousLexicalState = lexicalStateStack.pop();
yybegin(previousLexicalState);
return ElixirTypes.DOUBLE_QUOTES; }
}
<BODY, INTERPOLATION> {
{DOUBLE_QUOTES} { lexicalStateStack.push(yystate());
yybegin(DOUBLE_QUOTED_STRING);
return ElixirTypes.DOUBLE_QUOTES; }
}
<INTERPOLATION> {
{INTERPOLATION_END} { int previousLexicalState = lexicalStateStack.pop();
yybegin(previousLexicalState);
return ElixirTypes.INTERPOLATION_END; }
}
Associativity | Left | Right |
---|---|---|
Code |
a or b || c
|
a ++ b <> c
|
Nesting |
|
|
Effective Parentheses |
(a or b) || c
|
a ++ (b <> c)
|
Execution Pipeline | a |> Kernel.or(b) |> Kernel.||(c) | a |> Kernel.++(b |> Kernel.<>(c)) |
Look-ahead, Left-to-Right, Rightmost deriviation (LALR) | Parsing Expression Grammar | |
---|---|---|
Inventor | Frank DeRemer | Bryan Ford |
Invented | 1969 | 2004 |
Terminal symbols | ✓ | ✓ |
Nonterminal rules | ✓ | ✓ |
Empty string | ✓ | ✓ |
Sequence | ✓ | ✓ |
Choice | Ambiguous | Ordered |
Zero-or-more | ❌ |
*
|
One-or-more | ❌ |
+
|
Optional | ❌ |
?
|
Positive Look-ahead | ❌ |
&
|
Negative Look-ahead | ❌ |
!
|
Derivation | Rightmost | Leftmost |
Left-Recursion | Favored | Infinite Loop |
Right-Recursion | Unfavored | Favored |
Direction | Bottom-up | Top-down |
lib/elixir/src/elixir_parser.yrl
%% Changes in ops and precedence should be reflected on lib/elixir/lib/macro.ex
%% Note though the operator => in practice has lower precedence than all others,
%% its entry in the table is only to support the %{user | foo => bar} syntax.
Left 5 do.
Right 10 stab_op_eol. %% ->
Left 20 ','.
Nonassoc 30 capture_op_eol. %% &
Left 40 in_match_op_eol. %% <-, \\ (allowed in matches along =)
Right 50 when_op_eol. %% when
Right 60 type_op_eol. %% ::
Right 70 pipe_op_eol. %% |
Right 80 assoc_op_eol. %% =>
Right 90 match_op_eol. %% =
Left 130 or_op_eol. %% ||, |||, or, xor
Left 140 and_op_eol. %% &&, &&&, and
Left 150 comp_op_eol. %% ==, !=, =~, ===, !==
Left 160 rel_op_eol. %% <, >, <=, >=
Left 170 arrow_op_eol. %% < (op), (op) > (e.g |>, <<<, >>>)
Left 180 in_op_eol. %% in
Right 200 two_op_eol. %% ++, --, .., <>
Left 210 add_op_eol. %% + (op), - (op)
Left 220 mult_op_eol. %% * (op), / (op)
Left 250 hat_op_eol. %% ^ (op) (e.g ^^^)
Nonassoc 300 unary_op_eol. %% +, -, !, ^, not, ~~~
Left 310 dot_call_op.
Left 310 dot_op. %% .
Nonassoc 320 at_op_eol. %% @
Nonassoc 330 dot_identifier.
src/org/elixir_lang/Elixir.bnf
matchedExpression ::= matchedExpressionCaptureOperation |
matchedExpressionInMatchOperation |
matchedExpressionWhenOperation |
matchedExpressionTypeOperation |
matchedExpressionPipeOperation |
matchedExpressionMatchOperation |
matchedExpressionOrOperation |
matchedExpressionAndOperation |
matchedExpressionComparisonOperation |
matchedExpressionRelationalOperation |
matchedExpressionArrowOperation |
matchedExpressionInOperation |
matchedExpressionTwoOperation |
matchedExpressionAdditionOperation |
matchedExpressionMultiplicationOperation |
matchedExpressionHatOperation |
matchedExpressionUnaryOperation |
matchedExpressionDotOperation |
matchedExpressionAtOperation |
identifierExpression |
accessExpression
src/org/elixir/Elixir.bnf
matchedExpressionAdditionOperation ::= matchedExpression DUAL_OPERATOR EOL* matchedExpression
matchedExpressionAndOperation ::= matchedExpression EOL* AND_OPERATOR EOL* matchedExpression
matchedExpressionArrowOperation ::= matchedExpression EOL* ARROW_OPERATOR EOL* matchedExpression
matchedExpressionAtOperation ::= AT_OPERATOR EOL* matchedExpression
matchedExpressionCaptureOperation ::= CAPTURE_OPERATOR EOL* matchedExpression
matchedExpressionComparisonOperation ::= matchedExpression EOL* COMPARISON_OPERATOR EOL* matchedExpression
matchedExpressionDotOperation ::= matchedExpression EOL* DOT_OPERATOR EOL* matchedExpression
matchedExpressionHatOperation ::= matchedExpression EOL* HAT_OPERATOR EOL* matchedExpression
matchedExpressionInMatchOperation ::= matchedExpression EOL* IN_MATCH_OPERATOR EOL* matchedExpression
matchedExpressionInOperation ::= matchedExpression EOL* IN_OPERATOR EOL* matchedExpression
matchedExpressionMatchOperation ::= matchedExpression EOL* MATCH_OPERATOR EOL* matchedExpression { rightAssociative = true }
matchedExpressionMultiplicationOperation ::= matchedExpression EOL* MULTIPLICATION_OPERATOR EOL* matchedExpression
matchedExpressionOrOperation ::= matchedExpression EOL* OR_OPERATOR EOL* matchedExpression
matchedExpressionPipeOperation ::= matchedExpression EOL* PIPE_OPERATOR EOL* matchedExpression { rightAssociative = true }
matchedExpressionRelationalOperation ::= matchedExpression EOL* RELATIONAL_OPERATOR EOL* matchedExpression
matchedExpressionTwoOperation ::= matchedExpression EOL* TWO_OPERATOR EOL* matchedExpression { rightAssociative = true }
matchedExpressionTypeOperation ::= matchedExpression EOL* TYPE_OPERATOR EOL* matchedExpression { rightAssociative = true }
matchedExpressionUnaryOperation ::= (DUAL_OPERATOR | UNARY_OPERATOR) EOL* matchedExpression
matchedExpressionWhenOperation ::= matchedExpression EOL* WHEN_OPERATOR EOL* matchedExpression { rightAssociative = true }
gen/org/elixir_lang/parser/ElixirParser.java
public class ElixirParser implements PsiParser {
/* ********************************************************** */
// Expression root: matchedExpression
// Operator priority table:
// 0: PREFIX(matchedExpressionCaptureOperation)
// 1: BINARY(matchedExpressionInMatchOperation)
// 2: BINARY(matchedExpressionWhenOperation)
// 3: BINARY(matchedExpressionTypeOperation)
// 4: BINARY(matchedExpressionPipeOperation)
// 5: BINARY(matchedExpressionMatchOperation)
// 6: BINARY(matchedExpressionOrOperation)
// 7: BINARY(matchedExpressionAndOperation)
// 8: BINARY(matchedExpressionComparisonOperation)
// 9: BINARY(matchedExpressionRelationalOperation)
// 10: BINARY(matchedExpressionArrowOperation)
// 11: BINARY(matchedExpressionInOperation)
// 12: BINARY(matchedExpressionTwoOperation)
// 13: BINARY(matchedExpressionAdditionOperation)
// 14: BINARY(matchedExpressionMultiplicationOperation)
// 15: BINARY(matchedExpressionHatOperation)
// 16: PREFIX(matchedExpressionUnaryOperation)
// 17: BINARY(matchedExpressionDotOperation)
// 18: PREFIX(matchedExpressionAtOperation)
// 19: ATOM(identifierExpression)
// 20: ATOM(accessExpression)
public static boolean matchedExpression(PsiBuilder b, int l, int g) {
if (!recursion_guard_(b, l, "matchedExpression")) return false;
addVariant(b, "<matched expression>");
boolean r, p;
Marker m = enter_section_(b, l, _NONE_, "<matched expression>");
r = matchedExpressionCaptureOperation(b, l + 1);
if (!r) r = matchedExpressionUnaryOperation(b, l + 1);
if (!r) r = matchedExpressionAtOperation(b, l + 1);
if (!r) r = identifierExpression(b, l + 1);
if (!r) r = accessExpression(b, l + 1);
p = r;
r = r && matchedExpression_0(b, l + 1, g);
exit_section_(b, l, m, null, r, p, null);
return r || p;
}
}
gen/org/elixir_lang/parser/ElixirParser.java
public class ElixirParser implements PsiParser {
public static boolean matchedExpression_0(PsiBuilder b, int l, int g) {
if (!recursion_guard_(b, l, "matchedExpression_0")) return false;
boolean r = true;
while (true) {
Marker m = enter_section_(b, l, _LEFT_, null);
if (g < 1 && matchedExpressionInMatchOperation_0(b, l + 1)) {
r = matchedExpression(b, l, 1);
exit_section_(b, l, m, MATCHED_EXPRESSION_IN_MATCH_OPERATION, r, true, null);
}
else if (g < 2 && matchedExpressionWhenOperation_0(b, l + 1)) {
r = matchedExpression(b, l, 1);
exit_section_(b, l, m, MATCHED_EXPRESSION_WHEN_OPERATION, r, true, null);
}
else if (g < 3 && matchedExpressionTypeOperation_0(b, l + 1)) {
r = matchedExpression(b, l, 2);
exit_section_(b, l, m, MATCHED_EXPRESSION_TYPE_OPERATION, r, true, null);
}
else if (g < 4 && matchedExpressionPipeOperation_0(b, l + 1)) {
r = matchedExpression(b, l, 3);
exit_section_(b, l, m, MATCHED_EXPRESSION_PIPE_OPERATION, r, true, null);
}
else if (g < 5 && matchedExpressionMatchOperation_0(b, l + 1)) {
r = matchedExpression(b, l, 4);
exit_section_(b, l, m, MATCHED_EXPRESSION_MATCH_OPERATION, r, true, null);
}
else if (g < 6 && matchedExpressionOrOperation_0(b, l + 1)) {
r = matchedExpression(b, l, 6);
exit_section_(b, l, m, MATCHED_EXPRESSION_OR_OPERATION, r, true, null);
}
// ...
else {
exit_section_(b, l, m, null, false, false, null);
break;
}
}
return r;
}
}
lib/elixir/src/elixir_parser.yrl
expr -> no_parens_expr : '$1'.
no_parens_expr -> dot_op_identifier call_args_no_parens_many_strict : build_identifier('$1', '$2').
no_parens_expr -> dot_identifier call_args_no_parens_many_strict : build_identifier('$1', '$2').
dot_identifier -> identifier : '$1'.
dot_identifier -> matched_expr dot_op identifier : build_dot('$2', '$1', '$3').
dot_op_identifier -> op_identifier : '$1'.
dot_op_identifier -> matched_expr dot_op op_identifier : build_dot('$2', '$1', '$3').
call_args_no_parens_comma_expr -> matched_expr ',' call_args_no_parens_expr : ['$3', '$1'].
call_args_no_parens_comma_expr -> call_args_no_parens_comma_expr ',' call_args_no_parens_expr : ['$3'|'$1'].
call_args_no_parens_many -> matched_expr ',' call_args_no_parens_kw : ['$1', '$3'].
call_args_no_parens_many -> call_args_no_parens_comma_expr : reverse('$1').
call_args_no_parens_many -> call_args_no_parens_comma_expr ',' call_args_no_parens_kw : reverse(['$3'|'$1']).
call_args_no_parens_many_strict -> call_args_no_parens_many : '$1'.
call_args_no_parens_many_strict -> empty_paren : throw_no_parens_strict('$1').
call_args_no_parens_many_strict -> open_paren call_args_no_parens_kw close_paren : throw_no_parens_strict('$1').
call_args_no_parens_many_strict -> open_paren call_args_no_parens_many close_paren : throw_no_parens_strict('$1').
no_parens_expr -> dot_identifier call_args_no_parens_many_strict
dot_identifier -> identifier
dot_identifier -> matched_expr dot_op identifier
dot_identifier
no_parens_expr -> dot_identifier call_args_no_parens_many_strict
dot_identifier ::= (matched_expr dot_op)? identifier
dot_identifer
no_parens_expr ::= (matched_expr dot_op)? identifier call_args_no_parens_many_strict
src/org/elixir_lang/Elixir.bnf
private expression ::= emptyParentheses |
unqualifiedNoParenthesesManyArgumentsCall |
matchedExpression
noParenthesesManyArgumentsUnqualifiedIdentifier ::= IDENTIFIER
unqualifiedNoParenthesesManyArgumentsCall ::= noParenthesesManyArgumentsUnqualifiedIdentifier
noParenthesesManyArgumentsStrict
src/org/elixir_lang/Elixir.bnf#
noParenthesesNoArgumentsUnqualifiedCallOrVariable ::= IDENTIFIER
matchedExpression ::= matchedCaptureNonNumericOperation |
// ...
matchedCallOperation |
noParenthesesNoArgumentsUnqualifiedCallOrVariable |
accessExpression
matchedCallOperation ::= matchedExpression noParenthesesManyArgumentsStrict
lib/elixir/src/elixir_parser.yrl
call_args_no_parens_many_strict -> call_args_no_parens_many : '$1'.
call_args_no_parens_many_strict -> empty_paren : throw_no_parens_strict('$1').
call_args_no_parens_many_strict -> open_paren call_args_no_parens_kw close_paren : throw_no_parens_strict('$1').
call_args_no_parens_many_strict -> open_paren call_args_no_parens_many close_paren : throw_no_parens_strict('$1').
src/org/elixir_lang/Elixir.bnf
/* Special class for wrapping rules so that
{@link: org.elixir_lang.inspection.NoParenthesesStrict} can just search for
ElixirNoParenthesesStrict instead of having to differentiate between valid and invalid
rule classes. */
noParenthesesStrict ::= emptyParentheses |
OPENING_PARENTHESIS (
noParenthesesKeywords |
noParenthesesManyArguments
) CLOSING_PARENTHESIS
{ implements = "org.elixir_lang.psi.QuotableArguments" methods = [quoteArguments] }
private noParenthesesManyArgumentsStrict ::= noParenthesesManyArguments |
noParenthesesStrict
function (first_positional, second_positional, key: value)
Code.string_to_quoted
{:error,
{1,
"unexpected parenthesis. If you are making a function call, do not insert spaces in between the function name and the opening parentheses. Syntax error before: ",
"'('"}}
lib/elixir/src/elixir_parser.yrl
call_args_no_parens_expr -> matched_expr : '$1'.
call_args_no_parens_expr -> empty_paren : nil.
call_args_no_parens_expr -> no_parens_expr : throw_no_parens_many_strict('$1').
call_args_no_parens_comma_expr -> matched_expr ',' call_args_no_parens_expr : ['$3', '$1'].
call_args_no_parens_comma_expr -> call_args_no_parens_comma_expr ',' call_args_no_parens_expr : ['$3'|'$1'].
call_args_no_parens_many -> matched_expr ',' call_args_no_parens_kw : ['$1', '$3'].
call_args_no_parens_many -> call_args_no_parens_comma_expr : reverse('$1').
call_args_no_parens_many -> call_args_no_parens_comma_expr ',' call_args_no_parens_kw : reverse(['$3'|'$1']).
src/org/elixir_lang/Elixir.bnf
private noParenthesesCommaExpression ::= matchedExpression (infixComma noParenthesesExpression)+
noParenthesesFirstPositional ::= matchedExpression
{ implements = "org.elixir_lang.psi.Quotable" methods = [quote] }
noParenthesesOnePositionalAndKeywordsArguments ::= noParenthesesFirstPositional infixComma noParenthesesKeywords
{ implements = "org.elixir_lang.psi.QuotableArguments" methods = [quoteArguments] }
noParenthesesManyPositionalAndMaybeKeywordsArguments ::= noParenthesesCommaExpression (infixComma noParenthesesKeywords)?
{ implements = "org.elixir_lang.psi.QuotableArguments" methods = [quoteArguments] }
lib/elixir/src/elixir_parser.yrl
call_args_no_parens_expr -> matched_expr : '$1'.
call_args_no_parens_expr -> empty_paren : nil.
call_args_no_parens_expr -> no_parens_expr : throw_no_parens_many_strict('$1').
src/org/elixir_lang/Elixir.bnf
/* Have to prevent matchedExpression that is actually a keywordKey from being parsed as just a matchedExpression or
callArgumentsNoParenthesesCommaExpression COMMA EOL* callArgumentsNoParenthesesKeywords will never match. */
noParenthesesExpression ::= emptyParentheses |
/* Must be before matchedExpression because noParenthesesExpression is
`matchedExpressionDotIdentifier callArgumentsNoParenthesesManyStrict` which is longer
than `matchedExpressionDotIdentifier` in matchedExpression. */
/* This will be marked as an error by
{@link org.elixir_lang.inspection.NoParenthesesManyStrict} */
noParenthesesManyStrictNoParenthesesExpression |
matchedExpression !KEYWORD_PAIR_COLON
{ implements = "org.elixir_lang.psi.Quotable" methods = [quote] }
matchedExpression
matchedExpression ::= accessExpression
accessionExpression ::= stringLine
quote ::= stringLine
keywordKey ::= quote
private keywordKeyColonEOL ::= keywordKey KEYWORD_PAIR_COLON EOL*
noParenthesesKeywordPair ::= keywordKeyColonEOL noParenthesesExpression
noParenthesesKeywords ::= noParenthesesKeywordPair (infixComma noParenthesesKeywordPair)*
noParenthesesOnePositionalAndKeywordsArguments ::= noParenthesesFirstPositional infixComma noParenthesesKeywords
noParenthesesManyPositionalAndMaybeKeywordsArguments ::= noParenthesesCommaExpression (infixComma noParenthesesKeywords)?
lib/elixir/src/elixir_parser.yrl
matched_expr -> matched_expr no_parens_op_expr : build_op(element(1, '$2'), '$1', element(2, '$2')).
matched_expr -> unary_op_eol no_parens_expr : build_unary_op('$1', '$2').
matched_expr -> at_op_eol no_parens_expr : build_unary_op('$1', '$2').
matched_expr -> capture_op_eol no_parens_expr : build_unary_op('$1', '$2').
no_parens_op_expr -> match_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> add_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> mult_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> hat_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> two_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> and_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> or_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> in_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> in_match_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> type_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> pipe_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> comp_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> rel_op_eol no_parens_expr : {'$1', '$2'}.
no_parens_op_expr -> arrow_op_eol no_parens_expr : {'$1', '$2'}.
src/org/elixir_lang/Elixir.bnf
matchedExpression ::= matchedCaptureNonNumericOperation |
matchedInMatchOperation |
matchedWhenNoParenthesesKeywordsOperation |
matchedWhenOperation |
matchedTypeOperation |
matchedPipeOperation |
matchedMatchOperation |
matchedOrOperation |
matchedAndOperation |
matchedComparisonOperation |
matchedRelationalOperation |
matchedArrowOperation |
matchedInOperation |
matchedTwoOperation |
matchedAdditionOperation |
matchedMultiplicationOperation |
matchedHatOperation |
matchedUnaryNonNumericOperation |
matchedDotOperation |
matchedAtNonNumericOperation |
matchedCallOperation |
noParenthesesNoArgumentsUnqualifiedCallOrVariable |
accessExpression
matchedCallOperation ::= matchedExpression noParenthesesManyArgumentsStrict
matchedExpression ::= matchedDotOperation |
matchedCallOperation |
noParenthesesNoArgumentsUnqualifiedCallOrVariable |
accessExpression
matchedDotOperation ::= matchedExpression dotInfixOperator matchedExpression
matchedCallOperation ::= matchedExpression noParenthesesManyArgumentsStrict
accessExpression ::= alias
alias
matchedExpression ::= matchedDotOperation |
matchedCallOperation |
noParenthesesNoArgumentsUnqualifiedCallOrVariable
matchedDotOperation ::= alias dotInfixOperator matchedExpression
matchedCallOperation ::= matchedExpression noParenthesesManyArgumentsStrict
matchedCallOperation
matchedExpression ::= matchedDotOperation |
matchedCallOperation |
noParenthesesNoArgumentsUnqualifiedCallOrVariable |
matchedDotOperation ::= alias dotInfixOperator matchedCallOperation
matchedCallOperation ::= matchedExpression noParenthesesManyArgumentsStrict
matchedCallOperation
matchedExpression ::= matchedDotOperation |
noParenthesesNoArgumentsUnqualifiedCallOrVariable
matchedDotOperation ::= alias dotInfixOperator matchedExpression noParenthesesManyArgumentsStrict
noParenthesesNoArgumentsUnqualifiedCallOrVariable
matchedDotOperation ::= alias dotInfixOperator noParenthesesNoArgumentsUnqualifiedCallOrVariable noParenthesesManyArgumentsStrict
Kernel . inspect 0..1, structs: false
Quoted
Pattern
Code.string_to_quoted!
|
psiToString
|
---|---|
|
|
src/org/elixir_lang/IntellijElixir.java
package org.elixir_lang;
import com.ericsson.otp.erlang.OtpNode;
import java.io.IOException;
public class IntellijElixir {
private static OtpNode localNode = null;
public static final String REMOTE_NODE = "intellij_elixir@127.0.0.1";
public static OtpNode getLocalNode() throws IOException {
if (localNode == null) {
localNode = new OtpNode(
"intellij-elixir@127.0.0.1",
"intellij_elixir"
);
}
return localNode;
}
}
src/org/elixir_lang/intellij_elixir/Quoter.java
package org.elixir_lang.intellij_elixir;
public class Quoter {
public static OtpErlangTuple quote(@NotNull String code) throws IOException,
OtpErlangExit,
OtpErlangDecodeException {
final OtpNode otpNode = IntellijElixir.getLocalNode();
final OtpMbox otpMbox = otpNode.createMbox();
OtpErlangObject quoteMessage = Quoter.quoteMessage(code, otpMbox.self());
otpMbox.send(REMOTE_NAME, IntellijElixir.REMOTE_NODE, quoteMessage);
return (OtpErlangTuple) otpMbox.receive(TIMEOUT_IN_MILLISECONDS);
}
}
src/org/elixir_lang/intellij_elixir/Quoter.java
package org.elixir_lang.intellij_elixir;
public class Quoter {
public static OtpErlangObject quoteMessage(final String text, final OtpErlangPid self) {
final OtpErlangAtom[] messageKeys = new OtpErlangAtom[]{
new OtpErlangAtom("quote"),
new OtpErlangAtom("for")
};
final OtpErlangObject[] messageValues = new OtpErlangObject[]{
elixirString(text),
self
};
return new OtpErlangMap(messageKeys, messageValues);
}
}
lib/intellij_elixir/supervisor.ex
defmodule IntellijElixir.Supervisor do
use Supervisor
def start_link do
Supervisor.start_link(__MODULE__, :ok)
end
@quoter_module IntellijElixir.Quoter
def init(:ok) do
children = [
worker(@quoter_module, [[], [name: @quoter_module]])
]
supervise(children, strategy: :one_for_one)
end
end
lib/intellij_elixir/quoter.ex
defmodule IntellijElixir.Quoter do
use GenServer
def start_link(args, opts \\ []) do
GenServer.start_link(__MODULE__, args, opts)
end
def handle_info(%{quote: code, for: pid}, state) do
{status, quoted} = Code.string_to_quoted(code)
send pid, {status, %{code: code, quoted: quoted}}
{:noreply, state}
end
end
lib/elixir/src/elixir_parser.yrl
matched_expr -> matched_expr matched_op_expr : build_op(element(1, '$2'), '$1', element(2, '$2')).
matched_expr -> matched_expr no_parens_op_expr : build_op(element(1, '$2'), '$1', element(2, '$2')).
matched_op_expr -> match_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> add_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> mult_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> hat_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> two_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> and_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> or_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> in_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> in_match_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> type_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> when_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> pipe_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> comp_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> rel_op_eol matched_expr : {'$1', '$2'}.
matched_op_expr -> arrow_op_eol matched_expr : {'$1', '$2'}.
src/org/elixir_lang/Elixir.bnf
matchedMatchOperation ::= matchedExpression matchInfixOperator matchedExpression
{ implements = "org.elixir_lang.psi.InfixOperation" methods = [quote] rightAssociative = true }
matchedOrOperation ::= matchedExpression orInfixOperator matchedExpression
{ implements = "org.elixir_lang.psi.InfixOperation" methods = [quote] }
src/org/elixir_lang/psi/impl/ElixirPsiImplUtil.java#
public class ElixirPsiImplUtil {
@Contract(pure = true)
@NotNull
public static OtpErlangObject quote(@NotNull final InfixOperation infixOperation) {
PsiElement[] children = infixOperation.getChildren();
if (children.length != 3) {
throw new NotImplementedException(
"BinaryOperation expected to have 3 children (left operand, operator, right operand"
);
}
Quotable leftOperand = (Quotable) children[0];
OtpErlangObject quotedLeftOperand = leftOperand.quote();
Quotable operator = (Quotable) children[1];
OtpErlangObject quotedOperator = operator.quote();
Quotable rightOperand = (Quotable) children[2];
OtpErlangObject quotedRightOperand = rightOperand.quote();
return quotedFunctionCall(
quotedOperator,
metadata(operator),
quotedLeftOperand,
quotedRightOperand
);
}
}
src/org/elixir_lang/psi/impl/ElixirPsiImplUtil.java
package org.elixir_lang.psi.impl;
public class ElixirPsiImplUtil {
public static OtpErlangObject quote(ElixirFile file) {
final Deque<OtpErlangObject> quotedChildren = new LinkedList<OtpErlangObject>();
file.acceptChildren(
new PsiElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if (element instanceof Quotable) {
visitQuotable((Quotable) element);
} else if (!isUnquoted(element)) {
throw new NotImplementedException("Don't know how to visit " + element);
}
super.visitElement(element);
}
public void visitQuotable(@NotNull Quotable child) {
final OtpErlangObject quotedChild = child.quote();
quotedChildren.add(quotedChild);
}
}
);
return block(quotedChildren);
}
}
Erlang | Java |
---|---|
lib/elixir/src/elixir_parser.yrl
|
src/org/elixir_lang/psi/impl/ElixirPsiImplUtil.java
|
src/org/elixir_lang/intellij_elixir/Quoter.java
package org.elixir_lang.intellij_elixir;
public class Quoter {
public static void assertQuotedCorrectly(PsiFile file) {
final String text = file.getText();
try {
OtpErlangTuple quotedMessage = Quoter.quote(text);
Quoter.assertMessageReceived(quotedMessage);
OtpErlangAtom status = (OtpErlangAtom) quotedMessage.elementAt(0);
String statusString = status.atomValue();
OtpErlangMap map = (OtpErlangMap) quotedMessage.elementAt(1);
assertCodeEquals(text, map);
OtpErlangObject expectedQuoted = quoted(map);
if (statusString.equals("ok")) {
OtpErlangObject actualQuoted = ElixirPsiImplUtil.quote(file);
assertEquals(expectedQuoted, actualQuoted);
} else if (statusString.equals("error")) {
OtpErlangTuple error = (OtpErlangTuple) expectedQuoted;
OtpErlangLong line = (OtpErlangLong) error.elementAt(0);
OtpErlangBinary messageBinary = (OtpErlangBinary) error.elementAt(1);
String message = javaString(messageBinary);
OtpErlangBinary tokenBinary = (OtpErlangBinary) error.elementAt(2);
String token = javaString(tokenBinary);
throw new AssertionError(
"intellij_elixir returned \"" + message + "\" on line " + line + " due to " + token +
", use assertQuotesAroundError if error is expect in Elixir natively, " +
"but not in intellij-elixir plugin"
);
}
}
catch (IOException e) {
throw new RuntimeException(e);
} catch (OtpErlangDecodeException e) {
throw new RuntimeException(e);
} catch (OtpErlangExit e) {
throw new RuntimeException(e);
}
}
}
Range | Java Class | |
---|---|---|
Start | End | |
0 | 255 |
OtpErlangString
|
256 | N/A |
OtpErlangList
|
lib/jinterface/java_src/com/ericsson/otp/erlang/OtpInputStream.java
package com.ericsson.otp.erlang;
public class OtpInputStream extends ByteArrayInputStream {
public OtpErlangObject read_any() throws OtpErlangDecodeException {
// ...
switch(tag) {
// ...
case OtpExternal.stringTag:
return new OtpErlangString(this);
case OtpExternal.listTag:
return new OtpErlangList(this);
// ...
}
}
}
lib/jinterface/java_src/com/ericsson/otp/erlang/OtpExternal.java
package com.ericsson.otp.erlang;
public class OtpExternal {
/** The tag used for empty lists */
public static final int nilTag = 106;
/** The tag used for strings and lists of small integers */
public static final int stringTag = 107;
/** The tag used for non-empty lists */
public static final int listTag = 108;
}
Uncommented | Commented | ||
---|---|---|---|
Code | Quoted | Code | Quoted |
|
|
|
|
|
|
|
|
src/org/elixir_lang/Elixir.flex
<YYINITIAL, INTERPOLATION> {
{DOT_OPERATOR} { pushAndBegin(DOT_OPERATION);
return ElixirTypes.DOT_OPERATOR; }
}
<DOT_OPERATION> {
{AND_OPERATOR} { yybegin(CALL_MAYBE);
return ElixirTypes.AND_OPERATOR; }
/*
* Emulates strip_space in elixir_tokenizer.erl
*/
{ESCAPED_EOL}|{WHITE_SPACE}+ { return TokenType.WHITE_SPACE; }
{EOL} { return ElixirTypes.EOL; }
{COMMENT} { return ElixirTypes.COMMENT; }
. { org.elixir_lang.lexer.StackFrame stackFrame = pop();
handleInState(stackFrame.getLastLexicalState()); }
}
strip_dot_space
Time | Code |
---|---|
Before |
|
After |
|
No Space | Space | |||
---|---|---|---|---|
Code | Quoted | Code | Quoted | |
Parentheses |
|
|
|
Error |
Brackets |
|
|
|
|
lib/elixir/src/elixir_tokenizer.erl
tokenize([H|_] = String, Line, Scope, Tokens) when ?is_downcase(H); H == $_ ->
case tokenize_any_identifier(String, Line, Scope, Tokens) of
{keyword, Rest, Check, T} ->
handle_terminator(Rest, Line, Scope, Check, T);
{identifier, Rest, Token} ->
tokenize(Rest, Line, Scope, [Token|Tokens]);
{error, _, _, _} = Error ->
Error
end;
tokenize_any_identifier(Original, Line, Scope, Tokens) ->
{Rest, Identifier} = tokenize_identifier(Original, []),
{AllIdentifier, AllRest} =
case Rest of
[H|T] when H == $?; H == $! -> {Identifier ++ [H], T};
_ -> {Identifier, Rest}
end,
case unsafe_to_atom(AllIdentifier, Line, Scope) of
{ok, Atom} ->
tokenize_kw_or_other(AllRest, identifier, Line, Atom, Tokens);
{error, Reason} ->
{error, Reason, Original, Tokens}
end.
tokenize_kw_or_other(Rest, Kind, Line, Atom, Tokens) ->
case check_keyword(Line, Atom, Tokens) of
nomatch ->
{identifier, Rest, check_call_identifier(Kind, Line, Atom, Rest)};
{ok, [Check|T]} ->
{keyword, Rest, Check, T};
{error, Token} ->
{error, {Line, "syntax error before: ", Token}, atom_to_list(Atom) ++ Rest, Tokens}
end.
check_call_identifier(_Kind, Line, Atom, [$(|_]) -> {paren_identifier, Line, Atom};
check_call_identifier(_Kind, Line, Atom, [$[|_]) -> {bracket_identifier, Line, Atom};
check_call_identifier(Kind, Line, Atom, _Rest) -> {Kind, Line, Atom}.
src/org/elixir_lang/Elixir.flex
<YYINITIAL, INTERPOLATION> {
{IDENTIFIER} { pushAndBegin(CALL_OR_KEYWORD_PAIR_MAYBE);
return ElixirTypes.IDENTIFIER; }
}
<CALL_MAYBE, CALL_OR_KEYWORD_PAIR_MAYBE> {
{OPENING_BRACKET}|{OPENING_PARENTHESIS} { org.elixir_lang.lexer.StackFrame stackFrame = pop();
handleInState(stackFrame.getLastLexicalState());
// zero-width token
return ElixirTypes.CALL; }
}
<DOT_OPERATION> {
{AND_OPERATOR} { yybegin(CALL_MAYBE);
return ElixirTypes.AND_OPERATOR; }
}
src/org/elixir_lang/Elixir.bnf
matchedExpression ::= matchedBracketOperation |
matchedQualifiedBracketOperation |
matchedQualifiedParenthesesCall |
matchedQualifiedNoArgumentsCall |
matchedUnqualifiedParenthesesCall |
matchedUnqualifiedBracketOperation |
variable |
accessExpression
matchedParenthesesArguments ::= CALL parenthesesArguments parenthesesArguments?
matchedBracketOperation ::= matchedExpression bracketArguments
matchedQualifiedBracketOperation ::= matchedExpression dotInfixOperator relativeIdentifier CALL bracketArguments
matchedQualifiedParenthesesCall ::= matchedExpression dotInfixOperator relativeIdentifier matchedParenthesesArguments
matchedQualifiedNoArgumentsCall ::= matchedExpression dotInfixOperator relativeIdentifier !CALL
matchedUnqualifiedParenthesesCall ::= IDENTIFIER matchedParenthesesArguments
matchedUnqualifiedBracketOperation ::= IDENTIFIER CALL bracketArguments
Code | Description |
---|---|
|
Anonymous function clause |
|
Do block clauses |
|
Do block start |
|
Parenthetical groups |
lib/elixir/src/elixir_parser.yrl
access_expr -> fn_eol stab end_eol : build_fn('$1', build_stab(reverse('$2'))).
access_expr -> open_paren stab close_paren : build_stab(reverse('$2')).
stab -> stab_expr : ['$1'].
stab -> stab eol stab_expr : ['$3'|'$1'].
stab_eol -> stab : '$1'.
stab_eol -> stab eol : '$1'.
stab_expr -> expr : '$1'.
stab_expr -> stab_op_eol stab_maybe_expr : build_op('$1', [], '$2').
stab_expr -> call_args_no_parens_all stab_op_eol stab_maybe_expr :
build_op('$2', unwrap_when(unwrap_splice('$1')), '$3').
stab_expr -> stab_parens_many stab_op_eol stab_maybe_expr :
build_op('$2', unwrap_splice('$1'), '$3').
stab_expr -> stab_parens_many when_op expr stab_op_eol stab_maybe_expr :
build_op('$4', [{'when', meta('$2'), unwrap_splice('$1') ++ ['$3']}], '$5').
stab_maybe_expr -> 'expr' : '$1'.
stab_maybe_expr -> '$empty' : nil.
lib/elixir/src/elixir_parser.yrl
build_stab([{'->', Meta, [Left, Right]}|T]) ->
build_stab(Meta, T, Left, [Right], []);
build_stab(Else) ->
build_block(Else).
build_stab(Old, [{'->', New, [Left, Right]}|T], Marker, Temp, Acc) ->
H = {'->', Old, [Marker, build_block(reverse(Temp))]},
build_stab(New, T, Left, [Right], [H|Acc]);
build_stab(Meta, [H|T], Marker, Temp, Acc) ->
build_stab(Meta, T, Marker, [H|Temp], Acc);
build_stab(Meta, [], Marker, Temp, Acc) ->
H = {'->', Meta, [Marker, build_block(reverse(Temp))]},
reverse([H|Acc]).
src/org/elixir_lang/Elixir.bnf
stabNoParenthesesSignature ::= noParenthesesArguments
stabParenthesesSignature ::= parenthesesArguments (whenInfixOperator expression)?
stabSignature ::= (stabParenthesesSignature |
stabNoParenthesesSignature)?
stabInfixOperator ::= EOL* STAB_OPERATOR EOL*
private stabOperationPrefix ::= stabSignature stabInfixOperator
private stabBodyExpression ::= !stabOperationPrefix expression
stabBody ::= stabBodyExpression (endOfExpression+ stabBodyExpression)*
stabOperation ::= stabOperationPrefix stabBody?
{ implements = "org.elixir_lang.psi.Quotable" methods = [quote] }
stab ::= stabOperation (endOfExpression stabOperation)* |
stabBody
anonymousFunction ::= FN endOfExpression?
stab
endOfExpression* END
parentheticalStab ::= OPENING_PARENTHESIS EOL*
(infixSemicolon? stab infixSemicolon? | infixSemicolon)
EOL* CLOSING_PARENTHESIS
accessExpression ::= anonymousFunction |
parentheticalStab
unmatched_expr
lib/elixir/src/elixir_parser.yrl
expr -> unmatched_expr : '$1'.
unmatched_expr -> empty_paren op_expr : build_op(element(1, '$2'), nil, element(2, '$2')).
unmatched_expr -> matched_expr op_expr : build_op(element(1, '$2'), '$1', element(2, '$2')).
unmatched_expr -> unmatched_expr op_expr : build_op(element(1, '$2'), '$1', element(2, '$2')).
unmatched_expr -> unary_op_eol expr : build_unary_op('$1', '$2').
unmatched_expr -> at_op_eol expr : build_unary_op('$1', '$2').
unmatched_expr -> capture_op_eol expr : build_unary_op('$1', '$2').
unmatched_expr -> block_expr : '$1'.
op_expr -> match_op_eol expr : {'$1', '$2'}.
op_expr -> add_op_eol expr : {'$1', '$2'}.
op_expr -> mult_op_eol expr : {'$1', '$2'}.
op_expr -> hat_op_eol expr : {'$1', '$2'}.
op_expr -> two_op_eol expr : {'$1', '$2'}.
op_expr -> and_op_eol expr : {'$1', '$2'}.
op_expr -> or_op_eol expr : {'$1', '$2'}.
op_expr -> in_op_eol expr : {'$1', '$2'}.
op_expr -> in_match_op_eol expr : {'$1', '$2'}.
op_expr -> type_op_eol expr : {'$1', '$2'}.
op_expr -> when_op_eol expr : {'$1', '$2'}.
op_expr -> pipe_op_eol expr : {'$1', '$2'}.
op_expr -> comp_op_eol expr : {'$1', '$2'}.
op_expr -> rel_op_eol expr : {'$1', '$2'}.
op_expr -> arrow_op_eol expr : {'$1', '$2'}.
block_expr
lib/elixir/src/elixir_parser.yrl
block_expr -> parens_call call_args_parens do_block : build_identifier('$1', '$2' ++ '$3').
block_expr -> parens_call call_args_parens call_args_parens do_block : build_nested_parens('$1', '$2', '$3' ++ '$4').
block_expr -> dot_do_identifier do_block : build_identifier('$1', '$2').
block_expr -> dot_identifier call_args_no_parens_all do_block : build_identifier('$1', '$2' ++ '$3').
do_block -> do_eol 'end' : [[{do,nil}]].
do_block -> do_eol stab end_eol : [[{do, build_stab(reverse('$2'))}]].
do_block -> do_eol block_list 'end' : [[{do, nil}|'$2']].
do_block -> do_eol stab_eol block_list 'end' : [[{do, build_stab(reverse('$2'))}|'$3']].
block_list
lib/elixir/src/elixir_parser.yrl
block_eol -> block_identifier : '$1'.
block_eol -> block_identifier eol : '$1'.
block_item -> block_eol stab_eol : {?exprs('$1'), build_stab(reverse('$2'))}.
block_item -> block_eol : {?exprs('$1'), nil}.
block_list -> block_item : ['$1'].
block_list -> block_item block_list : ['$1'|'$2'].
block_identifier
lib/elixir/src/elixir_tokenizer.erl
tokenize_kw_or_other(Rest, Kind, Line, Atom, Tokens) ->
case check_keyword(Line, Atom, Tokens) of
nomatch ->
{identifier, Rest, check_call_identifier(Kind, Line, Atom, Rest)};
{ok, [Check|T]} ->
{keyword, Rest, Check, T};
{error, Token} ->
{error, {Line, "syntax error before: ", Token}, atom_to_list(Atom) ++ Rest, Tokens}
end.
check_keyword(Line, Atom, Tokens) ->
case keyword(Atom) of
false -> nomatch;
token -> {ok, [{Atom, Line}|Tokens]};
block -> {ok, [{block_identifier, Line, Atom}|Tokens]};
unary_op -> {ok, [{unary_op, Line, Atom}|Tokens]};
Kind -> {ok, add_token_with_nl({Kind, Line, Atom}, Tokens)}
end.
keyword('after') -> block;
keyword('else') -> block;
keyword('rescue') -> block;
keyword('catch') -> block;
Ambiguous code | if a then if b then s else s2 | a b, c do s end |
---|---|---|
Bind to Outermost | if a then (if b then s) else s2 | a b, (c) do s end |
Bind to Closest | if a then (if b then s else s2) | a b, (c do s end) |
unmatchedExpression
src/org/elixir_lang/Elixir/bnf
private expression ::= emptyParentheses |
unmatchedExpression |
unqualifiedNoParenthesesManyArgumentsCall
unmatchedExpression ::= unmatchedCaptureNonNumericOperation |
// ...
unmatchedQualifiedNoParenthesesCall |
// ...
unmatchedAccessExpression
unmatchedQualifiedNoParenthesesCall ::= unmatchedExpression dotInfixOperator relativeIdentifier noParenthesesOneArgument doBlock?
noParenthesesOneArgument ::= // ...
!(DUAL_OPERATOR SIGNIFICANT_WHITE_SPACE) matchedExpression
elixir-lang/elixir
Code | Quoted |
---|---|
|
|
|
|
|
|
|
Error |
REFERENCE_OPERATION
src/org/elixir_lang/Elixir.flex
TWO_TOKEN_OR_OPERATOR = "or" |
"||"
TWO_TOKEN_OPERATOR = {TWO_TOKEN_AND_OPERATOR} |
{TWO_TOKEN_ARROW_OPERATOR} |
{TWO_TOKEN_ASSOCIATION_OPERATOR} |
{TWO_TOKEN_COMPARISON_OPERATOR} |
{TWO_TOKEN_IN_MATCH_OPERATOR} |
{TWO_TOKEN_OR_OPERATOR} |
{TWO_TOKEN_RELATIONAL_OPERATOR} |
{TWO_TOKEN_STAB_OPERATOR} |
{TWO_TOKEN_TUPLE_OPERATOR} |
{TWO_TOKEN_TWO_OPERATOR} |
{TWO_TOKEN_TYPE_OPERATOR}
REFERENCABLE_OPERATOR = {FOUR_TOKEN_OPERATOR} |
{THREE_TOKEN_OPERATOR} |
{TWO_TOKEN_OPERATOR} |
{ONE_TOKEN_REFERENCABLE_OPERATOR}
REFERENCE_OPERATOR = "/"
REFERENCE_INFIX_OPERATOR = ({WHITE_SPACE}|{EOL})*{REFERENCE_OPERATOR}
<YYINITIAL, INTERPOLATION> {
{REFERENCABLE_OPERATOR} / {REFERENCE_INFIX_OPERATOR} { pushAndBegin(REFERENCE_OPERATION);
return ElixirTypes.IDENTIFIER; }
}
<REFERENCE_OPERATION> {
{ESCAPED_EOL}|{WHITE_SPACE}+ { return TokenType.WHITE_SPACE; }
{EOL} { return ElixirTypes.EOL; }
{REFERENCE_OPERATOR} { org.elixir_lang.lexer.StackFrame stackFrame = pop();
yybegin(stackFrame.getLastLexicalState());
return ElixirTypes.MULTIPLICATION_OPERATOR; }
}
lib/elixir/src/elixir_tokenizer.erl
-define(operator_kw(A),
A == 'and';
A == 'or';
A == 'when';
A == 'not';
A == 'in').
check_keyword(_Line, _Column, _Length, Atom, [{capture_op, _, _}|_]) when ?operator_kw(Atom) ->
nomatch;
lib/mix/lib/mix/tasks/deps.clean.ex
defmodule Mix.Tasks.Deps.Clean do
defp checked_deps(build, deps) do
for root <- [deps, build],
path <- Path.wildcard(Path.join(root, "*")),
File.dir?(path) do
Path.basename(path)
end
|> Enum.uniq()
|> List.delete(to_string(Mix.Project.config[:app]))
end
end
Matched | Unmatched | |
---|---|---|
Code |
|
|
Quoted |
|
|
Date | Days | Commits | Version | |||
---|---|---|---|---|---|---|
Delta | Total | Delta | Total | Commits/Day | Name | |
2015‑07‑27 | 19 | 365 | 158 | 1356 | 2.44 | 1.0.0 |
Enhancements
Bug Fixes
]
.
that start with and
, or
, and
not
will be lexed as a single identifier instead of and
, or
, or
not
followed by another identifier.
end
is allowed as a relative identifier after .
(...)
as part of matched expression in no parentheses stab signature;
<op>/<arity>
) for function captures
(&<op>/<arity>
)
unquote_splicing
is properly wrapped in __block__
when in stab bodiesambiguous_op: nil
Qualifier.'relative'()
vs Qualifier.'relative' ()
and
Qualifier."relative"()
vs Qualifier."relative" ()
Incompatible Changes
CTRL+N ENTER
keyboard shortcut for New > File