-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Magic Comments for the Slicing (#895)
- Loading branch information
Showing
19 changed files
with
315 additions
and
74 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import type { NoInfo, RNode } from '../../r-bridge/lang-4.x/ast/model/model' | ||
import type { ParentInformation, NormalizedAst } from '../../r-bridge/lang-4.x/ast/model/processing/decorate' | ||
import { RType } from '../../r-bridge/lang-4.x/ast/model/type' | ||
|
||
/** | ||
* The structure of the predicate that should be used to determine | ||
* if a given normalized node should be included in the reconstructed code, | ||
* independent of if it is selected by the slice or not. | ||
* | ||
* @see reconstructToCode | ||
* @see doNotAutoSelect | ||
* @see autoSelectLibrary | ||
*/ | ||
export type AutoSelectPredicate = (node: RNode<ParentInformation>, fullAst: NormalizedAst) => boolean | ||
|
||
/** | ||
* A variant of the {@link AutoSelectPredicate} which does not select any additional statements (~> false) | ||
*/ | ||
export function doNotAutoSelect(_node: RNode): boolean { | ||
return false | ||
} | ||
|
||
const libraryFunctionCall = /^(library|require|((require|load|attach)Namespace))$/ | ||
|
||
/** | ||
* A variant of the {@link AutoSelectPredicate} which does its best | ||
* to select any kind of library import automatically. | ||
*/ | ||
export function autoSelectLibrary<Info = NoInfo>(node: RNode<Info>): boolean { | ||
if(node.type !== RType.FunctionCall || !node.named) { | ||
return false | ||
} | ||
return libraryFunctionCall.test(node.functionName.content) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import type { RNode } from '../../r-bridge/lang-4.x/ast/model/model' | ||
import type { RComment } from '../../r-bridge/lang-4.x/ast/model/nodes/r-comment' | ||
import type { NormalizedAst, ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate' | ||
import { visitAst } from '../../r-bridge/lang-4.x/ast/model/processing/visitor' | ||
import { RType } from '../../r-bridge/lang-4.x/ast/model/type' | ||
import { guard } from '../../util/assert' | ||
import type { SourceRange } from '../../util/range' | ||
import type { AutoSelectPredicate } from './auto-select-defaults' | ||
|
||
function getLoc({ location, info: { fullRange } }: RNode): SourceRange { | ||
const loc = location ?? fullRange | ||
guard(loc !== undefined, 'TODO: support location-less nodes!') | ||
return loc | ||
} | ||
|
||
type MagicCommentConsumer = (n: RComment, stack: number[]) => number[] | undefined | ||
|
||
const magicCommentIdMapper: Record<string, MagicCommentConsumer> = { | ||
'include_next_line': (n: RComment) => { | ||
return [getLoc(n)[0] + 1] | ||
}, | ||
'include_this_line': (n: RComment) => { | ||
return [getLoc(n)[0]] | ||
}, | ||
'include_start': (n: RComment, stack: number[]) => { | ||
stack.push(getLoc(n)[0] + 1) | ||
return undefined | ||
}, | ||
'include_end': (n: RComment, stack: number[]) => { | ||
const to = getLoc(n)[0] | ||
guard(stack.length >= 1, `mismatched magic start and end at ${to}`) | ||
const from = stack.pop() as number | ||
const ret = new Array<number>(to - from - 1) | ||
for(let i = from; i < to; i++) { | ||
ret[i - from] = i | ||
} | ||
return ret | ||
} | ||
} | ||
|
||
const commentTriggerRegex = / flowr@(\w+)/ | ||
|
||
/** | ||
* This takes an {@link NormalizedAst} and returns an auto-select predicate for {@link reconstructToCode}, | ||
* which will automatically include lines marked by these special comments! | ||
* Please make sure to create one per source as it will use it to cache. | ||
* | ||
* We support two formats: | ||
* - Line comments in the form of `# flowr@include_next_line` or `# flowr@include_this_line`. | ||
* - Block comments which start with `# flowr@include_start` and end with `# flowr@include_end`. | ||
* This supports nesting, but they have to appear on a single line. | ||
* | ||
* Please note that these comments have to start exactly with this content to work. | ||
* | ||
* @param and - Predicate to composite this one with, If you do not pass a predicate, you may assume composition with | ||
* {@link doNotAutoSelect}. | ||
*/ | ||
export function makeMagicCommentHandler(and?: AutoSelectPredicate): AutoSelectPredicate { | ||
let lines: Set<number> | undefined = undefined | ||
return (node: RNode<ParentInformation>, normalizedAst: NormalizedAst) => { | ||
if(!lines) { | ||
lines = new Set<number>() | ||
const startLineStack: number[] = [] | ||
visitAst(normalizedAst.ast, n => { | ||
const comments = n.info.additionalTokens | ||
if(!comments) { | ||
return | ||
} | ||
for(const c of comments) { | ||
if(c.type !== RType.Comment || !c.content.startsWith(' flowr@')) { | ||
continue | ||
} | ||
const match = commentTriggerRegex.exec(c.content) | ||
guard(match !== null, `invalid magic comment: ${c.content}`) | ||
const idMapper = magicCommentIdMapper[match[1]] | ||
guard(idMapper !== undefined, `unknown magic comment: ${match[1]}`) | ||
const ls = idMapper(c, startLineStack) | ||
if(ls !== undefined) { | ||
for(const l of ls) { | ||
(lines as Set<number>).add(l) | ||
} | ||
} | ||
} | ||
}) | ||
guard(startLineStack.length === 0, `mismatched magic start and end at end of file (${JSON.stringify(startLineStack)})`) | ||
} | ||
const loc = node.location ?? node.info.fullRange | ||
|
||
if(loc && lines.has(loc[0])) { | ||
return true | ||
} | ||
return and?.(node, normalizedAst) ?? false | ||
} | ||
} | ||
|
||
|
Oops, something went wrong.