Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support resolving all kinds of expressions #726

Merged
merged 12 commits into from Sep 10, 2019
123 changes: 63 additions & 60 deletions src/ast.ts
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
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