1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2025-02-20 14:29:16 +00:00

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

View File

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

View File

@ -1079,7 +1079,7 @@ function getErrorElement(err : WorkerError) {
link.click((ev) => { link.click((ev) => {
var wnd = projectWindows.createOrShow(path); var wnd = projectWindows.createOrShow(path);
if (wnd instanceof Views.SourceEditor) { 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 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 { Platform, EmuState, lookupSymbol, BaseDebugPlatform, BaseZ80MachinePlatform, BaseZ80Platform, CpuState } from "../common/baseplatform";
import { hex, lpad, rpad, safeident, rgb2bgr } from "../common/util"; import { hex, lpad, rpad, safeident, rgb2bgr } from "../common/util";
import { CodeAnalyzer } from "../common/analysis"; import { CodeAnalyzer } from "../common/analysis";
@ -88,7 +88,7 @@ export class SourceEditor implements ProjectView {
editor; editor;
dirtylisting = true; dirtylisting = true;
sourcefile : SourceFile; sourcefile : SourceFile;
currentDebugLine : number; currentDebugLine : SourceLocation;
errormsgs = []; errormsgs = [];
errorwidgets = []; errorwidgets = [];
inspectWidget; 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"); var div = document.createElement("div");
div.style.color = '#66ffff'; div.style.color = '#66ffff';
div.appendChild(document.createTextNode("\u25b6")); div.appendChild(document.createTextNode("\u25b6"));
@ -337,10 +337,14 @@ export class SourceEditor implements ProjectView {
} }
this.clearCurrentLine(moveCursor); this.clearCurrentLine(moveCursor);
if (line>0) { if (line) {
addCurrentMarker(line-1); addCurrentMarker(line);
if (moveCursor) if (moveCursor) {
this.editor.setSelection({line:line,ch:0}, {line:line-1,ch:0}, {scroll:true}); 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; this.currentDebugLine = line;
} }
} }
@ -349,24 +353,23 @@ export class SourceEditor implements ProjectView {
if (this.currentDebugLine) { if (this.currentDebugLine) {
this.editor.clearGutter("gutter-info"); this.editor.clearGutter("gutter-info");
if (moveCursor) this.editor.setSelection(this.editor.getCursor()); if (moveCursor) this.editor.setSelection(this.editor.getCursor());
this.currentDebugLine = 0; this.currentDebugLine = null;
} }
} }
getActiveLine() { getActiveLine() : SourceLocation {
var state = lastDebugState; var state = lastDebugState;
if (this.sourcefile && state) { if (this.sourcefile && state) {
var EPC = (state && state.c && (state.c.EPC || state.c.PC)); // || (platform.getPC && platform.getPC()); var EPC = (state && state.c && (state.c.EPC || state.c.PC)); // || (platform.getPC && platform.getPC());
var res = this.sourcefile.findLineForOffset(EPC, 15); var res = this.sourcefile.findLineForOffset(EPC, 15);
return res && res.line; return res;
} else }
return -1;
} }
refreshDebugState(moveCursor:boolean) { refreshDebugState(moveCursor:boolean) {
this.clearCurrentLine(moveCursor); this.clearCurrentLine(moveCursor);
var line = this.getActiveLine(); var line = this.getActiveLine();
if (line >= 0) { if (line) {
this.setCurrentLine(line, moveCursor); this.setCurrentLine(line, moveCursor);
} }
} }

View File

@ -90,7 +90,8 @@ describe('Store', function () {
assert.deepEqual([false], msgs); assert.deepEqual([false], msgs);
var lst = buildresult.listings.test; var lst = buildresult.listings.test;
console.log(lst); 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 + 16, 15));
assert.equal(null, lst.sourcefile.findLineForOffset(61440 + 1, 0)); assert.equal(null, lst.sourcefile.findLineForOffset(61440 + 1, 0));
assert.equal(null, lst.sourcefile.findLineForOffset(61440 - 1, 16)); 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"); assert.equal(nerrors, msg.errors.length, "errors");
} else { } else {
assert.equal(nerrors||0, 0, "errors"); assert.equal(nerrors||0, 0, "errors");
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.equal(msg.output.code?msg.output.code.length:msg.output.length, outlen, "output binary");
assert.ok(msg.output.code || msg.output instanceof Uint8Array); assert.ok(msg.output.code || msg.output instanceof Uint8Array);
}
if (nlines) { if (nlines) {
if (typeof nlines === 'number') if (typeof nlines === 'number')
nlines = [nlines]; nlines = [nlines];
@ -324,5 +328,15 @@ describe('Worker', function() {
}); });
*/ */
// TODO: vectrex, x86 // 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);
});
}); });