views use SourceLocation/Line to locate code

This commit is contained in:
Steven Hugg 2020-08-10 21:35:25 -05:00
parent d5405c4db1
commit d92cc5542d
6 changed files with 51 additions and 29 deletions

View File

@ -1,7 +1,7 @@
import { WorkerError, CodeListingMap, SourceLocation } from "../workertypes";
import { WorkerError, CodeListingMap, SourceLocation, SourceLine } from "../workertypes";
export interface SourceLocated {
$loc?: SourceLocation;
$loc?: SourceLine;
}
class CompileError extends Error {
@ -780,8 +780,11 @@ export class BASICParser {
var srclines = [];
var pc = 0;
program.lines.forEach((line, idx) => {
srclines.push({offset: pc, line: idx+1});
pc += line.stmts.length;
line.stmts.forEach((stmt) => {
var sl = stmt.$loc;
sl.offset = pc++; // TODO: could Statement have offset field?
srclines.push(sl);
});
});
return { lines: srclines };
}

View File

@ -9,6 +9,7 @@ export interface SourceLocation {
end?: number;
}
// actually it's a kind of SourceSnippet .. can have multiple per line
export interface SourceLine extends SourceLocation {
offset:number;
insns?:string;
@ -19,29 +20,29 @@ export interface SourceLine extends SourceLocation {
export class SourceFile {
lines: SourceLine[];
text: string;
offset2line: Map<number,number>; //{[offset:number]:number};
offset2loc: Map<number,SourceLine>; //{[offset:number]:number};
line2offset: Map<number,number>; //{[line:number]:number};
constructor(lines:SourceLine[], text:string) {
lines = lines || [];
this.lines = lines;
this.text = text;
this.offset2line = new Map();
this.offset2loc = new Map();
this.line2offset = new Map();
for (var info of lines) {
if (info.offset >= 0) {
this.offset2line[info.offset] = info.line;
this.offset2loc[info.offset] = info;
this.line2offset[info.line] = info.offset;
}
}
}
// TODO: smarter about looking for source lines between two addresses
findLineForOffset(PC:number, lookbehind:number) {
if (this.offset2line) {
if (this.offset2loc) {
for (var i=0; i<=lookbehind; i++) {
var line = this.offset2line[PC];
if (line >= 0) {
return {line:line, offset:PC};
var loc = this.offset2loc[PC];
if (loc) {
return loc;
}
PC--;
}

View File

@ -1079,7 +1079,7 @@ function getErrorElement(err : WorkerError) {
link.click((ev) => {
var wnd = projectWindows.createOrShow(path);
if (wnd instanceof Views.SourceEditor) {
wnd.setCurrentLine(err.line, true);
wnd.setCurrentLine(err, true);
}
});
}

View File

@ -1,6 +1,6 @@
//import CodeMirror = require("codemirror");
import { SourceFile, WorkerError, Segment, FileData } from "../common/workertypes";
import { SourceFile, WorkerError, Segment, FileData, SourceLocation, SourceLine } from "../common/workertypes";
import { Platform, EmuState, lookupSymbol, BaseDebugPlatform, BaseZ80MachinePlatform, BaseZ80Platform, CpuState } from "../common/baseplatform";
import { hex, lpad, rpad, safeident, rgb2bgr } from "../common/util";
import { CodeAnalyzer } from "../common/analysis";
@ -88,7 +88,7 @@ export class SourceEditor implements ProjectView {
editor;
dirtylisting = true;
sourcefile : SourceFile;
currentDebugLine : number;
currentDebugLine : SourceLocation;
errormsgs = [];
errorwidgets = [];
inspectWidget;
@ -327,9 +327,9 @@ export class SourceEditor implements ProjectView {
}
}
setCurrentLine(line:number, moveCursor:boolean) {
setCurrentLine(line:SourceLocation, moveCursor:boolean) {
var addCurrentMarker = (line:number) => {
var addCurrentMarker = (line:SourceLocation) => {
var div = document.createElement("div");
div.style.color = '#66ffff';
div.appendChild(document.createTextNode("\u25b6"));
@ -337,10 +337,14 @@ export class SourceEditor implements ProjectView {
}
this.clearCurrentLine(moveCursor);
if (line>0) {
addCurrentMarker(line-1);
if (moveCursor)
this.editor.setSelection({line:line,ch:0}, {line:line-1,ch:0}, {scroll:true});
if (line) {
addCurrentMarker(line);
if (moveCursor) {
if (line.start || line.end)
this.editor.setSelection({line:line.line-1,ch:line.start}, {line:line.line-1,ch:line.end||line.start+1}, {scroll:true});
else
this.editor.setSelection({line:line.line-1,ch:0}, {line:line.line,ch:0}, {scroll:true});
}
this.currentDebugLine = line;
}
}
@ -349,24 +353,23 @@ export class SourceEditor implements ProjectView {
if (this.currentDebugLine) {
this.editor.clearGutter("gutter-info");
if (moveCursor) this.editor.setSelection(this.editor.getCursor());
this.currentDebugLine = 0;
this.currentDebugLine = null;
}
}
getActiveLine() {
getActiveLine() : SourceLocation {
var state = lastDebugState;
if (this.sourcefile && state) {
var EPC = (state && state.c && (state.c.EPC || state.c.PC)); // || (platform.getPC && platform.getPC());
var res = this.sourcefile.findLineForOffset(EPC, 15);
return res && res.line;
} else
return -1;
return res;
}
}
refreshDebugState(moveCursor:boolean) {
this.clearCurrentLine(moveCursor);
var line = this.getActiveLine();
if (line >= 0) {
if (line) {
this.setCurrentLine(line, moveCursor);
}
}

View File

@ -90,7 +90,8 @@ describe('Store', function () {
assert.deepEqual([false], msgs);
var lst = buildresult.listings.test;
console.log(lst);
assert.deepEqual({ line: 3, offset: 61440 }, lst.sourcefile.findLineForOffset(61440 + 15, 15));
assert.deepEqual({ line: 3, offset: 61440, insns: 'a9 00', iscode: true },
lst.sourcefile.findLineForOffset(61440 + 15, 15));
assert.equal(null, lst.sourcefile.findLineForOffset(61440 + 16, 15));
assert.equal(null, lst.sourcefile.findLineForOffset(61440 + 1, 0));
assert.equal(null, lst.sourcefile.findLineForOffset(61440 - 1, 16));

View File

@ -48,8 +48,12 @@ function doBuild(msgs, callback, outlen, nlines, nerrors, options) {
assert.equal(nerrors, msg.errors.length, "errors");
} else {
assert.equal(nerrors||0, 0, "errors");
assert.equal(msg.output.code?msg.output.code.length:msg.output.length, outlen, "output binary");
assert.ok(msg.output.code || msg.output instanceof Uint8Array);
if (msg.output.lines) { // AST for BASIC
assert.equal(msg.output.lines.length, outlen, "output lines");
} else {
assert.equal(msg.output.code?msg.output.code.length:msg.output.length, outlen, "output binary");
assert.ok(msg.output.code || msg.output instanceof Uint8Array);
}
if (nlines) {
if (typeof nlines === 'number')
nlines = [nlines];
@ -324,5 +328,15 @@ describe('Worker', function() {
});
*/
// TODO: vectrex, x86
it('should compile basic example', function(done) {
var csource = ab2str(fs.readFileSync('presets/basic/wumpus.bas'));
var msgs = [{code:csource, platform:"basic", tool:"basic", path:'wumpus.bas'}];
var done2 = function(err, msg) {
var ast = msg.output;
assert.ok(ast);
done(err, msg);
};
doBuild(msgs, done2, 222, 0, 0);
});
});