Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 63 additions & 60 deletions src/ast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ export abstract class Node {
stmt.range = range;
stmt.name = name;
stmt.arguments = args;
stmt.decoratorKind = decoratorNameToKind(name);
stmt.decoratorKind = DecoratorKind.fromNode(name);
return stmt;
}

Expand Down Expand Up @@ -1187,73 +1187,76 @@ export enum DecoratorKind {
UNSAFE
}

/** Returns the kind of the specified decorator. Defaults to {@link DecoratorKind.CUSTOM}. */
export function decoratorNameToKind(name: Expression): DecoratorKind {
// @global, @inline, @operator, @sealed, @unmanaged
if (name.kind == NodeKind.IDENTIFIER) {
let nameStr = (<IdentifierExpression>name).text;
assert(nameStr.length);
switch (nameStr.charCodeAt(0)) {
case CharCode.b: {
if (nameStr == "builtin") return DecoratorKind.BUILTIN;
break;
}
case CharCode.e: {
if (nameStr == "external") return DecoratorKind.EXTERNAL;
break;
}
case CharCode.g: {
if (nameStr == "global") return DecoratorKind.GLOBAL;
break;
}
case CharCode.i: {
if (nameStr == "inline") return DecoratorKind.INLINE;
break;
}
case CharCode.l: {
if (nameStr == "lazy") return DecoratorKind.LAZY;
break;
}
case CharCode.o: {
if (nameStr == "operator") return DecoratorKind.OPERATOR;
break;
}
case CharCode.s: {
if (nameStr == "sealed") return DecoratorKind.SEALED;
break;
}
case CharCode.u: {
if (nameStr == "unmanaged") return DecoratorKind.UNMANAGED;
if (nameStr == "unsafe") return DecoratorKind.UNSAFE;
break;
}
}
} else if (
name.kind == NodeKind.PROPERTYACCESS &&
(<PropertyAccessExpression>name).expression.kind == NodeKind.IDENTIFIER
) {
let nameStr = (<IdentifierExpression>(<PropertyAccessExpression>name).expression).text;
assert(nameStr.length);
let propStr = (<PropertyAccessExpression>name).property.text;
assert(propStr.length);
// @operator.binary, @operator.prefix, @operator.postfix
if (nameStr == "operator") {
switch (propStr.charCodeAt(0)) {
export namespace DecoratorKind {

/** Returns the kind of the specified decorator name node. Defaults to {@link DecoratorKind.CUSTOM}. */
export function fromNode(nameNode: Expression): DecoratorKind {
// @global, @inline, @operator, @sealed, @unmanaged
if (nameNode.kind == NodeKind.IDENTIFIER) {
let nameStr = (<IdentifierExpression>nameNode).text;
assert(nameStr.length);
switch (nameStr.charCodeAt(0)) {
case CharCode.b: {
if (propStr == "binary") return DecoratorKind.OPERATOR_BINARY;
if (nameStr == "builtin") return DecoratorKind.BUILTIN;
break;
}
case CharCode.p: {
switch (propStr) {
case "prefix": return DecoratorKind.OPERATOR_PREFIX;
case "postfix": return DecoratorKind.OPERATOR_POSTFIX;
}
case CharCode.e: {
if (nameStr == "external") return DecoratorKind.EXTERNAL;
break;
}
case CharCode.g: {
if (nameStr == "global") return DecoratorKind.GLOBAL;
break;
}
case CharCode.i: {
if (nameStr == "inline") return DecoratorKind.INLINE;
break;
}
case CharCode.l: {
if (nameStr == "lazy") return DecoratorKind.LAZY;
break;
}
case CharCode.o: {
if (nameStr == "operator") return DecoratorKind.OPERATOR;
break;
}
case CharCode.s: {
if (nameStr == "sealed") return DecoratorKind.SEALED;
break;
}
case CharCode.u: {
if (nameStr == "unmanaged") return DecoratorKind.UNMANAGED;
if (nameStr == "unsafe") return DecoratorKind.UNSAFE;
break;
}
}
} else if (
nameNode.kind == NodeKind.PROPERTYACCESS &&
(<PropertyAccessExpression>nameNode).expression.kind == NodeKind.IDENTIFIER
) {
let nameStr = (<IdentifierExpression>(<PropertyAccessExpression>nameNode).expression).text;
assert(nameStr.length);
let propStr = (<PropertyAccessExpression>nameNode).property.text;
assert(propStr.length);
// @operator.binary, @operator.prefix, @operator.postfix
if (nameStr == "operator") {
switch (propStr.charCodeAt(0)) {
case CharCode.b: {
if (propStr == "binary") return DecoratorKind.OPERATOR_BINARY;
break;
}
case CharCode.p: {
switch (propStr) {
case "prefix": return DecoratorKind.OPERATOR_PREFIX;
case "postfix": return DecoratorKind.OPERATOR_POSTFIX;
}
break;
}
}
}
}
return DecoratorKind.CUSTOM;
}
return DecoratorKind.CUSTOM;
}

/** Represents a decorator. */
Expand Down
55 changes: 34 additions & 21 deletions src/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -595,29 +595,38 @@ export function compileCall(
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
compiler.currentType = Type.bool;
if (!type) return module.unreachable();
let classType = type.classReference;
if (classType) {
let stringInstance = compiler.program.stringInstance;
if (stringInstance && classType.isAssignableTo(stringInstance)) return module.i32(1);
if (type.is(TypeFlags.REFERENCE)) {
let classReference = type.classReference;
if (classReference) {
let stringInstance = compiler.program.stringInstance;
if (stringInstance && classReference.isAssignableTo(stringInstance)) return module.i32(1);
}
}
return module.i32(0);
}
case BuiltinSymbols.isArray: { // isArray<T!>() / isArray<T?>(value: T) -> bool
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
compiler.currentType = Type.bool;
if (!type) return module.unreachable();
let classReference = type.classReference;
if (!classReference) return module.i32(0);
let classPrototype = classReference.prototype;
return module.i32(classPrototype.extends(compiler.program.arrayPrototype) ? 1 : 0);
if (type.is(TypeFlags.REFERENCE)) {
let classReference = type.classReference;
if (classReference) {
return module.i32(classReference.prototype.extends(compiler.program.arrayPrototype) ? 1 : 0);
}
}
return module.i32(0);
}
case BuiltinSymbols.isArrayLike: { // isArrayLike<T!>() / isArrayLike<T?>(value: T) -> bool
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
compiler.currentType = Type.bool;
if (!type) return module.unreachable();
let classReference = type.classReference;
if (!classReference) return module.i32(0);
return module.i32(classReference.isArrayLike ? 1 : 0);
if (type.is(TypeFlags.REFERENCE)) {
let classReference = type.classReference;
if (classReference) {
return module.i32(classReference.isArrayLike ? 1 : 0);
}
}
return module.i32(0);
}
case BuiltinSymbols.isFunction: { // isFunction<T!> / isFunction<T?>(value: T) -> bool
let type = evaluateConstantType(compiler, typeArguments, operands, reportNode);
Expand All @@ -637,7 +646,7 @@ export function compileCall(
checkTypeAbsent(typeArguments, reportNode, prototype) |
checkArgsRequired(operands, 1, reportNode, compiler)
) return module.unreachable();
let element = compiler.resolver.resolveExpression(
let element = compiler.resolver.lookupExpression(
operands[0],
compiler.currentFlow,
Type.auto,
Expand Down Expand Up @@ -747,8 +756,9 @@ export function compileCall(
checkTypeRequired(typeArguments, reportNode, compiler) |
checkArgsOptional(operands, 0, 1, reportNode, compiler)
) return module.unreachable();
let classType = typeArguments![0].classReference;
if (!classType) {
let typeArgument = typeArguments![0];
let classType = typeArgument.classReference;
if (!(typeArgument.is(TypeFlags.REFERENCE) && classType !== null)) {
compiler.error(
DiagnosticCode.Operation_not_supported,
reportNode.typeArgumentsRange
Expand Down Expand Up @@ -2436,8 +2446,9 @@ export function compileCall(
if (
checkTypeRequired(typeArguments, reportNode, compiler, true)
) return module.unreachable();
let classInstance = typeArguments![0].classReference;
if (!classInstance) {
let typeArgument = typeArguments![0];
let classInstance = typeArgument.classReference;
if (!(typeArgument.is(TypeFlags.REFERENCE) && classInstance !== null)) {
compiler.error(
DiagnosticCode.Operation_not_supported,
reportNode.typeArgumentsRange
Expand Down Expand Up @@ -3665,7 +3676,7 @@ export function compileCall(
}

let classReference = type.classReference;
if (!classReference || classReference.hasDecorator(DecoratorFlags.UNMANAGED)) {
if (!type.is(TypeFlags.REFERENCE) || !classReference || classReference.hasDecorator(DecoratorFlags.UNMANAGED)) {
compiler.error(
DiagnosticCode.Operation_not_supported,
reportNode.range
Expand Down Expand Up @@ -4102,11 +4113,13 @@ export function compileVisitGlobals(compiler: Compiler): void {
for (let element of compiler.program.elementsByName.values()) {
if (element.kind != ElementKind.GLOBAL) continue;
let global = <Global>element;
let classReference = global.type.classReference;
let globalType = global.type;
let classType = globalType.classReference;
if (
global.is(CommonFlags.COMPILED) &&
classReference !== null &&
!classReference.hasDecorator(DecoratorFlags.UNMANAGED)
globalType.is(TypeFlags.REFERENCE) &&
classType !== null &&
!classType.hasDecorator(DecoratorFlags.UNMANAGED) &&
global.is(CommonFlags.COMPILED)
) {
if (global.is(CommonFlags.INLINED)) {
let value = global.constantIntegerValue;
Expand Down
Loading