From c6345ec7284fa4aebac8e4a4866bb3ff9d27a1a5 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Tue, 7 Nov 2023 17:00:35 -0600 Subject: [PATCH] server: updated parsing, flags --- src/common/util.ts | 6 +++++ src/ide/views/editors.ts | 6 ++++- src/platform/vcs.ts | 1 + src/worker/server/buildenv.ts | 23 +++++++++-------- src/worker/server/clang.ts | 48 +++++++++++++++++++++-------------- 5 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/common/util.ts b/src/common/util.ts index db372cf6..13c358a3 100644 --- a/src/common/util.ts +++ b/src/common/util.ts @@ -695,3 +695,9 @@ export function coerceToArray(arrobj: any) : T[] { else if (typeof arrobj === 'object') return Array.from(Object.values(arrobj)) else throw new Error(`Expected array or object, got "${arrobj}"`); } + +export function replaceAll(s:string, search:string, replace:string) : string { + if (s == '') return ''; + if (search == '') return s; + return s.split(search).join(replace); +} diff --git a/src/ide/views/editors.ts b/src/ide/views/editors.ts index 92ba16c1..566d4901 100644 --- a/src/ide/views/editors.ts +++ b/src/ide/views/editors.ts @@ -64,6 +64,7 @@ export class SourceEditor implements ProjectView { errorwidgets = []; errormarks = []; inspectWidget; + refreshDelayMsec = 300; createDiv(parent:HTMLElement) { var div = document.createElement('div'); @@ -77,6 +78,9 @@ export class SourceEditor implements ProjectView { this.editor.setSelection({line:0,ch:0}, {line:0,ch:0}, {scroll:true}); // move cursor to start } this.setupEditor(); + if (current_project.getToolForFilename(this.path).startsWith("remote:")) { + this.refreshDelayMsec = 1000; // remote URLs get slower refresh + } return div; } @@ -114,7 +118,7 @@ export class SourceEditor implements ProjectView { clearTimeout(this.updateTimer); this.updateTimer = setTimeout( () => { current_project.updateFile(this.path, this.editor.getValue()); - }, 300); + }, this.refreshDelayMsec); if (this.markHighlight) { this.markHighlight.clear(); this.markHighlight = null; diff --git a/src/platform/vcs.ts b/src/platform/vcs.ts index 88f8ffd3..8507da1cd 100644 --- a/src/platform/vcs.ts +++ b/src/platform/vcs.ts @@ -58,6 +58,7 @@ const VCS_PRESETS = [ ]; function getToolForFilename_vcs(fn: string) { + if (fn.endsWith("-llvm.c")) return "remote:llvm-mos"; if (fn.endsWith(".wiz")) return "wiz"; if (fn.endsWith(".bb") || fn.endsWith(".bas")) return "bataribasic"; if (fn.endsWith(".ca65")) return "ca65"; diff --git a/src/worker/server/buildenv.ts b/src/worker/server/buildenv.ts index aa798271..06a33083 100644 --- a/src/worker/server/buildenv.ts +++ b/src/worker/server/buildenv.ts @@ -3,15 +3,15 @@ import fs from 'fs'; import path from 'path'; import { spawn } from 'child_process'; import { CodeListingMap, WorkerBuildStep, WorkerError, WorkerErrorResult, WorkerFileUpdate, WorkerResult, isOutputResult } from '../../common/workertypes'; -import { getBasePlatform, getRootBasePlatform } from '../../common/util'; +import { getBasePlatform, getRootBasePlatform, replaceAll } from '../../common/util'; import { BuildStep, makeErrorMatcher } from '../workermain'; -import { parseObjDumpListing, parseObjDumpSymbolTable } from './clang'; +import { parseObjDump } from './clang'; const LLVM_MOS_TOOL: ServerBuildTool = { name: 'llvm-mos', version: '', - extensions: ['.c', '.cpp', '.s'], + extensions: ['.c', '.cpp', '.s', '.S', '.C'], archs: ['6502'], platforms: ['atari8', 'c64', 'nes', 'pce', 'vcs'], platform_configs: { @@ -27,11 +27,9 @@ const LLVM_MOS_TOOL: ServerBuildTool = { }, c64: { command: 'mos-c64-clang', - libargs: ['-D', '__C64__'] }, atari8: { command: 'mos-atari8-clang', - libargs: ['-D', '__ATARI__'] }, nes: { command: 'mos-nes-nrom-clang', // TODO @@ -39,7 +37,9 @@ const LLVM_MOS_TOOL: ServerBuildTool = { }, pce: { command: 'mos-pce-clang', // TODO - libargs: ['-D', '__PCE__'] + }, + vcs: { + command: 'mos-atari2600-3e-clang', // TODO }, } } @@ -175,6 +175,10 @@ export class ServerBuildEnv { resolve(this.processOutput(step)); } } else { + errorData = replaceAll(errorData, this.sessionDir, ''); + errorData = replaceAll(errorData, this.rootdir, ''); + // remove folder paths + errorData = errorData.replace(/(\/var\/folders\/.+?\/).+?:/g, ''); let errorResult = await this.processErrors(step, errorData); if (errorResult.errors.length === 0) { errorResult.errors.push({ line: 0, msg: `Build failed.\n\n${errorData}` }); @@ -203,10 +207,9 @@ export class ServerBuildEnv { async processDebugInfo(step: WorkerBuildStep): Promise { let dbgfile = path.join(this.sessionDir, 'debug.out'); - let dbglist = await fs.promises.readFile(dbgfile); - let listings = parseObjDumpListing(dbglist.toString()); - let symbolmap = parseObjDumpSymbolTable(dbglist.toString()); - return { output: [], listings, symbolmap }; + let dbglist = (await fs.promises.readFile(dbgfile)).toString(); + let { listings, symbolmap, segments } = parseObjDump(dbglist); + return { output: [], listings, symbolmap, segments }; } async compileAndLink(step: WorkerBuildStep, updates: WorkerFileUpdate[]): Promise { diff --git a/src/worker/server/clang.ts b/src/worker/server/clang.ts index 9deb8132..8d85f300 100644 --- a/src/worker/server/clang.ts +++ b/src/worker/server/clang.ts @@ -1,27 +1,37 @@ import path from 'path'; -import { CodeListing, CodeListingMap } from "../../common/workertypes"; +import { CodeListing, CodeListingMap, Segment } from "../../common/workertypes"; -export function parseObjDumpSymbolTable(symbolTable) { - const lines = symbolTable.split('\n'); - const result = {}; +export function parseObjDump(lst: string) { + // parse symbol map + const lines = lst.split('\n'); + const symbolmap = {}; + const segments : Segment[] = []; for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); - if (line.startsWith('00')) { + if (line.startsWith("Disassembly")) break; + if (line.startsWith('0')) { const parts = line.split(/\s+/); if (parts.length < 5) continue; const symbol = parts[parts.length-1]; - const address = parseInt(parts[0], 16); - result[symbol] = address; + const address = parseInt(parts[0], 16) & 0xffff; // TODO: 32-bit addresses + symbolmap[symbol] = address; + // is it a segment? + if (symbol.startsWith('__')) { + if (symbol.endsWith('_start')) { + let name = symbol.substring(2, symbol.length - 6); + let type = parts[2] == '.text' ? 'rom' : 'ram'; + segments.push({ name, start: address, size: 0, type }) + } else if (symbol.endsWith('_size')) { + let name = symbol.substring(2, symbol.length - 5); + let seg = segments.find(s => s.name === name); + if (seg) seg.size = address; + } + } } } - return result; -} - -export function parseObjDumpListing(lst: string): CodeListingMap { - const lines = lst.split('\n'); - const result: CodeListingMap = {}; + // parse listings + const listings: CodeListingMap = {}; var lastListing : CodeListing = null; - for (let i = 0; i < lines.length; i++) { const line = lines[i].trim(); if (line.startsWith(';')) { @@ -32,18 +42,18 @@ export function parseObjDumpListing(lst: string): CodeListingMap { const file = path.basename(fileParts[0].trim()).split('.')[0] + '.lst'; const lineNumber = parseInt(fileParts[1], 10); if (lineNumber > 0) { - if (!result[file]) result[file] = { lines: [], text: lst }; - lastListing = result[file]; + if (!listings[file]) listings[file] = { lines: [], text: lst }; + lastListing = listings[file]; lastListing.lines.push({ line: lineNumber, offset: null }); } } } else if (lastListing && line.match(/^\s*[A-F0-9]+:.+/i)) { const offsetIndex = line.indexOf(':'); if (offsetIndex !== -1) { - const offset = parseInt(line.substring(0, offsetIndex).trim(), 16); + const offset = parseInt(line.substring(0, offsetIndex).trim(), 16) & 0xffff; // TODO: 32-bit addresses; lastListing.lines[lastListing.lines.length - 1].offset = offset; } } } - return result; -} \ No newline at end of file + return { listings, symbolmap, segments }; +}