Skip to content

Commit a4e7ca1

Browse files
tolauwaecarllocos
andauthored
Fix asc compilation (#122)
* Use locally installed `asc` instead of global * fix #120 and compile AS without optimisation To compile ASC without any optimisation I removed the `03s` argument * fix regex to only be true for source maps AssemblyScript compiler can generate lines that contain the `@` symbol but have nothing to do with the source mapping (e.g., '000287d: 6e67 2e55 5446 382e 656e 636f 6465 4076 ng.UTF8.encode@v') which causes `extractLineInfo` to fail on those lines. This commit modifies the regex to only be true for lines that start with `@ {` which ensures that `extractLineInfo` is applied to real source map lines. * 🔨 Use AS source map directly --------- Co-authored-by: Carlos Rojas <carlosj.rojascastillo@gmail.com>
1 parent 4d5be69 commit a4e7ca1

File tree

6 files changed

+150
-90
lines changed

6 files changed

+150
-90
lines changed

package-lock.json

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,7 @@
287287
"chai": "^4.3.6",
288288
"ieee754": "^1.2.1",
289289
"mqtt": "^4.3.7",
290+
"source-map": "^0.7.4",
290291
"ts-retry-promise": "^0.7.0"
291292
}
292293
}

src/CompilerBridges/AssemblyScriptCompilerBridge.ts

Lines changed: 83 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {CompileBridge, CompileResult} from './CompileBridge';
22
import {exec, ExecException} from 'child_process';
33
import {SourceMap} from '../State/SourceMap';
4+
import {MappingItem, SourceMapConsumer} from 'source-map';
45
import * as fs from 'fs';
56
import {readFileSync} from 'fs';
67
import {WASMCompilerBridge} from './WASMCompilerBridge';
@@ -10,32 +11,20 @@ import * as path from 'path';
1011

1112
export class AssemblyScriptCompilerBridge implements CompileBridge {
1213
sourceFilePath: String;
13-
private wat: WASMCompilerBridge;
1414
private readonly tmpdir: string;
15+
private readonly wabt: string;
16+
private readonly workingDir?: string;
1517

16-
constructor(sourceFilePath: String, tmpdir: string, wabt: string) {
18+
constructor(sourceFilePath: String, tmpdir: string, wabt: string, workingDir?: string) {
1719
this.sourceFilePath = sourceFilePath;
1820
this.tmpdir = tmpdir;
19-
this.wat = new WASMCompilerBridge(`${this.tmpdir}/upload.wast`, tmpdir, wabt);
21+
this.wabt = wabt;
22+
this.workingDir = workingDir;
2023
}
2124

2225
async compile(): Promise<CompileResult> {
23-
return this.wasm().then((result) => {
24-
return this.lineInformation(result.sourceMap).then((lines) => {
25-
const wasm: Buffer = readFileSync(`${this.tmpdir}/upload.wasm`);
26-
result.sourceMap.lineInfoPairs = lines;
27-
return Promise.resolve({sourceMap: result.sourceMap, wasm: wasm});
28-
});
29-
});
30-
}
31-
32-
async clean(path2makefile: string): Promise<void> {
33-
return;
34-
}
35-
36-
private async wasm() {
3726
return new Promise<void>(async (resolve, reject) => {
38-
const command = `cd ${path.dirname(this.sourceFilePath.toString())} ; ` + await this.getCompilationCommand();
27+
const command = await this.getCompilationCommand();
3928
let out: String = '';
4029
let err: String = '';
4130

@@ -53,13 +42,21 @@ export class AssemblyScriptCompilerBridge implements CompileBridge {
5342
}
5443
resolve();
5544
});
56-
}).then(() => {
57-
return this.wat.compile();
45+
}).then(async () => {
46+
const w: Buffer = readFileSync(`${this.tmpdir}/upload.wasm`);
47+
return Promise.resolve({
48+
sourceMap: await new AsScriptMapper(this.sourceFilePath.toString(), this.tmpdir, this.wabt).mapping(),
49+
wasm: w
50+
});
5851
}).catch((error) => {
5952
return Promise.reject(error);
6053
});
6154
}
6255

56+
async clean(path2makefile: string): Promise<void> {
57+
return;
58+
}
59+
6360
// private executeCompileCommand(command: string): Promise<SourceMap> {
6461
// const compiler = this;
6562
// return new Promise(async function (resolve, reject) {
@@ -115,7 +112,7 @@ export class AssemblyScriptCompilerBridge implements CompileBridge {
115112
}
116113
});
117114

