Make type checking builtins also accept just a type argument

This commit is contained in:
dcodeIO 2018-04-07 23:31:36 +02:00
parent 8ffc7d463d
commit dcc0e284fb
12 changed files with 1113 additions and 888 deletions

2
dist/asc.js vendored

File diff suppressed because one or more lines are too long

2
dist/asc.js.map vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -105,118 +105,46 @@ export function compileCall(
// types // types
case "isInteger": { case "isInteger": { // isInteger<T!>() / isInteger<T?>(value: T) -> bool
compiler.currentType = Type.bool; let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
if (typeArguments) {
compiler.error(
DiagnosticCode.Type_0_is_not_generic,
reportNode.range, prototype.internalName
); // recoverable
}
if (operands.length != 1) {
compiler.error(
DiagnosticCode.Expected_0_arguments_but_got_1,
reportNode.range, "1", operands.length.toString(10)
);
return module.createUnreachable();
}
compiler.compileExpressionRetainType(operands[0], Type.i32, false);
let type = compiler.currentType;
compiler.currentType = Type.bool; compiler.currentType = Type.bool;
if (!type) return module.createUnreachable();
return type.is(TypeFlags.INTEGER) && !type.is(TypeFlags.REFERENCE) return type.is(TypeFlags.INTEGER) && !type.is(TypeFlags.REFERENCE)
? module.createI32(1) ? module.createI32(1)
: module.createI32(0); : module.createI32(0);
} }
case "isFloat": { case "isFloat": { // isFloat<T!>() / isFloat<T?>(value: T) -> bool
compiler.currentType = Type.bool; let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
if (typeArguments) {
compiler.error(
DiagnosticCode.Type_0_is_not_generic,
reportNode.range, prototype.internalName
); // recoverable
}
if (operands.length != 1) {
compiler.error(
DiagnosticCode.Expected_0_arguments_but_got_1,
reportNode.range, "1", operands.length.toString(10)
);
return module.createUnreachable();
}
compiler.compileExpressionRetainType(operands[0], Type.i32, false);
let type = compiler.currentType;
compiler.currentType = Type.bool; compiler.currentType = Type.bool;
if (!type) return module.createUnreachable();
return type.is(TypeFlags.FLOAT) return type.is(TypeFlags.FLOAT)
? module.createI32(1) ? module.createI32(1)
: module.createI32(0); : module.createI32(0);
} }
case "isReference": { case "isReference": { // isReference<T!>() / isReference<T?>(value: T) -> bool
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
compiler.currentType = Type.bool; compiler.currentType = Type.bool;
if (typeArguments) { if (!type) return module.createUnreachable();
compiler.error(
DiagnosticCode.Type_0_is_not_generic,
reportNode.range, prototype.internalName
); // recoverable
}
if (operands.length != 1) {
compiler.error(
DiagnosticCode.Expected_0_arguments_but_got_1,
reportNode.range, "1", operands.length.toString(10)
);
return module.createUnreachable();
}
compiler.compileExpressionRetainType(operands[0], Type.i32, false);
let type = compiler.currentType;
compiler.currentType = Type.bool; compiler.currentType = Type.bool;
return type.is(TypeFlags.REFERENCE) return type.is(TypeFlags.REFERENCE)
? module.createI32(1) ? module.createI32(1)
: module.createI32(0); : module.createI32(0);
} }
case "isString": { case "isString": { // isString<T!>() / isString<T?>(value: T) -> bool
compiler.currentType = Type.bool; let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
if (typeArguments) {
compiler.error(
DiagnosticCode.Type_0_is_not_generic,
reportNode.range, prototype.internalName
); // recoverable
}
if (operands.length != 1) {
compiler.error(
DiagnosticCode.Expected_0_arguments_but_got_1,
reportNode.range, "1", operands.length.toString(10)
);
return module.createUnreachable();
}
compiler.compileExpressionRetainType(operands[0], Type.i32, false);
let type = compiler.currentType;
compiler.currentType = Type.bool; compiler.currentType = Type.bool;
if (!type) return module.createUnreachable();
let classType = type.classReference; let classType = type.classReference;
if (classType) { if (classType) {
let stringInstance = compiler.program.stringInstance; let stringInstance = compiler.program.stringInstance;
if (!stringInstance) return module.createUnreachable(); if (stringInstance && classType.isAssignableTo(stringInstance)) return module.createI32(1);
if (classType.isAssignableTo(stringInstance)) {
return module.createI32(1);
}
} }
return module.createI32(0); return module.createI32(0);
} }
case "isArray": { case "isArray": { // isArray<T!>() / isArray<T?>(value: T) -> bool
compiler.currentType = Type.bool; let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
if (typeArguments) {
compiler.error(
DiagnosticCode.Type_0_is_not_generic,
reportNode.range, prototype.internalName
); // recoverable
}
if (operands.length != 1) {
compiler.error(
DiagnosticCode.Expected_0_arguments_but_got_1,
reportNode.range, "1", operands.length.toString(10)
);
return module.createUnreachable();
}
compiler.compileExpressionRetainType(operands[0], Type.i32, false);
let type = compiler.currentType;
compiler.currentType = Type.bool; compiler.currentType = Type.bool;
if (!type) return module.createUnreachable();
let classType = type.classReference; let classType = type.classReference;
return classType != null && classType.prototype.fnIndexedGet != null return classType != null && classType.prototype.fnIndexedGet != null
? module.createI32(1) ? module.createI32(1)
@ -2546,6 +2474,54 @@ export function compileCall(
return module.createUnreachable(); return module.createUnreachable();
} }
function evaluateConstantType(
compiler: Compiler,
typeArguments: Type[] | null,
operands: Expression[],
reportNode: Node
): Type | null {
if (operands.length == 0) { // requires type argument
if (!typeArguments || typeArguments.length != 1) {
compiler.error(
DiagnosticCode.Expected_0_type_arguments_but_got_1,
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
);
return null;
}
return typeArguments[0];
}
if (operands.length == 1) { // optional type argument
if (typeArguments) {
if (typeArguments.length == 1) {
compiler.compileExpression(operands[0], typeArguments[0], ConversionKind.IMPLICIT, false);
} else {
if (typeArguments.length) {
compiler.error(
DiagnosticCode.Expected_0_type_arguments_but_got_1,
reportNode.range, "1", typeArguments.length.toString(10)
);
return null;
}
compiler.compileExpressionRetainType(operands[0], Type.i32, false);
}
} else {
compiler.compileExpressionRetainType(operands[0], Type.i32, false);
}
return compiler.currentType;
}
if (typeArguments && typeArguments.length > 1) {
compiler.error(
DiagnosticCode.Expected_0_type_arguments_but_got_1,
reportNode.range, "1", typeArguments.length.toString(10)
);
}
compiler.error(
DiagnosticCode.Expected_0_arguments_but_got_1,
reportNode.range, "1", operands.length.toString(10)
);
return null;
}
function evaluateConstantOffset(compiler: Compiler, expression: Expression): i32 { function evaluateConstantOffset(compiler: Compiler, expression: Expression): i32 {
var expr: ExpressionRef; var expr: ExpressionRef;
var value: i32; var value: i32;

10
std/assembly.d.ts vendored
View File

@ -236,15 +236,15 @@ declare function isNaN<T = f32 | f64>(value: T): bool;
/** Tests if a 32-bit or 64-bit float is finite, that is not `NaN` or +/-`Infinity`. */ /** Tests if a 32-bit or 64-bit float is finite, that is not `NaN` or +/-`Infinity`. */
declare function isFinite<T = f32 | f64>(value: T): bool; declare function isFinite<T = f32 | f64>(value: T): bool;
/** Tests if the specified expression is of an integer type and not a reference. Compiles to a constant. */ /** Tests if the specified expression is of an integer type and not a reference. Compiles to a constant. */
declare function isInteger(value: any): value is number; declare function isInteger<T>(value?: any): value is number;
/** Tests if the specified expression is of a float type. Compiles to a constant. */ /** Tests if the specified expression is of a float type. Compiles to a constant. */
declare function isFloat(value: any): value is number; declare function isFloat<T>(value?: any): value is number;
/** Tests if the specified expression is of a reference type. Compiles to a constant. */ /** Tests if the specified expression is of a reference type. Compiles to a constant. */
declare function isReference(value: any): value is object | string; declare function isReference<T>(value?: any): value is object | string;
/** Tests if the specified expression can be used ass a string. Compiles to a constant. */ /** Tests if the specified expression can be used ass a string. Compiles to a constant. */
declare function isString(value: any): value is string | String; declare function isString<T>(value?: any): value is string | String;
/** Tests if the specified expression can be used as an array. Compiles to a constant. */ /** Tests if the specified expression can be used as an array. Compiles to a constant. */
declare function isArray(value: any): value is Array<any>; declare function isArray<T>(value?: any): value is Array<any>;
/** Traps if the specified value is not true-ish, otherwise returns the (non-nullable) value. */ /** Traps if the specified value is not true-ish, otherwise returns the (non-nullable) value. */
declare function assert<T>(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`? declare function assert<T>(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`?
/** Parses an integer string to a 64-bit float. */ /** Parses an integer string to a 64-bit float. */

View File

@ -1,12 +1,12 @@
export declare function isInteger(value: void): bool; export declare function isInteger<T>(value?: T): bool;
export declare function isFloat(value: void): bool; export declare function isFloat<T>(value?: T): bool;
export declare function isReference(value: void): bool; export declare function isReference<T>(value?: T): bool;
export declare function isString(value: void): bool; export declare function isString<T>(value?: T): bool;
export declare function isArray(value: void): bool; export declare function isArray<T>(value?: T): bool;
export declare const NaN: f64; // | f32 export declare const NaN: f64; // | f32

View File

@ -79,7 +79,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 34) (i32.const 43)
(i32.const 19) (i32.const 19)
) )
(unreachable) (unreachable)
@ -106,7 +106,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 35) (i32.const 44)
(i32.const 20) (i32.const 20)
) )
(unreachable) (unreachable)
@ -131,7 +131,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 36) (i32.const 45)
(i32.const 20) (i32.const 20)
) )
(unreachable) (unreachable)
@ -176,7 +176,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 52) (i32.const 61)
(i32.const 19) (i32.const 19)
) )
(unreachable) (unreachable)
@ -205,7 +205,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 53) (i32.const 62)
(i32.const 20) (i32.const 20)
) )
(unreachable) (unreachable)
@ -230,7 +230,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 54) (i32.const 63)
(i32.const 20) (i32.const 20)
) )
(unreachable) (unreachable)
@ -657,7 +657,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 244) (i32.const 253)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -674,7 +674,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 245) (i32.const 254)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -700,7 +700,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 246) (i32.const 255)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -726,7 +726,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 247) (i32.const 256)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -752,7 +752,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 248) (i32.const 257)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -778,7 +778,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 249) (i32.const 258)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -806,7 +806,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 250) (i32.const 259)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -834,7 +834,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 4) (i32.const 4)
(i32.const 251) (i32.const 260)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)

