Skip to content

Commit 2dd9378

Browse files
authored
Fix: reconstruction of if-then-else constructs (#790)
2 parents 9385f2b + a7fc3f7 commit 2dd9378

File tree

13 files changed

+159
-89
lines changed

13 files changed

+159
-89
lines changed

src/dataflow/environments/built-in.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ registerBuiltInFunctions(['<<-'], processAssignment,
165165
registerBuiltInFunctions(['->'], processAssignment, { swapSourceAndTarget: true, canBeReplacement: true }, )
166166
registerBuiltInFunctions(['->>'], processAssignment, { superAssignment: true, swapSourceAndTarget: true, canBeReplacement: true } )
167167
registerBuiltInFunctions(['&&', '||', '&', '|'], processSpecialBinOp, { lazy: true } )
168-
registerBuiltInFunctions(['|>'], processPipe, {}, )
168+
registerBuiltInFunctions(['|>', '%>%'], processPipe, {}, )
169169
registerBuiltInFunctions(['function', '\\'], processFunctionDefinition, {}, )
170170
registerBuiltInFunctions(['quote', 'substitute', 'bquote'], processQuote, { quoteArgumentsWithIndex: 0 }, )
171171
registerBuiltInFunctions(['for'], processForLoop, {}, )

src/r-bridge/lang-4.x/ast/parser/xml/internal/expression/normalize-expression.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export function normalizeExpression(data: NormalizerData, obj: XmlBasedJson): RN
5151

5252
const children = normalizeExpressions(childData, childrenSource)
5353

54-
const [delimiters, nodes] = partition(children, x => x.type === RType.Delimiter)
54+
const [delimiters, nodes] = partition(children, x => x.type === RType.Delimiter || x.type === RType.Comment)
5555

5656
if(nodes.length === 1) {
5757
const result = nodes[0] as RNode

src/r-bridge/lang-4.x/ast/parser/xml/internal/structure/normalize-root.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function normalizeRootObjToAst(
2828
log.debug('no children found, assume empty input')
2929
}
3030

31-
const [delimiters, nodes] = partition(parsedChildren, x => x.type === RType.Delimiter)
31+
const [delimiters, nodes] = partition(parsedChildren, x => x.type === RType.Delimiter || x.type === RType.Comment)
3232

3333
return {
3434
type: RType.ExpressionList,

src/reconstruct/reconstruct.ts

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -112,15 +112,21 @@ function reconstructUnaryOp(leaf: RNodeWithParent, operand: Code, configuration:
112112
}
113113
}
114114

115-
function reconstructBinaryOp(n: RBinaryOp<ParentInformation> | RPipe<ParentInformation>, lhs: Code, rhs: Code): Code {
115+
function reconstructBinaryOp(n: RBinaryOp<ParentInformation> | RPipe<ParentInformation>, lhs: Code, rhs: Code, config: ReconstructionConfiguration): Code {
116116
if(lhs.length === 0 && rhs.length === 0) {
117-
return []
118-
}
119-
if(lhs.length === 0) { // if we have no lhs, only return rhs
117+
if(isSelected(config, n)) {
118+
return plain(getLexeme(n))
119+
} else {
120+
return []
121+
}
122+
} else if(lhs.length === 0) { // if we have no lhs, only return rhs
120123
return rhs
121-
}
122-
if(rhs.length === 0) { // if we have no rhs we have to keep everything to get the rhs
123-
return plain(getLexeme(n))
124+
} else if(rhs.length === 0) {
125+
if(isSelected(config, n)) {
126+
return plain(getLexeme(n))
127+
} else {
128+
return lhs
129+
}
124130
}
125131

126132
return reconstructRawBinaryOperator(lhs, n.type === RType.Pipe ? '|>' : n.operator, rhs)
@@ -205,7 +211,7 @@ function reconstructIfThenElse(ifThenElse: RIfThenElse<ParentInformation>, condi
205211
return otherwise
206212
}
207213
} else {
208-
const thenRemainder = indentBy(then.splice(1), 1)
214+
const thenRemainder = indentBy(then.slice(1), 1)
209215
if(thenRemainder.length > 0) {
210216
if(!thenRemainder[thenRemainder.length - 1].line.trim().endsWith('else')) {
211217
thenRemainder[thenRemainder.length - 1].line += ' else '
@@ -344,10 +350,20 @@ function reconstructSpecialInfixFunctionCall(args: (Code | typeof EmptyArgument)
344350
}
345351

346352
function reconstructFunctionCall(call: RFunctionCall<ParentInformation>, functionName: Code, args: (Code | typeof EmptyArgument)[], configuration: ReconstructionConfiguration): Code {
353+
const selected = isSelected(configuration, call)
354+
if(!selected) {
355+
const f = args.filter(a => a !== EmptyArgument && a.length !== 0) as Code[]
356+
if(f.length === 0) {
357+
return []
358+
} else if(f.length === 1) {
359+
return f[0]
360+
}
361+
}
362+
347363
if(call.infixSpecial === true) {
348364
return reconstructSpecialInfixFunctionCall(args, call)
349365
}
350-
if(call.flavor === 'named' && isSelected(configuration, call)) {
366+
if(call.flavor === 'named' && selected) {
351367
return plain(getLexeme(call))
352368
}
353369
const filteredArgs = args.filter(a => a !== undefined && a.length > 0)

src/slicing/criterion/filters/all-variables.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ const defaultAllVariablesCollectorFolds: FoldFunctions<ParentInformation, NodeId
4646
if(c.flavor === 'named') {
4747
return c.functionName.content === 'library' ? args.slice(1) : args
4848
} else {
49-
return [...a, ...args]
49+
return [...a.filter(x => x !== EmptyArgument), ...args]
5050
}
5151
},
5252
foldArgument: (_: unknown, _a: unknown, b: NodeId[] | undefined) => b ?? [],

test/functionality/_helper/shell.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,8 +265,8 @@ export function assertSliced(name: string | TestLabel, shell: RShell, input: str
265265
`got: ${result.reconstruct.code}, vs. expected: ${expected}, for input ${input} (slice for ${JSON.stringify(criteria)}: ${printIdMapping(result.slice.decodedCriteria.map(({ id }) => id), result.normalize.idMap)}), url: ${graphToMermaidUrl(result.dataflow.graph, true, result.slice.result)}`
266266
)
267267
} catch(e) {
268-
console.error(normalizedAstToMermaidUrl(result.normalize.ast))
269268
console.error(`got:\n${result.reconstruct.code}\nvs. expected:\n${expected}`)
269+
console.error(normalizedAstToMermaidUrl(result.normalize.ast))
270270
throw e
271271
}
272272
})

test/functionality/benchmark/slicer.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ cat(d)`
100100
assert.deepStrictEqual(stats.perSliceMeasurements.sliceSize, {
101101
// only one entry
102102
lines: { min: 2, max: 5, median: 3, mean: (2+3+5)/3, std: 1.247219128924647, total: 10 },
103-
characters: { min: 17, max: 46, median: 24, mean: 29, std: 12.355835328567093, total: 87 },
104-
nonWhitespaceCharacters: { min: 14, max: 32, median: 18, mean: 21.333333333333332, std: 7.71722460186015, total: 64 },
105-
tokens: { min: 13, max: 40, median: 19, mean: 24, std: 11.575836902790225, total: 72 },
106-
normalizedTokens: { min: 8, max: 22, median: 11, mean: (8+11+22)/3, std: 6.018490028422596, total: 41 },
103+
characters: { min: 17, max: 41, median: 24, mean: 27.333333333333332, std: 10.077477638553981, total: 82 },
104+
nonWhitespaceCharacters: { min: 14, max: 27, median: 18, mean: 19.666666666666668, std: 5.436502143433363, total: 59 },
105+
tokens: { min: 13, max: 35, median: 19, mean: 22.333333333333332, std: 9.285592184789413, total: 67 },
106+
normalizedTokens: { min: 8, max: 19, median: 11, mean: (8+11+19)/3, std: 4.642796092394707, total: 38 },
107107
dataflowNodes: { min: 3, max: 14, median: 6, mean: (3+6+14)/3, std: 4.642796092394707, total: 23 },
108108
autoSelected: { min: 1, max: 1, median: 1, mean: 1, std: 0, total: 3 } // always select one library statement
109109
}, statInfo)

test/functionality/r-bridge/lang/ast/parse-assignments.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { RType } from '../../../../../src/r-bridge/lang-4.x/ast/model/type'
88

99
describe('Parse simple assignments',
1010
withShell(shell => {
11-
describe('Constant Assignments', () => {
11+
describe('Constant assignments', () => {
1212
for(const op of AssignmentOperators) {
1313
const opOffset = op.length - 1
1414
const data = OperatorDatabase[op]

test/functionality/r-bridge/lang/ast/parse-operations.ts

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,26 @@ describe('Parse simple operations', withShell(shell => {
5959

6060
describe('Intermixed with comments', () => {
6161
assertAst(label('1 + # comment\n2', ['binary-operator', 'infix-calls', 'function-calls', 'numbers', 'comments', 'newlines', ...OperatorDatabase['+'].capabilities]),
62-
shell, '1 + # comment\n2', exprList({ // hoist children
62+
shell, '1 + # comment\n2', { // hoist children
6363
type: RType.ExpressionList,
64-
location: rangeFrom(1, 1, 2, 1),
64+
location: undefined,
6565
grouping: undefined,
6666
info: {},
67-
lexeme: '1 + # comment\n2',
67+
lexeme: undefined,
6868
children: [
6969
{
70-
type: RType.Comment,
71-
content: ' comment',
72-
lexeme: '# comment',
73-
location: rangeFrom(1, 5, 1, 13),
74-
info: {}
75-
},
76-
{
77-
type: RType.BinaryOp,
78-
info: {},
70+
type: RType.BinaryOp,
71+
info: {
72+
additionalTokens: [
73+
{
74+
type: RType.Comment,
75+
content: ' comment',
76+
lexeme: '# comment',
77+
location: rangeFrom(1, 5, 1, 13),
78+
info: {}
79+
}
80+
]
81+
},
7982
lexeme: '+',
8083
operator: '+',
8184
location: rangeFrom(1, 3, 1, 3),
@@ -95,7 +98,7 @@ describe('Parse simple operations', withShell(shell => {
9598
}
9699
}
97100
]
98-
}), {
101+
}, {
99102
ignoreAdditionalTokens: false
100103
}
101104
)

test/functionality/r-bridge/lang/ast/parse-values.ts

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,20 @@ describe('Constant Parsing',
129129
describe('comments', () => {
130130
assertAst(label('simple line comment', ['comments']),
131131
shell, '# Hello World',
132-
exprList({
133-
type: RType.Comment,
134-
location: rangeFrom(1, 1, 1, 13),
135-
lexeme: '# Hello World',
136-
content: ' Hello World',
137-
info: {}
138-
})
132+
{
133+
...exprList(),
134+
info: {
135+
additionalTokens: [
136+
{
137+
type: RType.Comment,
138+
location: rangeFrom(1, 1, 1, 13),
139+
lexeme: '# Hello World',
140+
content: ' Hello World',
141+
info: {}
142+
}
143+
]
144+
}
145+
}
139146
)
140147
})
141148
})

0 commit comments

Comments
 (0)