From d92cc5542d8c784369d6c1ed76bfad5678b101f9 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Mon, 10 Aug 2020 21:35:25 -0500 Subject: [PATCH] views use SourceLocation/Line to locate code --- src/common/basic/compiler.ts | 11 +++++++---- src/common/workertypes.ts | 15 ++++++++------- src/ide/ui.ts | 2 +- src/ide/views.ts | 31 +++++++++++++++++-------------- test/cli/teststore.js | 3 ++- test/cli/testworker.js | 18 ++++++++++++++++-- 6 files changed, 51 insertions(+), 29 deletions(-) diff --git a/src/common/basic/compiler.ts b/src/common/basic/compiler.ts index 129eb5ca..c69f168e 100644 --- a/src/common/basic/compiler.ts +++ b/src/common/basic/compiler.ts @@ -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 }; } diff --git a/src/common/workertypes.ts b/src/common/workertypes.ts index cd29e23f..acafd50c 100644 --- a/src/common/workertypes.ts +++ b/src/common/workertypes.ts @@ -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; //{[offset:number]:number}; + offset2loc: Map; //{[offset:number]:number}; line2offset: Map; //{[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--; } diff --git a/src/ide/ui.ts b/src/ide/ui.ts index 2e7d39e1..e8bd13ce 100644 --- a/src/ide/ui.ts +++ b/src/ide/ui.ts @@ -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); } }); } diff --git a/src/ide/views.ts b/src/ide/views.ts index ac6414d5..de8c29c9 100644 --- a/src/ide/views.ts +++ b/src/ide/views.ts @@ -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); } } diff --git a/test/cli/teststore.js b/test/cli/teststore.js index d4ad22af..60fe786e 100644 --- a/test/cli/teststore.js +++ b/test/cli/teststore.js @@ -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)); diff --git a/test/cli/testworker.js b/test/cli/testworker.js index 6993d9b4..41dfc916 100644 --- a/test/cli/testworker.js +++ b/test/cli/testworker.js @@ -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); + }); });