Up-propogation of errors works. Now need to handle the case of changing includes

This commit is contained in:
Noah Santschi-Cooney 2018-08-03 15:46:17 +01:00
parent 24c5b5bf51
commit f5af65a701
4 changed files with 75 additions and 56 deletions

View file

@ -1,5 +1,5 @@
type Node = { type Node = {
parents: Map<string, Node> parents: Map<string, Pair<number, Node>>
children: Map<string, Node> children: Map<string, Node>
} }
@ -10,14 +10,14 @@ export class Graph {
return this.nodes.has(uri) ? this.nodes.get(uri).parents.size > 0 : false return this.nodes.has(uri) ? this.nodes.get(uri).parents.size > 0 : false
} }
public setParent(uri: string, parent: string) { public setParent(uri: string, parent: string, lineNum: number) {
const par: Node = this.nodes.has(parent) ? this.nodes.get(parent) : {parents: new Map(), children: new Map()} const par: Node = this.nodes.has(parent) ? this.nodes.get(parent) : {parents: new Map(), children: new Map()}
if (this.nodes.has(uri)) { if (this.nodes.has(uri)) {
const node = this.nodes.get(uri) const node = this.nodes.get(uri)
node.parents.set(parent, par) node.parents.set(parent, {first: lineNum, second: par})
par.children.set(uri, node) par.children.set(uri, node)
} else { } else {
const node: Node = {parents: new Map([par].map(p => [parent, p]) as [string, Node][]), children: new Map()} const node: Node = {parents: new Map([par].map(p => [parent, {first: lineNum, second: p}]) as [string, Pair<number, Node>][]), children: new Map()}
par.children.set(uri, node) par.children.set(uri, node)
this.nodes.set(uri, node) this.nodes.set(uri, node)
} }
@ -29,3 +29,9 @@ export class Graph {
return this.nodes.get(uri) return this.nodes.get(uri)
} }
} }
// can you imagine that some people out there would import a whole library just for this?
export type Pair<T, S> = {
first: T,
second: S
}

View file

