Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 47 additions & 14 deletions src/parser/grammar.ne
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,28 @@ interface CommentAttachments {
trailing?: CommentNode[];
}

interface ExpressionList {
previous: ExpressionList | null;
value: AstNode;
}

interface PendingExpressions {
expressions: ExpressionList | null;
clauses: AstNode[];
}

const materializeExpressionList = (expressions: ExpressionList | null): AstNode[] => {
const result: AstNode[] = [];
for (let current = expressions; current !== null; current = current.previous) {
result.push(current.value);
}
result.reverse();
return result;
};

const materializeExpressions = ({ expressions, clauses }: PendingExpressions): AstNode[] =>
materializeExpressionList(expressions).concat(clauses);

const addComments = (node: AstNode, { leading, trailing }: CommentAttachments): AstNode => {
if (leading?.length) {
node = { ...node, leadingComments: leading };
Expand Down Expand Up @@ -83,14 +105,19 @@ main -> statement:* {%
statement -> expressions_or_clauses (%DELIMITER | %EOF) {%
([children, [delimiter]]) => ({
type: NodeType.statement,
children,
children: materializeExpressions(children),
hasSemicolon: delimiter.type === TokenType.DELIMITER,
})
%}

# To avoid ambiguity, plain expressions can only come before clauses
expressions_or_clauses -> free_form_sql:* clause:* {%
([expressions, clauses]) => [...expressions, ...clauses]
expressions_or_clauses -> expression_list clause:* {%
([expressions, clauses]) => ({ expressions, clauses })
%}

expression_list -> null {% () => null %}
expression_list -> expression_list free_form_sql {%
([previous, value]) => ({ previous, value })
%}

clause ->
Expand Down Expand Up @@ -119,11 +146,13 @@ limit_clause -> %LIMIT _ expression_chain_ (%COMMA free_form_sql:+):? {%
}
%}

select_clause -> %RESERVED_SELECT (all_columns_asterisk free_form_sql:* | asteriskless_free_form_sql free_form_sql:*) {%
select_clause -> %RESERVED_SELECT (all_columns_asterisk expression_list | asteriskless_free_form_sql expression_list) {%
([nameToken, [exp, expressions]]) => ({
type: NodeType.clause,
nameKw: toKeywordNode(nameToken),
children: [exp, ...expressions],
get children(): AstNode[] {
return [exp, ...materializeExpressionList(expressions)];
},
})
%}
select_clause -> %RESERVED_SELECT {%
Expand All @@ -138,19 +167,23 @@ all_columns_asterisk -> %ASTERISK {%
() => ({ type: NodeType.all_columns_asterisk })
%}

other_clause -> %RESERVED_CLAUSE free_form_sql:* {%
other_clause -> %RESERVED_CLAUSE expression_list {%
([nameToken, children]) => ({
type: NodeType.clause,
nameKw: toKeywordNode(nameToken),
children,
get children(): AstNode[] {
return materializeExpressionList(children);
},
})
%}

set_operation -> %RESERVED_SET_OPERATION free_form_sql:* {%
set_operation -> %RESERVED_SET_OPERATION expression_list {%
([nameToken, children]) => ({
type: NodeType.set_operation,
nameKw: toKeywordNode(nameToken),
children,
get children(): AstNode[] {
return materializeExpressionList(children);
},
})
%}

Expand Down Expand Up @@ -232,25 +265,25 @@ function_call -> %RESERVED_FUNCTION_NAME _ parenthesis {%
parenthesis -> "(" expressions_or_clauses ")" {%
([open, children, close]) => ({
type: NodeType.parenthesis,
children: children,
children: materializeExpressions(children),
openParen: "(",
closeParen: ")",
})
%}

curly_braces -> "{" free_form_sql:* "}" {%
curly_braces -> "{" expression_list "}" {%
([open, children, close]) => ({
type: NodeType.parenthesis,
children: children,
children: materializeExpressionList(children),
openParen: "{",
closeParen: "}",
})
%}

square_brackets -> "[" free_form_sql:* "]" {%
square_brackets -> "[" expression_list "]" {%
([open, children, close]) => ({
type: NodeType.parenthesis,
children: children,
children: materializeExpressionList(children),
openParen: "[",
closeParen: "]",
})
Expand Down
2 changes: 1 addition & 1 deletion test/perftest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe('Performance test', () => {
});

// Issue #840
it.skip('should use less than 100 MB of additional memory to format ~100 KB of SQL', () => {
it('should use less than 100 MB of additional memory to format ~100 KB of SQL', () => {
// Long list of values
const values = Array(10000).fill('myid');
const sql = `SELECT ${values.join(', ')}`;
Expand Down