Skip to content

Commit fc777b3

Browse files
committed
Builtins rewrite with type parameter inference; Small integer math optimizations; Switchify
1 parent 0de05b5 commit fc777b3

Some content is hidden

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

64 files changed

+4857
-1583
lines changed

src/builtins.ts

Lines changed: 1465 additions & 419 deletions
Large diffs are not rendered by default.

src/compiler.ts

Lines changed: 563 additions & 294 deletions
Large diffs are not rendered by default.

src/diagnosticMessages.generated.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export enum DiagnosticCode {
1111
Structs_cannot_extend_classes_and_vice_versa = 107,
1212
Structs_cannot_implement_interfaces = 108,
1313
Invalid_regular_expression_flags = 109,
14+
Type_0_cannot_be_reinterpreted_as_type_1 = 110,
1415
Unterminated_string_literal = 1002,
1516
Identifier_expected = 1003,
1617
_0_expected = 1005,
@@ -97,6 +98,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
9798
case 107: return "Structs cannot extend classes and vice-versa.";
9899
case 108: return "Structs cannot implement interfaces.";
99100
case 109: return "Invalid regular expression flags.";
101+
case 110: return "Type '{0}' cannot be reinterpreted as type '{1}'.";
100102
case 1002: return "Unterminated string literal.";
101103
case 1003: return "Identifier expected.";
102104
case 1005: return "'{0}' expected.";

src/diagnosticMessages.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"Structs cannot extend classes and vice-versa.": 107,
1010
"Structs cannot implement interfaces.": 108,
1111
"Invalid regular expression flags.": 109,
12+
"Type '{0}' cannot be reinterpreted as type '{1}'.": 110,
1213

1314
"Unterminated string literal.": 1002,
1415
"Identifier expected.": 1003,

src/tokenizer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,8 @@ export class Range {
351351
}
352352
}
353353