@ -98,7 +98,7 @@ export function preprocess(lines: string[], docURI: string) {
lint(docURI, lines, includeMap, diagnostics) lint(docURI, lines, includeMap, diagnostics)
} }
const buildIncludeGraph = (inc: IncludeObj) => includeGraph.setParent(inc.path, inc.parent) const buildIncludeGraph = (inc: IncludeObj) => includeGraph.setParent(inc.path, inc.parent, inc.lineNum)
function processIncludes(lines: string[], incStack: string[], allIncludes: IncludeObj[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) { function processIncludes(lines: string[], incStack: string[], allIncludes: IncludeObj[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
const includes = getIncludes(incStack[0], lines) const includes = getIncludes(incStack[0], lines)
@ -113,49 +113,61 @@ function processIncludes(lines: string[], incStack: string[], allIncludes: Inclu
} }
} }
// TODO no type LinesProcessingInfo = {
total: number,
comment: Comment.State,
parStack: string[],
count: number[],
}
// TODO can surely be reworked
export function getIncludes(uri: string, lines: string[]) { export function getIncludes(uri: string, lines: string[]) {
const count = [-1] // for each file we need to track the line number // the numbers start at -1 because we increment them as soon as we enter the loop so that we
const parStack = [uri] // for each include we need to track its parent // dont have to put an incrememnt at each return
const lineInfo: LinesProcessingInfo = {
total: -1,
comment: Comment.State.No,
parStack: [uri],
count: [-1],
}
let total = -1 // current line number overall return lines.reduce<IncludeObj[]>((out, line, i, l): IncludeObj[] => processLine(out, line, lines, i, lineInfo), [])
let comment = Comment.State.No }
return lines.reduce<IncludeObj[]>((out, line, i, l): IncludeObj[] => { function processLine(includes: IncludeObj[], line: string, lines: string[], i: number, linesInfo: LinesProcessingInfo): IncludeObj[] {
const updated = Comment.update(line, comment) const updated = Comment.update(line, linesInfo.comment)
comment = updated[0] linesInfo.comment = updated[0]
line = updated[1] line = updated[1]
lines[i] = line lines[i] = line
count[count.length - 1]++ linesInfo.count[linesInfo.count.length - 1]++
total++ linesInfo.total++
if (comment) return out if (linesInfo.comment) return includes
if (line.startsWith('#line')) { if (line.startsWith('#line')) {
const inc = line.slice(line.indexOf('"') + 1, line.lastIndexOf('"')) const inc = line.slice(line.indexOf('"') + 1, line.lastIndexOf('"'))
if (inc === parStack[parStack.length - 2]) { if (inc === linesInfo.parStack[linesInfo.parStack.length - 2]) {
count.pop() linesInfo.count.pop()
parStack.pop() linesInfo.parStack.pop()
} else { } else {
count.push(-1) linesInfo.count.push(-1)
parStack.push(inc) linesInfo.parStack.push(inc)
}
return out
} }
return includes
}
const match = line.match(reInclude) const match = line.match(reInclude)
if (match) { if (match) {
out.push({ includes.push({
path: formatURI(absPath(parStack[parStack.length - 1], match[1])), path: formatURI(absPath(linesInfo.parStack[linesInfo.parStack.length - 1], match[1])),
lineNum: count[count.length - 1], lineNum: linesInfo.count[linesInfo.count.length - 1],
lineNumTopLevel: total, lineNumTopLevel: linesInfo.total,
parent: formatURI(parStack[parStack.length - 1]), parent: formatURI(linesInfo.parStack[linesInfo.parStack.length - 1]),
match match
}) })
} }
return out return includes
}, [])
} }
function ifInvalidFile(inc: IncludeObj, lines: string[], incStack: string[], diagnostics: Map<string, Diagnostic[]>) { function ifInvalidFile(inc: IncludeObj, lines: string[], incStack: string[], diagnostics: Map<string, Diagnostic[]>) {
@ -202,11 +214,9 @@ function mergeInclude(inc: IncludeObj, lines: string[], incStack: string[], diag
incStack.push(inc.path) incStack.push(inc.path)
// TODO deal with the fact that includes may not be the sole text on a line
// add #line indicating we are entering a new include block // add #line indicating we are entering a new include block
lines[inc.lineNumTopLevel] = `#line 0 "${formatURI(inc.path)}"` lines[inc.lineNumTopLevel] = `#line 0 "${formatURI(inc.path)}"`
// merge the lines of the file into the current document // merge the lines of the file into the current document
// TODO do we wanna use a DLL here?
lines.splice(inc.lineNumTopLevel + 1, 0, ...dataLines) lines.splice(inc.lineNumTopLevel + 1, 0, ...dataLines)
// add the closing #line indicating we're re-entering a block a level up // add the closing #line indicating we're re-entering a block a level up
lines.splice(inc.lineNumTopLevel + 1 + dataLines.length, 0, `#line ${inc.lineNum + 1} "${inc.parent}"`) lines.splice(inc.lineNumTopLevel + 1 + dataLines.length, 0, `#line ${inc.lineNum + 1} "${inc.parent}"`)
@ -248,21 +258,23 @@ function lint(docURI: string, lines: string[], includes: Map<string, IncludeObj>
}) })
} }
function propogateDiagnostic(errorFile: string, type: string, line: string, msg: string, diagnostics: Map<string, Diagnostic[]>, includes: Map<string, IncludeObj>) { function propogateDiagnostic(errorFile: string, type: string, line: string, msg: string, diagnostics: Map<string, Diagnostic[]>, includes: Map<string, IncludeObj>, parentURI?: string) {
let nextFile = errorFile includeGraph.get(parentURI || errorFile).parents.forEach((pair, parURI) => {
while (nextFile !== '0') { console.log('parent', parURI, 'child', errorFile)
// TODO this doesnt deal with the fact that an include can have multiple parents :( const diag: Diagnostic = {
const diag = {
severity: errorType(type), severity: errorType(type),
range: calcRange(includes.get(nextFile).lineNum, includes.get(nextFile).parent), range: calcRange(pair.first, parURI),
message: `Line ${line} ${includes.get(errorFile).path.replace(conf.shaderpacksPath, '')} ${replaceWords(msg)}`, message: `Line ${line} ${errorFile.replace(conf.shaderpacksPath, '')} ${replaceWords(msg)}`,
source: 'mc-glsl' source: 'mc-glsl'
} }
diagnostics.get(includes.get(nextFile).parent).push(diag) if (!diagnostics.has(parURI)) diagnostics.set(parURI, [])
diagnostics.get(parURI).push(diag)
nextFile = includes.get(nextFile).parent if (pair.second.parents.size > 0) {
} propogateDiagnostic(errorFile, type, line, msg, diagnostics, includes, parURI)
}
})
} }
export const replaceWords = (msg: string) => Array.from(tokens.entries()).reduce((acc, [key, value]) => acc.replace(key, value), msg) export const replaceWords = (msg: string) => Array.from(tokens.entries()).reduce((acc, [key, value]) => acc.replace(key, value), msg)

View file

@ -55,9 +55,7 @@ export function onEvent(document: vsclangproto.TextDocument) {
function lintBubbleDown(uri: string, document: vsclangproto.TextDocument) { function lintBubbleDown(uri: string, document: vsclangproto.TextDocument) {
includeGraph.get(uri).parents.forEach((parent, parentURI) => { includeGraph.get(uri).parents.forEach((parent, parentURI) => {
console.log(parentURI) if (parent.second.parents.size > 0) {
console.log(parent.parents)
if (parent.parents.size > 0) {
lintBubbleDown(parentURI, document) lintBubbleDown(parentURI, document)
} else { } else {
const lines = getDocumentContents(parentURI).split('\n') const lines = getDocumentContents(parentURI).split('\n')

View file

@ -33,6 +33,9 @@
"severity": "warning" "severity": "warning"
}, },
"curly": [true, "ignore-same-line"], "curly": [true, "ignore-same-line"],
"whitespace": false "whitespace": false,
"no-trailing-whitespace": {
"severity": "warning"
}
} }
} }