Rename lib prefix to '~lib' (parens aren't valid); Add built-in alignof<T>; Prepare for ArrayBufferView

This commit is contained in:
dcodeIO
2018-04-02 19:05:26 +02:00
parent 3b50720603
commit 06198a3723
51 changed files with 2286 additions and 2209 deletions

View File

@ -534,7 +534,7 @@ export abstract class Node {
identifier: IdentifierExpression,
typeParameters: TypeParameterNode[],
extendsType: TypeNode | null, // can't be a function
implementsTypes: TypeNode[], // can't be a function
implementsTypes: TypeNode[] | null, // can't be functions
members: DeclarationStatement[],
decorators: DecoratorNode[] | null,
flags: CommonFlags,
@ -546,7 +546,7 @@ export abstract class Node {
stmt.name = identifier; identifier.parent = stmt;
stmt.typeParameters = typeParameters; setParent(typeParameters, stmt);
stmt.extendsType = extendsType; if (extendsType) extendsType.parent = stmt;
stmt.implementsTypes = implementsTypes; setParent(implementsTypes, stmt);
stmt.implementsTypes = implementsTypes; if (implementsTypes) setParent(implementsTypes, stmt);
stmt.members = members; setParent(members, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt;
@ -756,8 +756,10 @@ export abstract class Node {
static createInterfaceDeclaration(
name: IdentifierExpression,
typeParameters: TypeParameterNode[],
extendsType: TypeNode | null, // can't be a function
members: DeclarationStatement[],
decorators: DecoratorNode[] | null,
flags: CommonFlags,
range: Range
): InterfaceDeclaration {
@ -765,8 +767,10 @@ export abstract class Node {
stmt.range = range;
stmt.flags = flags;
stmt.name = name; name.parent = stmt;
stmt.typeParameters = typeParameters; if (typeParameters) setParent(typeParameters, stmt);
stmt.extendsType = extendsType; if (extendsType) extendsType.parent = stmt;
stmt.members = members; setParent(members, stmt);
stmt.decorators = decorators; if (decorators) setParent(decorators, stmt);
return stmt;
}
@ -1487,10 +1491,10 @@ export class ClassDeclaration extends DeclarationStatement {
/** Accepted type parameters. */
typeParameters: TypeParameterNode[];
/** Base class type being extended. */
/** Base class type being extended, if any. */
extendsType: TypeNode | null; // can't be a function
/** Interface types being implemented. */
implementsTypes: TypeNode[]; // can't be a function
/** Interface types being implemented, if any. */
implementsTypes: TypeNode[] | null; // can't be functions
/** Class member declarations. */
members: DeclarationStatement[];

View File

@ -1790,6 +1790,55 @@ export function compileCall(
}
return ret;
}
case "alignof": { // alignof<T!>() -> usize
compiler.currentType = compiler.options.usizeType;
if (operands.length != 0) {
if (!(typeArguments && typeArguments.length == 1)) {
compiler.error(
DiagnosticCode.Expected_0_type_arguments_but_got_1,
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
);
}
compiler.error(
DiagnosticCode.Expected_0_arguments_but_got_1,
reportNode.range, "0", operands.length.toString(10)
);
return module.createUnreachable();
}
if (!(typeArguments && typeArguments.length == 1)) {
compiler.error(
DiagnosticCode.Expected_0_type_arguments_but_got_1,
reportNode.range, "1", typeArguments ? typeArguments.length.toString(10) : "0"
);
}
let byteSize = (<Type[]>typeArguments)[0].byteSize;
let alignLog2: i32;
switch (byteSize) {
case 1: { alignLog2 = 0; break; }
case 2: { alignLog2 = 1; break; }
case 4: { alignLog2 = 2; break; }
case 8: { alignLog2 = 3; break; }
default: { assert(false); return module.createUnreachable(); }
}
if (compiler.options.isWasm64) {
// implicitly wrap if contextual type is a 32-bit integer
if (contextualType.is(TypeFlags.INTEGER) && contextualType.size <= 32) {
compiler.currentType = Type.u32;
ret = module.createI32(alignLog2);
} else {
ret = module.createI64(alignLog2, 0);
}
} else {
// implicitly extend if contextual type is a 64-bit integer
if (contextualType.is(TypeFlags.INTEGER) && contextualType.size == 64) {
compiler.currentType = Type.u64;
ret = module.createI64(alignLog2, 0);
} else {
ret = module.createI32(alignLog2);
}
}
return ret;
}
case "offsetof": { // offsetof<T!>(fieldName?: string) -> usize
compiler.currentType = compiler.options.usizeType;
if (operands.length > 1) {

View File

@ -367,7 +367,7 @@ export class Compiler extends DiagnosticEmitter {
}
}
// try (lib)/file.ts
// try ~lib/file.ts
expected = LIBRARY_PREFIX + normalizedPathWithoutExtension + ".ts";
for (let i = 0, k = sources.length; i < k; ++i) {
let source = sources[i];

View File

@ -64,6 +64,7 @@ export enum DiagnosticCode {
Declaration_expected = 1146,
_const_declarations_must_be_initialized = 1155,
Unterminated_regular_expression_literal = 1161,
Interface_declaration_cannot_have_implements_clause = 1176,
Binary_digit_expected = 1177,
Octal_digit_expected = 1178,
An_implementation_cannot_be_declared_in_ambient_contexts = 1183,
@ -169,6 +170,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 1146: return "Declaration expected.";
case 1155: return "'const' declarations must be initialized.";
case 1161: return "Unterminated regular expression literal.";
case 1176: return "Interface declaration cannot have 'implements' clause.";
case 1177: return "Binary digit expected.";
case 1178: return "Octal digit expected.";
case 1183: return "An implementation cannot be declared in ambient contexts.";

View File

@ -57,6 +57,7 @@
"Declaration expected.": 1146,
"'const' declarations must be initialized.": 1155,
"Unterminated regular expression literal.": 1161,
"Interface declaration cannot have 'implements' clause.": 1176,
"Binary digit expected.": 1177,
"Octal digit expected.": 1178,
"An implementation cannot be declared in ambient contexts.": 1183,

View File

@ -784,13 +784,15 @@ export class ASTBuilder {
this.visitTypeNode(extendsType);
}
var implementsTypes = node.implementsTypes;
var numImplementsTypes = implementsTypes.length;
if (numImplementsTypes) {
sb.push(" implements ");
this.visitTypeNode(implementsTypes[0]);
for (let i = 1; i < numImplementsTypes; ++i) {
sb.push(", ");
this.visitTypeNode(implementsTypes[i]);
if (implementsTypes) {
let numImplementsTypes = implementsTypes.length;
if (numImplementsTypes) {
sb.push(" implements ");
this.visitTypeNode(implementsTypes[0]);
for (let i = 1; i < numImplementsTypes; ++i) {
sb.push(", ");
this.visitTypeNode(implementsTypes[i]);
}
}
}
var members = node.members;
@ -1123,6 +1125,7 @@ export class ASTBuilder {
sb.push(" extends ");
this.visitTypeNode(extendsType);
}
// must not have implementsTypes
sb.push(" {\n");
var indentLevel = ++this.indentLevel;
var members = node.members;

View File

@ -262,9 +262,10 @@ export class Parser extends DiagnosticEmitter {
}
// fall through
}
case Token.CLASS: {
case Token.CLASS:
case Token.INTERFACE: {
tn.next();
statement = this.parseClass(tn, flags, decorators, startPos);
statement = this.parseClassOrInterface(tn, flags, decorators, startPos);
decorators = null;
break;
}
@ -1381,20 +1382,22 @@ export class Parser extends DiagnosticEmitter {
return Node.createFunctionExpression(declaration);
}
parseClass(
parseClassOrInterface(
tn: Tokenizer,
flags: CommonFlags,
decorators: DecoratorNode[] | null,
startPos: i32
): ClassDeclaration | null {
// at 'class':
// at ('class' | 'interface'):
// Identifier
// ('<' TypeParameters)?
// ('extends' Type)?
// ('implements' Type (',' Type)*)?
// '{' ClassMember* '}'
var isInterface = tn.token == Token.INTERFACE;
if (!tn.skip(Token.IDENTIFIER)) {
this.error(
DiagnosticCode.Identifier_expected,
@ -1431,12 +1434,21 @@ export class Parser extends DiagnosticEmitter {
extendsType = <TypeNode>t;
}
var implementsTypes = new Array<TypeNode>();
var implementsTypes: TypeNode[] | null = null;
if (tn.skip(Token.IMPLEMENTS)) {
if (isInterface) {
this.error(
DiagnosticCode.Interface_declaration_cannot_have_implements_clause,
tn.range()
); // recoverable
}
do {
let type = this.parseType(tn);
if (!type) return null;
implementsTypes.push(<TypeNode>type);
if (!isInterface) {
if (!implementsTypes) implementsTypes = [];
implementsTypes.push(<TypeNode>type);
}
} while (tn.skip(Token.COMMA));
}
@ -1449,16 +1461,30 @@ export class Parser extends DiagnosticEmitter {
}
var members = new Array<DeclarationStatement>();
var declaration = Node.createClassDeclaration(
identifier,
typeParameters,
extendsType,
implementsTypes,
members,
decorators,
flags,
tn.range(startPos, tn.pos)
);
var declaration: ClassDeclaration;
if (isInterface) {
assert(!implementsTypes);
declaration = Node.createInterfaceDeclaration(
identifier,
typeParameters,
extendsType,
members,
decorators,
flags,
tn.range(startPos, tn.pos)
);
} else {
declaration = Node.createClassDeclaration(
identifier,
typeParameters,
extendsType,
implementsTypes,
members,
decorators,
flags,
tn.range(startPos, tn.pos)
);
}
if (!tn.skip(Token.CLOSEBRACE)) {
do {
let member = this.parseClassMember(tn, declaration);

View File

@ -85,7 +85,7 @@ export const INSTANCE_DELIMITER = "#";
/** Delimiter used between class and namespace names and static members. */
export const STATIC_DELIMITER = ".";
/** Substitution used to indicate a library directory. */
export const LIBRARY_SUBST = "(lib)";
export const LIBRARY_SUBST = "~lib";
/** Library directory prefix. */
export const LIBRARY_PREFIX = LIBRARY_SUBST + PATH_DELIMITER;
@ -417,23 +417,25 @@ export class Program extends DiagnosticEmitter {
this.elementsLookup.set(internalName, prototype);
var implementsTypes = declaration.implementsTypes;
var numImplementsTypes = implementsTypes.length;
if (prototype.is(CommonFlags.UNMANAGED)) {
if (implementsTypes && numImplementsTypes) {
this.error(
DiagnosticCode.Structs_cannot_implement_interfaces,
Range.join(
declaration.name.range,
implementsTypes[numImplementsTypes - 1].range
)
);
}
} else if (numImplementsTypes) {
for (let i = 0; i < numImplementsTypes; ++i) {
this.error(
DiagnosticCode.Operation_not_supported,
implementsTypes[i].range
);
if (implementsTypes) {
let numImplementsTypes = implementsTypes.length;
if (prototype.is(CommonFlags.UNMANAGED)) {
if (implementsTypes && numImplementsTypes) {
this.error(
DiagnosticCode.Structs_cannot_implement_interfaces,
Range.join(
declaration.name.range,
implementsTypes[numImplementsTypes - 1].range
)
);
}
} else if (numImplementsTypes) {
for (let i = 0; i < numImplementsTypes; ++i) {
this.error(
DiagnosticCode.Operation_not_supported,
implementsTypes[i].range
);
}
}
}