Skip to content

Commit bbb57ba

Browse files
committed
changetype builtin; some namespace parsing; more stdlib ideas; compiler options for asc
1 parent 59dafc8 commit bbb57ba

62 files changed

Lines changed: 622 additions & 455 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

assembly.d.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ declare type f32 = number;
2727
/** A 64-bit float. */
2828
declare type f64 = number;
2929

30-
// builtins
30+
// built-ins
3131

3232
/** Performs the sign-agnostic count leading zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered leading if the value is zero. */
3333
declare function clz<T = i32 | i64>(value: T): T;
@@ -78,6 +78,8 @@ declare const NaN: f32 | f64;
7878
declare const Infinity: f32 | f64;
7979
/** Determines the byte size of the specified core or class type. Compiles to a constant. */
8080
declare function sizeof<T>(): usize;
81+
/** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */
82+
declare function changetype<T1,T2>(value: T1): T2;
8183
/** Tests if a 32-bit or 64-bit float is NaN. */
8284
declare function isNaN<T = f32 | f64>(value: T): bool;
8385
/** Tests if a 32-bit or 64-bit float is finite, that is not NaN or +/-Infinity. */
@@ -87,10 +89,15 @@ declare function assert(isTrue: bool): void;
8789

8890
// internal decorators
8991

92+
/** Annotates an element being part of the global namespace. */
9093
declare function global(): any;
94+
/** Annotates a function being always inlined. */
9195
declare function inline(): any;
96+
/** Annotates a class using a C-style memory layout. */
97+
declare function struct(): any;
9298

9399
// standard library
94100

95101
/// <reference path="./std/carray.d.ts" />
96102
/// <reference path="./std/cstring.d.ts" />
103+
/// <reference path="./std/heap.d.ts" />