View File

@ -1,12 +1,21 @@
var b: bool; var b: bool;
// types // type checks
assert(isInteger<i32>());
assert(!isInteger<f32>());
assert(isFloat<f32>());
assert(!isFloat<i32>());
assert(isReference<string>());
assert(!isReference<usize>());
assert(isArray<i32[]>());
assert(!isArray<usize>());
assert(isInteger(<i32>1)); assert(isInteger(<i32>1));
assert(!isInteger(<f32>1)); assert(!isInteger(<f32>1));
assert(isFloat(<f32>1)); assert(isFloat(<f32>1));
assert(!isFloat(<i32>1)); assert(!isFloat(<i32>1));
assert(isReference(changetype<String>(null))); assert(isReference(changetype<string>(null)));
assert(!isReference(changetype<usize>(null))); assert(!isReference(changetype<usize>(null)));
assert(isString("1")); assert(isString("1"));
assert(!isString(1)); assert(!isString(1));

File diff suppressed because it is too large Load Diff

View File

@ -6404,7 +6404,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 34) (i32.const 43)
(i32.const 19) (i32.const 19)
) )
(unreachable) (unreachable)
@ -6431,7 +6431,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 35) (i32.const 44)
(i32.const 20) (i32.const 20)
) )
(unreachable) (unreachable)
@ -6456,7 +6456,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 36) (i32.const 45)
(i32.const 20) (i32.const 20)
) )
(unreachable) (unreachable)
@ -6501,7 +6501,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 52) (i32.const 61)
(i32.const 19) (i32.const 19)
) )
(unreachable) (unreachable)
@ -6530,7 +6530,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 53) (i32.const 62)
(i32.const 20) (i32.const 20)
) )
(unreachable) (unreachable)
@ -6555,7 +6555,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 54) (i32.const 63)
(i32.const 20) (i32.const 20)
) )
(unreachable) (unreachable)
@ -6982,7 +6982,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 244) (i32.const 253)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -6999,7 +6999,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 245) (i32.const 254)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -7025,7 +7025,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 246) (i32.const 255)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -7051,7 +7051,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 247) (i32.const 256)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -7077,7 +7077,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 248) (i32.const 257)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -7103,7 +7103,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 249) (i32.const 258)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -7131,7 +7131,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 250) (i32.const 259)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)
@ -7159,7 +7159,7 @@
(call $abort (call $abort
(i32.const 0) (i32.const 0)
(i32.const 28) (i32.const 28)
(i32.const 251) (i32.const 260)
(i32.const 0) (i32.const 0)
) )
(unreachable) (unreachable)

File diff suppressed because it is too large Load Diff