118-
return new Promise((resolve, reject) => {
115+
return new Promise((resolve) => {
119116
reader.on('close', () => {
120117
resolve(mapping);
121118
});
@@ -124,36 +121,84 @@ export class AssemblyScriptCompilerBridge implements CompileBridge {
124121

125122
private getCompilationCommand(): Promise<string> {
126123
// builds asc command based on the version of asc
127-
return new Promise<string>((resolve, reject) => {
124+
return new Promise<string>(async (resolve) => {
125+
let version: Version = await this.retrieveVersion();
126+
resolve(`${this.workingDir ? `cd ${this.workingDir}; ` : ''}npx asc ${this.sourceFilePath} --exportTable --disable bulk-memory --sourceMap --debug ` +
127+
`${(version.major > 0 || +version.minor >= 20) ? '--outFile' : '--binaryFile'} ${this.tmpdir}/upload.wasm`);
128+
});
129+
}
130+
131+
private retrieveVersion(): Promise<Version> {
132+
return new Promise<Version>((resolve, reject) => {
128133
let out: String = '';
129134
let err: String = '';
135+
130136
function handle(error: ExecException | null, stdout: String, stderr: any) {
131137
out = stdout;
132138
err = error?.message ?? '';
133139
}
134140

135-
let compilerVersion = exec('asc --version', handle);
141+
const command: string = `${this.workingDir ? `cd ${this.workingDir}; ` : ''}npx asc --version`;
142+
let compilerVersion = exec(command, handle);
136143
compilerVersion.on('close', (code) => {
137144
if (code !== 0) {
138-
reject(`Compilation to wasm failed: exit code ${code}. Message: ${err}`);
145+
reject(`asc --version failed: ${err}`);
139146
}
140147

141-
// build command
142-
const versionRegex: RegExp = /^Version (?<major>[0-9]+)\.(?<minor>[0-9]+)\.(?<patch>[0-9]+)/;
143-
const matched = out.match(versionRegex);
144-
if (!matched || !!!matched.groups?.major || !!!matched.groups?.minor || !!!matched.groups?.patch) {
145-
reject(`Compilation to wasm failed: asc--version did not print expected output format 'Version x.x.x'.Got instead ${out} `);
146-
}
147-
let command = `asc ${this.sourceFilePath} --exportTable --disable bulk-memory --sourceMap -O3s --debug `;
148-
if (+matched!.groups!.major > 0 || +matched!.groups!.minor >= 20) {
149-
command += '--outFile ';
150-
}
151-
else {
152-
command += '--binaryFile ';
148+
const matched = out.match(/^Version (?<major>[0-9]+)\.(?<minor>[0-9]+)\.(?<patch>[0-9]+)/);
149+
if (matched && matched.groups?.major && matched.groups?.minor && matched.groups?.patch) {
150+
resolve({major: +matched.groups.major, minor: +matched.groups.minor, patch: +matched.groups.patch});
151+
} else {
152+
reject(`asc --version did not print expected output format 'Version x.x.x'. Got ${out} instead.`);
153153
}
154-
command += `${this.tmpdir}/upload.wasm --textFile ${this.tmpdir}/upload.wast`; // use .wast to get inline sourcemapping
155-
resolve(command);
156154
});
157155
});
158156
}
157+
}
158+
159+
interface Version {
160+
major: number;
161+
minor: number;
162+
patch: number;
163+
}
164+
165+
export abstract class SourceMapper {
166+
abstract mapping(): Promise<SourceMap>;
167+
}
168+
169+
export class AsScriptMapper implements SourceMapper {
170+
private readonly sourceFile: string;
171+
private readonly tmpdir: string;
172+
private readonly wabt: string;
173+
174+
constructor(sourceFile: string, tmpdir: string, wabt: string) {
175+
this.sourceFile = sourceFile;
176+
this.tmpdir = tmpdir;
177+
this.wabt = wabt;
178+
}
179+
180+
public mapping(): Promise<SourceMap> {
181+
const input = fs.readFileSync(`${this.tmpdir}/upload.wasm.map`);
182+
183+
return new Promise<LineInfoPairs[]>((resolve) => {
184+
new SourceMapConsumer(input.toString()).then((consumer: SourceMapConsumer) => {
185+
const lineInfoPairs: LineInfoPairs[] = [];
186+
consumer.eachMapping(function (item: MappingItem) {
187+
if (!item.source.includes('~lib')) {
188+
lineInfoPairs.push({
189+
lineInfo: {
190+
line: item.originalLine,
191+
column: item.originalColumn,
192+
message: ''
193+
},
194+
lineAddress: item.generatedColumn.toString(16)
195+
});
196+
}
197+
});
198+
resolve(lineInfoPairs);
199+
});
200+
}).then((lines: LineInfoPairs[]) => {
201+
return new WASMCompilerBridge(this.sourceFile, this.tmpdir, this.wabt).sourceDump(lines);
202+
});
203+
}
159204
}

src/CompilerBridges/CompileBridge.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {SourceMap} from '../State/SourceMap';
33
export interface CompileResult{
44
sourceMap: SourceMap;
55
wasm: Buffer;
6-
};
6+
}
7+
78
export interface CompileBridge {
89
compile(): Promise<CompileResult>;
910
clean(path2makefile: string): Promise<void>;

src/CompilerBridges/CompileBridgeFactory.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import {getFileExtension} from '../Parsers/ParseUtils';
22
import {CompileBridge} from './CompileBridge';
33
import {WASMCompilerBridge} from './WASMCompilerBridge';
44
import {AssemblyScriptCompilerBridge} from './AssemblyScriptCompilerBridge';
5+
import * as vscode from 'vscode';
56

67
export class CompileBridgeFactory {
78
static makeCompileBridge(file: string, tmpdir: string, wabt: string): CompileBridge {
@@ -10,7 +11,7 @@ export class CompileBridgeFactory {
1011
case 'wast' :
1112
return new WASMCompilerBridge(file, tmpdir, wabt);
1213
case 'ts' :
13-
return new AssemblyScriptCompilerBridge(file, tmpdir, wabt);
14+
return new AssemblyScriptCompilerBridge(file, tmpdir, wabt, vscode.workspace.workspaceFolders?.[0].uri.path.toString());
1415
}
1516
throw new Error('Unsupported file type');
1617
}

0 commit comments

Comments
 (0)