bin/asc.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,12 @@ while ((diagnostic = assemblyscript.nextDiagnostic(parser)) != null) {
110110
if (hasErrors)
111111
process.exit(1);
112112

113-
var module = assemblyscript.compile(parser);
113+
var options = assemblyscript.createOptions();
114+
assemblyscript.setTarget(options, 0);
115+
assemblyscript.setNoTreeShaking(options, args.noTreeShaking);
116+
assemblyscript.setNoDebug(options, args.noDebug);
117+
118+
var module = assemblyscript.compile(parser, options);
114119

115120
hasErrors = false;
116121
while ((diagnostic = assemblyscript.nextDiagnostic(parser)) != null) {

bin/asc.json

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,37 @@
11
{
22
"version": {
3-
"desc": "Print the compiler's version.",
3+
"desc": "Prints the compiler's version.",
44
"type": "boolean",
55
"aliases": [ "v" ]
66
},
77
"help": {
8-
"desc": "Print this message.",
8+
"desc": "Prints this message.",
99
"type": "boolean",
1010
"aliases": [ "h" ]
1111
},
1212
"optimize": {
13-
"desc": "Optimize the module.",
13+
"desc": "Optimizes the module.",
1414
"type": "boolean",
1515
"aliases": [ "O" ]
1616
},
1717
"validate": {
18-
"desc": "Validate the module.",
18+
"desc": "Validates the module.",
1919
"type": "boolean"
2020
},
2121
"outFile": {
22-
"desc": "Specify the output file (binary format).",
22+
"desc": "Specifies the output file (binary format).",
2323
"type": "string"
2424
},
2525
"textFile": {
26-
"desc": "Specify the output file (text format).",
26+
"desc": "Specifies the output file (text format).",
2727
"type": "string"
28+
},
29+
"noTreeShaking": {
30+
"desc": "Disables built-in tree-shaking.",
31+
"type": "boolean"
32+
},
33+
"noDebug": {
34+
"desc": "Replaces assertions with nops.",
35+
"type": "boolean"
2836
}
2937
}

src/ast.ts

Lines changed: 72 additions & 49 deletions
Large diffs are not rendered by default.

src/builtins.ts

Lines changed: 170 additions & 156 deletions
Large diffs are not rendered by default.

src/compiler.ts

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ export class Compiler extends DiagnosticEmitter {
148148
const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", null);
149149
const startFunctionInstance: Function = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null);
150150
this.currentFunction = this.startFunction = startFunctionInstance;
151-
this.memoryOffset = new U64(2 * (this.options.target == Target.WASM64 ? 8 : 4), 0); // leave space for `null` and heapStart (both of usize type)
151+
this.memoryOffset = new U64(this.options.target == Target.WASM64 ? 8 : 4, 0); // leave space for `null`
152152
}
153153

154154
/** Performs compilation of the underlying {@link Program} to a {@link Module}. */
@@ -178,32 +178,12 @@ export class Compiler extends DiagnosticEmitter {
178178
}
179179

180180
// set up memory
181-
// store heapStart at `sizeof<usize>()` (that is right after `null`) as an usize
182181
const initial: U64 = this.memoryOffset.clone();
183-
let heapStartBuffer: Uint8Array;
184-
let heapStartOffset: i32;
185-
if (this.options.target == Target.WASM64) {
186-
heapStartBuffer = new Uint8Array(8);
187-
heapStartOffset = 8;
188-
heapStartBuffer[0] = (initial.lo ) as u8;
189-
heapStartBuffer[1] = (initial.lo >>> 8) as u8;
190-
heapStartBuffer[2] = (initial.lo >>> 16) as u8;
191-
heapStartBuffer[3] = (initial.lo >>> 24) as u8;
192-
heapStartBuffer[4] = (initial.hi ) as u8;
193-
heapStartBuffer[5] = (initial.hi >>> 8) as u8;
194-
heapStartBuffer[6] = (initial.hi >>> 16) as u8;
195-
heapStartBuffer[7] = (initial.hi >>> 24) as u8;
196-
} else {
197-
if (!initial.fitsInU32)
198-
throw new Error("static memory size overflows 32 bits");
199-
heapStartBuffer = new Uint8Array(4);
200-
heapStartOffset = 4;
201-
heapStartBuffer[0] = (initial.lo ) as u8;
202-
heapStartBuffer[1] = (initial.lo >>> 8) as u8;
203-
heapStartBuffer[2] = (initial.lo >>> 16) as u8;
204-
heapStartBuffer[3] = (initial.lo >>> 24) as u8;
205-
}
206-
this.memorySegments.push(MemorySegment.create(heapStartBuffer, new U64(heapStartOffset, 0))); // TODO: use a global instead?
182+
if (this.options.target == Target.WASM64)
183+
this.module.addGlobal("HEAP_START", NativeType.I64, false, this.module.createI64(initial.lo, initial.hi));
184+
else
185+
this.module.addGlobal("HEAP_START", NativeType.I32, false, this.module.createI32(initial.lo));
186+
207187
// determine initial page size
208188
const initialOverlaps: U64 = initial.clone();
209189
initialOverlaps.and32(0xffff);
@@ -663,7 +643,7 @@ export class Compiler extends DiagnosticEmitter {
663643
// memory
664644

665645
addMemorySegment(buffer: Uint8Array): MemorySegment {
666-
if (this.memoryOffset.lo & 7) { // align to 8 bytes so any possible data type is aligned here
646+
if (this.memoryOffset.lo & 7) { // align to 8 bytes so any native data type is aligned here
667647
this.memoryOffset.or32(7);
668648
this.memoryOffset.add32(1);
669649
}

src/diagnosticMessages.generated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export enum DiagnosticCode {
77
Operation_is_unsafe = 103,
88
Cannot_export_a_mutable_global = 104,
99
Compiling_constant_global_with_non_constant_initializer_as_mutable = 105,
10+
Type_0_cannot_be_changed_to_type_1 = 106,
1011
Unterminated_string_literal = 1002,
1112
Identifier_expected = 1003,
1213
_0_expected = 1005,
@@ -79,6 +80,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
7980
case 103: return "Operation is unsafe.";
8081
case 104: return "Cannot export a mutable global.";
8182
case 105: return "Compiling constant global with non-constant initializer as mutable.";
83+
case 106: return "Type '{0}' cannot be changed to type '{1}'.";
8284
case 1002: return "Unterminated string literal.";
8385
case 1003: return "Identifier expected.";
8486
case 1005: return "'{0}' expected.";

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"Operation is unsafe.": 103,
66
"Cannot export a mutable global.": 104,
77
"Compiling constant global with non-constant initializer as mutable.": 105,
8+
"Type '{0}' cannot be changed to type '{1}'.": 106,
89

910
"Unterminated string literal.": 1002,
1011
"Identifier expected.": 1003,

src/index.ts

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@
2020
*/
2121

2222
import { Module } from "./module";
23-
import { Compiler } from "./compiler";
24-
import { DiagnosticMessage, DiagnosticCategory } from "./diagnostics";
23+
import { Compiler, Options, Target } from "./compiler";
24+
import { DiagnosticMessage, DiagnosticCategory, formatDiagnosticMessage } from "./diagnostics";
2525
import { Parser } from "./parser";
2626
import { Program } from "./program";
2727

28+
/** Parses a single source file. If `parser` has been omitted a new one is created. */
2829
export function parseFile(text: string, path: string, parser: Parser | null = null): Parser {
2930
let isEntry: bool = false;
3031
if (!parser) {
@@ -35,24 +36,62 @@ export function parseFile(text: string, path: string, parser: Parser | null = nu
3536
return parser;
3637
}
3738

39+
/** Obtains the path to the next file required by the parser. Returns `null` once complete. */
3840
export function nextFile(parser: Parser): string | null {
3941
return parser.nextFile();
4042
}
4143

44+
/** Obtains the next diagnostic message. Returns `null` once there are no more messages. */
4245
export function nextDiagnostic(parser: Parser): DiagnosticMessage | null {
4346
const program: Program = parser.program;
4447
if (program.diagnosticsOffset < program.diagnostics.length)
4548
return program.diagnostics[program.diagnosticsOffset++];
4649
return null;
4750
}
4851

52+
/** Formats a diagnostic message to a string. */
53+
export function formatDiagnostic(message: DiagnosticMessage, useColors: bool, showContext: bool): string {
54+
return formatDiagnosticMessage(message, useColors, showContext);
55+
}
56+
57+
/** Tests whether a diagnostic is informatory. */
58+
export function isInfo(message: DiagnosticMessage): bool {
59+
return message.category == DiagnosticCategory.INFO;
60+
}
61+
62+
/** Tests whether a diagnostic is a warning. */
63+
export function isWarning(message: DiagnosticMessage): bool {
64+
return message.category == DiagnosticCategory.WARNING;
65+
}
66+
67+
/** Tests whether a diagnostic is an error. */
4968
export function isError(message: DiagnosticMessage): bool {
5069
return message.category == DiagnosticCategory.ERROR;
5170
}
5271

53-
export function compile(parser: Parser): Module {
54-
const program: Program = parser.finish();
55-
return Compiler.compile(program);
72+
/** Creates a new set of compiler options. */
73+
export function createOptions(): Options {
74+
return new Options();
5675
}
5776

58-
export { DiagnosticMessage, formatDiagnosticMessage as formatDiagnostic } from "./diagnostics";
77+
/** Sets the `target` option. */
78+
export function setTarget(options: Options, target: Target): void {
79+
options.target = target;
80+
}
81+
82+
/** Sets the `noTreeShaking` option. */
83+
export function setNoTreeShaking(options: Options, noTreeShaking: bool): void {
84+
options.noTreeShaking = noTreeShaking;
85+
}
86+
87+
/** Sets the `noDebug` option. */
88+
export function setNoDebug(options: Options, noDebug: bool): void {
89+
options.noDebug = noDebug;
90+
}
91+
92+
/** Compiles the sources computed by the parser to a module. */
93+
export function compile(parser: Parser, options: Options | null = null): Module {
94+
const program: Program = parser.finish();
95+
const compiler: Compiler = new Compiler(program, options);
96+
return compiler.compile();
97+
}

0 commit comments

Comments
 (0)