Properly resolve enum value siblings

This commit is contained in:
dcodeIO 2018-01-24 03:08:09 +01:00
parent 29935948f2
commit b548b5c81f
7 changed files with 50 additions and 7 deletions

View File

@ -187,6 +187,8 @@ export class Compiler extends DiagnosticEmitter {
/** Current function in compilation. */
currentFunction: Function;
/** Current enum in compilation. */
currentEnum: Enum | null = null;
/** Current type in compilation. */
currentType: Type = Type.void;
@ -214,6 +216,7 @@ export class Compiler extends DiagnosticEmitter {
// set up start function
var startFunctionTemplate = new FunctionPrototype(program, "start", "start", null);
var startFunctionInstance = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null);
startFunctionInstance.set(ElementFlags.START);
this.currentFunction = this.startFunction = startFunctionInstance;
}
@ -472,6 +475,7 @@ export class Compiler extends DiagnosticEmitter {
// members might reference each other, triggering another compile
element.set(ElementFlags.COMPILED);
this.currentEnum = element;
var previousValue: EnumValue | null = null;
if (element.members)
for (var member of element.members.values()) {
@ -480,6 +484,7 @@ export class Compiler extends DiagnosticEmitter {
var initInStart = false;
var val = <EnumValue>member;
var valueDeclaration = val.declaration;
val.set(ElementFlags.COMPILED);
if (val.is(ElementFlags.INLINED)) {
if (!element.declaration || element.declaration.isTopLevelExport)
this.module.addGlobal(val.internalName, NativeType.I32, false, this.module.createI32(val.constantValue));
@ -533,6 +538,7 @@ export class Compiler extends DiagnosticEmitter {
this.warning(DiagnosticCode.Cannot_export_a_mutable_global, valueDeclaration.range);
}
}
this.currentEnum = null;
return true;
}
@ -2775,7 +2781,7 @@ export class Compiler extends DiagnosticEmitter {
}
// otherwise resolve
var resolved = this.program.resolveIdentifier(expression, this.currentFunction); // reports
var resolved = this.program.resolveIdentifier(expression, this.currentFunction, this.currentEnum); // reports
if (!resolved)
return this.module.createUnreachable();
@ -2799,6 +2805,17 @@ export class Compiler extends DiagnosticEmitter {
return this.compileInlineConstant(<Global>element, contextualType);
this.currentType = (<Global>element).type;
return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
case ElementKind.ENUMVALUE: // here: if referenced from within the same enum
if (!element.is(ElementFlags.COMPILED)) {
this.error(DiagnosticCode.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums, expression.range);
this.currentType = Type.i32;
return this.module.createUnreachable();
}
this.currentType = Type.i32;
if ((<EnumValue>element).is(ElementFlags.INLINED))
return this.module.createI32((<EnumValue>element).constantValue);
return this.module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32);
}
this.error(DiagnosticCode.Operation_not_supported, expression.range);
return this.module.createUnreachable();

View File

@ -86,6 +86,7 @@ export enum DiagnosticCode {
Expected_0_arguments_but_got_1 = 2554,
Expected_at_least_0_arguments_but_got_1 = 2555,
Expected_0_type_arguments_but_got_1 = 2558,
A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums = 2651,
Namespace_0_has_no_exported_member_1 = 2694,
File_0_not_found = 6054
}
@ -177,6 +178,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 2554: return "Expected {0} arguments, but got {1}.";
case 2555: return "Expected at least {0} arguments, but got {1}.";
case 2558: return "Expected {0} type arguments, but got {1}.";
case 2651: return "A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums.";
case 2694: return "Namespace '{0}' has no exported member '{1}'.";
case 6054: return "File '{0}' not found.";
default: return "";

View File

@ -86,6 +86,7 @@
"Expected {0} arguments, but got {1}.": 2554,
"Expected at least {0} arguments, but got {1}.": 2555,
"Expected {0} type arguments, but got {1}.": 2558,
"A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums.": 2651,
"Namespace '{0}' has no exported member '{1}'.": 2694,
"File '{0}' not found.": 6054

View File

@ -992,18 +992,24 @@ export class Program extends DiagnosticEmitter {
}
/** Resolves an identifier to the element it refers to. */
resolveIdentifier(identifier: IdentifierExpression, contextualFunction: Function | null): ResolvedElement | null {
resolveIdentifier(identifier: IdentifierExpression, contextualFunction: Function | null, contextualEnum: Enum | null = null): ResolvedElement | null {
var name = identifier.name;
var element: Element | null;
var namespace: Element | null;
var reference: Element | null;
if (contextualFunction) {
// check siblings
if (contextualEnum) {
if (contextualEnum.members && (element = contextualEnum.members.get(name)) && element.kind == ElementKind.ENUMVALUE)
return (resolvedElement || (resolvedElement = new ResolvedElement())).set(element);
} else if (contextualFunction) {
// check locals
var local = contextualFunction.flow.getScopedLocal(name);
if (local)
return (resolvedElement || (resolvedElement = new ResolvedElement())).set(local);
if (element = contextualFunction.flow.getScopedLocal(name))
return (resolvedElement || (resolvedElement = new ResolvedElement())).set(element);
// search contextual parent namespaces if applicable
if (namespace = contextualFunction.prototype.namespace) {
@ -1259,7 +1265,9 @@ export enum ElementFlags {
/** Has already inherited base class static members. */
HAS_STATIC_BASE_MEMBERS = 1 << 18,
/** Is scoped. */
SCOPED = 1 << 19
SCOPED = 1 << 19,
/** Is the start function. */
START = 1 << 20
}
/** Base class of all program elements. */

View File

@ -14,6 +14,8 @@
(global $enum/Mixed.FOUR i32 (i32.const 4))
(global $enum/NonConstant.ZERO (mut i32) (i32.const 0))
(global $enum/NonConstant.ONE (mut i32) (i32.const 0))
(global $enum/SelfReference.ZERO i32 (i32.const 0))
(global $enum/SelfReference.ONE i32 (i32.const 1))
(memory $0 1)
(export "enum/Implicit.ZERO" (global $enum/Implicit.ZERO))
(export "enum/Implicit.ONE" (global $enum/Implicit.ONE))
@ -27,6 +29,8 @@
(export "enum/Mixed.ONE" (global $enum/Mixed.ONE))
(export "enum/Mixed.THREE" (global $enum/Mixed.THREE))
(export "enum/Mixed.FOUR" (global $enum/Mixed.FOUR))
(export "enum/SelfReference.ZERO" (global $enum/SelfReference.ZERO))
(export "enum/SelfReference.ONE" (global $enum/SelfReference.ONE))
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -27,3 +27,8 @@ export enum NonConstant {
ZERO = getZero(), // cannot export a mutable global
ONE // cannot export a mutable global (tsc doesn't allow this)
}
export enum SelfReference {
ZERO,
ONE = ZERO + 1
}

View File

@ -15,6 +15,8 @@
(global $enum/Mixed.FOUR i32 (i32.const 4))
(global $enum/NonConstant.ZERO (mut i32) (i32.const 0))
(global $enum/NonConstant.ONE (mut i32) (i32.const 0))
(global $enum/SelfReference.ZERO i32 (i32.const 0))
(global $enum/SelfReference.ONE i32 (i32.const 1))
(global $HEAP_BASE i32 (i32.const 4))
(memory $0 1)
(export "enum/Implicit.ZERO" (global $enum/Implicit.ZERO))
@ -29,6 +31,8 @@
(export "enum/Mixed.ONE" (global $enum/Mixed.ONE))
(export "enum/Mixed.THREE" (global $enum/Mixed.THREE))
(export "enum/Mixed.FOUR" (global $enum/Mixed.FOUR))
(export "enum/SelfReference.ZERO" (global $enum/SelfReference.ZERO))
(export "enum/SelfReference.ONE" (global $enum/SelfReference.ONE))
(export "memory" (memory $0))
(start $start)
(func $enum/getZero (; 0 ;) (type $i) (result i32)
@ -97,9 +101,11 @@
ENUM: enum/Mixed
FUNCTION_PROTOTYPE: enum/getZero
ENUM: enum/NonConstant
ENUM: enum/SelfReference
[program.exports]
ENUM: enum/Implicit
ENUM: enum/Explicit
ENUM: enum/Mixed
ENUM: enum/NonConstant
ENUM: enum/SelfReference
;)