354+
declare function parseFloat(str: string): f64;
355+
354356
export class Tokenizer extends DiagnosticEmitter {
355357

356358
source: Source;

src/types.ts

Lines changed: 182 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,18 @@ export class Type {
5858
functionType: Function | null;
5959
/** Whether nullable or not. */
6060
isNullable: bool = false;
61-
/** Respective nullable type, if nullable. */
61+
/** Respective nullable type, if non-nullable. */
6262
nullableType: Type | null = null;
63+
/** Respective non-nullable type, if nullable. */
64+
nonNullableType: Type;
6365

6466
/** Constructs a new resolved type. */
6567
constructor(kind: TypeKind, size: i32) {
6668
this.kind = kind;
6769
this.size = size;
6870
this.byteSize = <i32>ceil<f64>(<f64>size / 8);
6971
this.classType = null;
72+
this.nonNullableType = this;
7073
}
7174

7275
/** Sign-extending 32-bit shift, if a small signed integer. */
@@ -75,23 +78,157 @@ export class Type {
7578
get smallIntegerMask(): i32 { return -1 >>> (32 - this.size); }
7679

7780
/** Tests if this type is of any integer kind. */
78-
get isAnyInteger(): bool { return this.kind >= TypeKind.I8 && this.kind <= TypeKind.BOOL; }
79-
/** Tests if this type is of any small integer kind. */
80-
get isSmallInteger(): bool { return this.size != 0 && this.size < 32; }
81-
/** Tests if this type is of any long integer kind. */
82-
get isLongInteger(): bool { return this.size == 64 && this.kind != TypeKind.F64; }
81+
get isAnyInteger(): bool {
82+
switch (this.kind) {
83+
case TypeKind.I8:
84+
case TypeKind.I16:
85+
case TypeKind.I32:
86+
case TypeKind.I64:
87+
case TypeKind.ISIZE:
88+
case TypeKind.U8:
89+
case TypeKind.U16:
90+
case TypeKind.U32:
91+
case TypeKind.U64:
92+
case TypeKind.USIZE:
93+
case TypeKind.BOOL:
94+
return true;
95+
default:
96+
return false;
97+
}
98+
}
99+
83100
/** Tests if this type is of any unsigned integer kind. */
84-
get isUnsignedInteger(): bool { return this.kind >= TypeKind.U8 && this.kind <= TypeKind.BOOL; }
101+
get isAnyUnsignedInteger(): bool {
102+
switch (this.kind) {
103+
case TypeKind.U8:
104+
case TypeKind.U16:
105+
case TypeKind.U32:
106+
case TypeKind.U64:
107+
case TypeKind.USIZE:
108+
case TypeKind.BOOL:
109+
return true;
110+
default:
111+
return false;
112+
}
113+
}
114+
85115
/** Tests if this type is of any signed integer kind. */
86-
get isSignedInteger(): bool { return this.kind >= TypeKind.I8 && this.kind <= TypeKind.ISIZE; }
87-
/** Tests if this type is of any size kind, i.e., `isize` or `usize`. */
88-
get isAnySize(): bool { return this.kind == TypeKind.ISIZE || this.kind == TypeKind.USIZE; }
116+
get isAnySignedInteger(): bool {
117+
switch (this.kind) {
118+
case TypeKind.I8:
119+
case TypeKind.I16:
120+
case TypeKind.I32:
121+
case TypeKind.I64:
122+
case TypeKind.ISIZE:
123+
return true;
124+
default:
125+
return false;
126+
}
127+
}
128+
129+
/** Tests if this type is of any small integer kind. */
130+
get isSmallInteger(): bool {
131+
switch (this.kind) {
132+
case TypeKind.I8:
133+
case TypeKind.I16:
134+
case TypeKind.U8:
135+
case TypeKind.U16:
136+
case TypeKind.BOOL:
137+
return true;
138+
default:
139+
return false;
140+
}
141+
}
142+
143+
/** Tests if this type is of any small signed integer kind. */
144+
get isSmallSignedInteger(): bool {
145+
switch (this.kind) {
146+
case TypeKind.I8:
147+
case TypeKind.I16:
148+
return true;
149+
default:
150+
return false;
151+
}
152+
}
153+
154+
/** Tests if this type is of any small unsigned integer kind. */
155+
get isSmallUnsignedInteger(): bool {
156+
switch (this.kind) {
157+
case TypeKind.U8:
158+
case TypeKind.U16:
159+
case TypeKind.BOOL:
160+
return true;
161+
default:
162+
return false;
163+
}
164+
}
165+
166+
/** Tests if this type is of any long integer kind. */
167+
get isLongInteger(): bool {
168+
switch (this.kind) {
169+
case TypeKind.I64:
170+
case TypeKind.U64:
171+
return true;
172+
case TypeKind.ISIZE:
173+
case TypeKind.USIZE:
174+
return this.size == 64;
175+
default:
176+
return false;
177+
}
178+
}
179+
180+
/** Tests if this type is of any long signed integer kind. */
181+
get isLongSignedInteger(): bool {
182+
switch (this.kind) {
183+
case TypeKind.I64:
184+
return true;
185+
case TypeKind.ISIZE:
186+
return this.size == 64;
187+
default:
188+
return false;
189+
}
190+
}
191+
192+
/** Tests if this type is of any long unsigned integer kind. */
193+
get isLongUnsignedInteger(): bool {
194+
switch (this.kind) {
195+
case TypeKind.U64:
196+
return true;
197+
case TypeKind.USIZE:
198+
return this.size == 64;
199+
default:
200+
return false;
201+
}
202+
}
203+
204+
/** Tests if this type is of any size kind, that is `isize` or `usize`. */
205+
get isAnySize(): bool {
206+
switch (this.kind) {
207+
case TypeKind.ISIZE:
208+
case TypeKind.USIZE:
209+
return true;
210+
default:
211+
return false;
212+
}
213+
}
214+
89215
/** Tests if this type is of any float kind, i.e., `f32` or `f64`. */
90-
get isAnyFloat(): bool { return this.kind == TypeKind.F32 || this.kind == TypeKind.F64; }
216+
get isAnyFloat(): bool {
217+
switch (this.kind) {
218+
case TypeKind.F32:
219+
case TypeKind.F64:
220+
return true;
221+
default:
222+
return false;
223+
}
224+
}
225+
91226
/** Tests if this type is a class type. */
92227
get isClass(): bool { return this.classType != null; }
93228
/** Tests if this type is a function type. */
94229
get isFunction(): bool { return this.functionType != null; }
230+
/** Tests if this type is a reference type. */
231+
get isReference(): bool { return this.classType != null || this.functionType != null; }
95232

96233
/** Composes a class type from this type and a class. */
97234
asClass(classType: Class): Type {
@@ -103,17 +240,20 @@ export class Type {
103240

104241
/** Composes a function type from this type and a function. */
105242
asFunction(functionType: Function): Type {
106-
assert(this.kind == TypeKind.USIZE);
243+
assert(this.kind == TypeKind.USIZE && !this.isReference);
107244
var ret = new Type(this.kind, this.size);
108245
ret.functionType = functionType;
109246
return ret;
110247
}
111248

112249
/** Composes the respective nullable type of this type. */
113250
asNullable(): Type | null {
114-
assert(this.kind == TypeKind.USIZE);
115-
if (this.isNullable && !this.nullableType)
251+
assert(this.kind == TypeKind.USIZE && !this.isReference);
252+
if (this.isNullable && !this.nullableType) {
116253
(this.nullableType = new Type(this.kind, this.size)).isNullable = true;
254+
this.nullableType.classType = this.classType;
255+
this.nullableType.functionType = this.functionType;
256+
}
117257
return this.nullableType;
118258
}
119259

@@ -226,6 +366,34 @@ export class Type {
226366
}
227367
}
228368

369+
/** Converts this type to its native `-1` value. */
370+
toNativeNegOne(module: Module): ExpressionRef {
371+
switch (this.kind) {
372+
373+
case TypeKind.VOID:
374+
assert(false);
375+
376+
default:
377+
return module.createI32(-1);
378+
379+
case TypeKind.ISIZE:
380+
case TypeKind.USIZE:
381+
if (this.size != 64)
382+
return module.createI32(-1);
383+
// fall-through
384+
385+
case TypeKind.I64:
386+
case TypeKind.U64:
387+
return module.createI64(-1, -1);
388+
389+
case TypeKind.F32:
390+
return module.createF32(-1);
391+
392+
case TypeKind.F64:
393+
return module.createF64(-1);
394+
}
395+
}
396+
229397
/** Converts this type to its signature string. */
230398
toSignatureString(): string {
231399
switch (this.kind) {

std/assembly.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,14 @@ declare const Infinity: f32 | f64;
173173
declare const HEAP_BASE: usize;
174174
/** Determines the byte size of the specified core or class type. Compiles to a constant. */
175175
declare function sizeof<T>(): usize;
176-
/** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */
176+
/** Changes the type of any value of `usize` kind to another one of `usize` kind. Useful for casting class instances to their pointer values and vice-versa. Beware that this is unsafe.*/
177177
declare function changetype<T>(value: any): T;
178178
/** Tests if a 32-bit or 64-bit float is `NaN`. */
179179
declare function isNaN<T = f32 | f64>(value: T): bool;
180180
/** Tests if a 32-bit or 64-bit float is finite, that is not `NaN` or +/-`Infinity`. */
181181
declare function isFinite<T = f32 | f64>(value: T): bool;
182-
/** Traps if the specified value evaluates to `false`. */
183-
declare function assert(isTrue: bool, message?: string): void;
182+
/** Traps if the specified value is not true-ish, otherwise returns the value. */
183+
declare function assert<T>(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`?
184184
/** Parses an integer string to a 64-bit float. */
185185
declare function parseInt(str: string, radix?: i32): f64;
186186
/** Parses a string to a 64-bit float. */

std/assembly/regexp.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
@global
2+
class RegExp {
3+
4+
// @binding(CALL_NEW, [ STRING, STRING], OBJECT_HANDLE)
5+
constructor(pattern: string, flags: string = "") { throw new Error("unreachable"); }
6+
7+
// @binding(CALL_THIS, [ STRING ], PASS_THRU)
8+
test(search: string): bool { throw new Error("unreachable"); }
9+
10+
// @binding(CALL_THIS, [], STRING)
11+
toString(): string { throw new Error("unreachable"); }
12+
13+
}

std/assembly/string.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,15 @@ function isWhiteSpaceOrLineTerminator(c: u16): bool {
196196
return false;
197197
}
198198
}
199+
200+
// @global
201+
// @binding(CALL, [ STRING, PASS_THRU ], PASS_THRU)
202+
export function parseInt(str: string, radix: i32 = 10): f64 {
203+
throw new Error("not implemented");
204+
}
205+
206+
// @global
207+
// @binding(CALL, [ STRING ], PASS_THRU)
208+
export function parseFloat(str: string): f64 {
209+
throw new Error("not implemented");
210+
}

std/portable.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,10 +123,10 @@ declare function store<T = u8>(offset: usize, value: T): void;
123123
/** Emits an unreachable operation that results in a runtime error when executed. */
124124
declare function unreachable(): any; // sic
125125

126-
/** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */
126+
/** Changes the type of any value of `usize` kind to another one of `usize` kind. Useful for casting class instances to their pointer values and vice-versa. Beware that this is unsafe.*/
127127
declare function changetype<T>(value: any): T;
128-
/** Traps if the specified value evaluates to `false`. */
129-
declare function assert(isTrue: bool, message?: string): void;
128+
/** Traps if the specified value is not true-ish, otherwise returns the value. */
129+
declare function assert<T>(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`?
130130
/** Parses an integer string to a 64-bit float. */
131131
declare function parseInt(str: string, radix?: i32): f64;
132132
/** Parses a floating point string to a 64-bit float. */

0 commit comments

Comments
 (0)