Skip to content

Commit

Permalink
Support passing enums as their literal values (#849)
Browse files Browse the repository at this point in the history
  • Loading branch information
TwitchBronBron authored Jul 18, 2023
1 parent a6a7b51 commit 091221b
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 7 deletions.
62 changes: 62 additions & 0 deletions src/bscPlugin/validation/ScopeValidator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,68 @@ describe('ScopeValidator', () => {
});

describe('argumentTypeMismatch', () => {

it('treats string enums as strings when assigned to string vars', () => {
program.setFile('source/file.bs', `
sub main()
printDirection(Direction.up)
end sub
sub printDirection(theDirection as string)
print theDirection
end sub
enum Direction
up = "up"
down = "down"
end enum
`);
program.validate();
expectZeroDiagnostics(program);
});

it('does not treat strings as a string enum', () => {
program.setFile('source/file.bs', `
sub main()
printDirection("up")
end sub
sub printDirection(theDirection as Direction)
print theDirection
end sub
enum Direction
up = "up"
down = "down"
end enum
`);
program.validate();
expectDiagnostics(program, [
DiagnosticMessages.argumentTypeMismatch('string', 'Direction')
]);
});

it('supports passing enum type as enum type', () => {
program.setFile('source/file.bs', `
sub test(theDirection as Direction)
printDirection(theDirection)
end sub
sub printDirection(theDirection as Direction)
print theDirection
end sub
enum Direction
up = "up"
down = "down"
end enum
`);
program.validate();
expectDiagnostics(program, [
]);
});

it('Catches argument type mismatches on function calls', () => {
program.setFile('source/file.brs', `
sub a(age as integer)
Expand Down
15 changes: 12 additions & 3 deletions src/parser/Statement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2640,9 +2640,14 @@ export class EnumStatement extends Statement implements TypedefProvider {
}

getType(options: GetTypeOptions) {
const resultType = new EnumType(this.fullName);
const members = this.getMembers();

const resultType = new EnumType(
this.fullName,
members[0]?.getType(options)
);
resultType.pushMemberProvider(() => this.getSymbolTable());
for (const statement of this.getMembers()) {
for (const statement of members) {
resultType.addMember(statement?.tokens?.name?.text, statement?.range, statement.getType(options), SymbolTypeFlag.runtime);
}

Expand Down Expand Up @@ -2704,7 +2709,11 @@ export class EnumMemberStatement extends Statement implements TypedefProvider {
}

getType(options: GetTypeOptions) {
return new EnumMemberType((this.parent as EnumStatement)?.fullName, this.tokens?.name?.text);
return new EnumMemberType(
(this.parent as EnumStatement)?.fullName,
this.tokens?.name?.text,
this.value?.getType(options)
);
}
}

Expand Down
13 changes: 11 additions & 2 deletions src/types/EnumType.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { isDynamicType, isEnumMemberType, isEnumType } from '../astUtils/reflection';
import { BscType } from './BscType';
import { BscTypeKind } from './BscTypeKind';
import { DynamicType } from './DynamicType';

export class EnumType extends BscType {
constructor(
public name: string
public name: string,
/**
* The runtime type for this enum (i.e. what type the value will be transpiled into)
*/
public underlyingType: BscType = DynamicType.instance
) {
super(name);
}
Expand Down Expand Up @@ -36,7 +41,11 @@ export class EnumType extends BscType {
export class EnumMemberType extends BscType {
constructor(
public enumName: string,
public memberName: string
public memberName: string,
/**
* The runtime type for this enum (i.e. what type the value will be transpiled into)
*/
public underlyingType: BscType = DynamicType.instance
) {
super(`${enumName}.${memberName}`);
}
Expand Down
8 changes: 6 additions & 2 deletions src/types/StringType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isDynamicType, isStringType } from '../astUtils/reflection';
import { isDynamicType, isEnumMemberType, isEnumType, isStringType } from '../astUtils/reflection';
import { BscType } from './BscType';
import { BscTypeKind } from './BscTypeKind';

Expand All @@ -19,7 +19,11 @@ export class StringType extends BscType {
public isTypeCompatible(targetType: BscType) {
return (
isStringType(targetType) ||
isDynamicType(targetType)
isDynamicType(targetType) ||
//string enums are compatible with strings
(
(isEnumType(targetType) || isEnumMemberType(targetType)) && isStringType(targetType.underlyingType)
)
);
}

Expand Down

0 comments on commit 091221b

Please sign in to comment.