Skip to content

Commit

Permalink
Merges ExitForStatement and ExitWhileStatement (#1289)
Browse files Browse the repository at this point in the history
* Merges exitFor and exitWhile statements

* Properly use original text for exitwhile (one word)

* Updates the tokens in parser.tokens to reflect the created while token
  • Loading branch information
markwpearce authored Aug 21, 2024
1 parent 353f463 commit 43cbf8b
Show file tree
Hide file tree
Showing 13 changed files with 203 additions and 100 deletions.
17 changes: 6 additions & 11 deletions src/astUtils/reflection.spec.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/* eslint-disable no-multi-spaces */
import { expect } from '../chai-config.spec';
import { PrintStatement, Block, Body, AssignmentStatement, ExitForStatement, ExitWhileStatement, ExpressionStatement, FunctionStatement, IfStatement, IncrementStatement, GotoStatement, LabelStatement, ReturnStatement, EndStatement, StopStatement, ForStatement, ForEachStatement, WhileStatement, DottedSetStatement, IndexedSetStatement, LibraryStatement, NamespaceStatement, ImportStatement, ClassStatement, EmptyStatement, TryCatchStatement, CatchStatement, ThrowStatement } from '../parser/Statement';
import { PrintStatement, Block, Body, AssignmentStatement, ExpressionStatement, FunctionStatement, IfStatement, IncrementStatement, GotoStatement, LabelStatement, ReturnStatement, EndStatement, StopStatement, ForStatement, ForEachStatement, WhileStatement, DottedSetStatement, IndexedSetStatement, LibraryStatement, NamespaceStatement, ImportStatement, ClassStatement, EmptyStatement, TryCatchStatement, CatchStatement, ThrowStatement, ExitStatement } from '../parser/Statement';
import { FunctionExpression, BinaryExpression, CallExpression, DottedGetExpression, IndexedGetExpression, GroupingExpression, EscapedCharCodeLiteralExpression, ArrayLiteralExpression, AALiteralExpression, UnaryExpression, VariableExpression, SourceLiteralExpression, NewExpression, CallfuncExpression, TemplateStringQuasiExpression, XmlAttributeGetExpression, TemplateStringExpression, TaggedTemplateStringExpression, AnnotationExpression } from '../parser/Expression';
import type { Token } from '../lexer/Token';
import { TokenKind } from '../lexer/TokenKind';
import { isPrintStatement, isIfStatement, isBody, isAssignmentStatement, isBlock, isExpressionStatement, isExitForStatement, isExitWhileStatement, isFunctionStatement, isIncrementStatement, isGotoStatement, isLabelStatement, isReturnStatement, isEndStatement, isStopStatement, isForStatement, isForEachStatement, isWhileStatement, isDottedSetStatement, isIndexedSetStatement, isLibraryStatement, isNamespaceStatement, isImportStatement, isExpression, isBinaryExpression, isCallExpression, isFunctionExpression, isDottedGetExpression, isXmlAttributeGetExpression, isIndexedGetExpression, isGroupingExpression, isLiteralExpression, isEscapedCharCodeLiteralExpression, isArrayLiteralExpression, isAALiteralExpression, isUnaryExpression, isVariableExpression, isSourceLiteralExpression, isNewExpression, isCallfuncExpression, isTemplateStringQuasiExpression, isTemplateStringExpression, isTaggedTemplateStringExpression, isBrsFile, isXmlFile, isClassStatement, isStatement, isAnnotationExpression, isTryCatchStatement, isCatchStatement, isThrowStatement, isLiteralInvalid, isLiteralBoolean, isLiteralNumber, isLiteralInteger, isLiteralLongInteger, isLiteralFloat, isLiteralDouble } from './reflection';
import { isPrintStatement, isIfStatement, isBody, isAssignmentStatement, isBlock, isExpressionStatement, isFunctionStatement, isIncrementStatement, isGotoStatement, isLabelStatement, isReturnStatement, isEndStatement, isStopStatement, isForStatement, isForEachStatement, isWhileStatement, isDottedSetStatement, isIndexedSetStatement, isLibraryStatement, isNamespaceStatement, isImportStatement, isExpression, isBinaryExpression, isCallExpression, isFunctionExpression, isDottedGetExpression, isXmlAttributeGetExpression, isIndexedGetExpression, isGroupingExpression, isLiteralExpression, isEscapedCharCodeLiteralExpression, isArrayLiteralExpression, isAALiteralExpression, isUnaryExpression, isVariableExpression, isSourceLiteralExpression, isNewExpression, isCallfuncExpression, isTemplateStringQuasiExpression, isTemplateStringExpression, isTaggedTemplateStringExpression, isBrsFile, isXmlFile, isClassStatement, isStatement, isAnnotationExpression, isTryCatchStatement, isCatchStatement, isThrowStatement, isLiteralInvalid, isLiteralBoolean, isLiteralNumber, isLiteralInteger, isLiteralLongInteger, isLiteralFloat, isLiteralDouble, isExitStatement } from './reflection';
import { createToken, createStringLiteral, createInvalidLiteral, createBooleanLiteral, createIntegerLiteral, createVariableExpression, createFloatLiteral, createDoubleLiteral, createLongIntegerLiteral } from './creators';
import { Program } from '../Program';
import { BrsFile } from '../files/BrsFile';
Expand All @@ -31,8 +31,7 @@ describe('reflection', () => {
const assignment = new AssignmentStatement({ equals: undefined, name: ident, value: expr });
const block = new Block({ statements: [] });
const expression = new ExpressionStatement({ expression: expr });
const exitFor = new ExitForStatement({ exitFor: token });
const exitWhile = new ExitWhileStatement({ exitWhile: token });
const exit = new ExitStatement({ exit: token, loopType: token });
const funs = new FunctionStatement({
name: ident,
func: new FunctionExpression({
Expand Down Expand Up @@ -92,13 +91,9 @@ describe('reflection', () => {
expect(isExpressionStatement(expression)).to.be.true;
expect(isExpressionStatement(body)).to.be.false;
});
it('isExitForStatement', () => {
expect(isExitForStatement(exitFor)).to.be.true;
expect(isExitForStatement(body)).to.be.false;
});
it('isExitWhileStatement', () => {
expect(isExitWhileStatement(exitWhile)).to.be.true;
expect(isExitWhileStatement(body)).to.be.false;
it('isExitStatement', () => {
expect(isExitStatement(exit)).to.be.true;
expect(isExitStatement(body)).to.be.false;
});
it('isFunctionStatement', () => {
expect(isFunctionStatement(funs)).to.be.true;
Expand Down
9 changes: 3 additions & 6 deletions src/astUtils/reflection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Body, AssignmentStatement, Block, ExpressionStatement, ExitForStatement, ExitWhileStatement, FunctionStatement, IfStatement, IncrementStatement, PrintStatement, GotoStatement, LabelStatement, ReturnStatement, EndStatement, StopStatement, ForStatement, ForEachStatement, WhileStatement, DottedSetStatement, IndexedSetStatement, LibraryStatement, NamespaceStatement, ImportStatement, ClassStatement, InterfaceFieldStatement, InterfaceMethodStatement, InterfaceStatement, EnumStatement, EnumMemberStatement, TryCatchStatement, CatchStatement, ThrowStatement, MethodStatement, FieldStatement, ConstStatement, ContinueStatement, TypecastStatement, AliasStatement, ConditionalCompileStatement, ConditionalCompileConstStatement, ConditionalCompileErrorStatement, AugmentedAssignmentStatement } from '../parser/Statement';
import type { Body, AssignmentStatement, Block, ExpressionStatement, ExitStatement, FunctionStatement, IfStatement, IncrementStatement, PrintStatement, GotoStatement, LabelStatement, ReturnStatement, EndStatement, StopStatement, ForStatement, ForEachStatement, WhileStatement, DottedSetStatement, IndexedSetStatement, LibraryStatement, NamespaceStatement, ImportStatement, ClassStatement, InterfaceFieldStatement, InterfaceMethodStatement, InterfaceStatement, EnumStatement, EnumMemberStatement, TryCatchStatement, CatchStatement, ThrowStatement, MethodStatement, FieldStatement, ConstStatement, ContinueStatement, TypecastStatement, AliasStatement, ConditionalCompileStatement, ConditionalCompileConstStatement, ConditionalCompileErrorStatement, AugmentedAssignmentStatement } from '../parser/Statement';
import type { LiteralExpression, BinaryExpression, CallExpression, FunctionExpression, DottedGetExpression, XmlAttributeGetExpression, IndexedGetExpression, GroupingExpression, EscapedCharCodeLiteralExpression, ArrayLiteralExpression, AALiteralExpression, UnaryExpression, VariableExpression, SourceLiteralExpression, NewExpression, CallfuncExpression, TemplateStringQuasiExpression, TemplateStringExpression, TaggedTemplateStringExpression, AnnotationExpression, FunctionParameterExpression, AAMemberExpression, TypecastExpression, TypeExpression, TypedArrayExpression } from '../parser/Expression';
import type { BrsFile } from '../files/BrsFile';
import type { XmlFile } from '../files/XmlFile';
Expand Down Expand Up @@ -85,11 +85,8 @@ export function isBlock(element: AstNode | undefined): element is Block {
export function isExpressionStatement(element: AstNode | undefined): element is ExpressionStatement {
return element?.kind === AstNodeKind.ExpressionStatement;
}
export function isExitForStatement(element: AstNode | undefined): element is ExitForStatement {
return element?.kind === AstNodeKind.ExitForStatement;
}
export function isExitWhileStatement(element: AstNode | undefined): element is ExitWhileStatement {
return element?.kind === AstNodeKind.ExitWhileStatement;
export function isExitStatement(element: AstNode | undefined): element is ExitStatement {
return element?.kind === AstNodeKind.ExitStatement;
}
export function isFunctionStatement(element: AstNode | undefined): element is FunctionStatement {
return element?.kind === AstNodeKind.FunctionStatement;
Expand Down
5 changes: 2 additions & 3 deletions src/astUtils/visitors.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint-disable no-bitwise */
import type { CancellationToken } from 'vscode-languageserver';
import type { Body, AssignmentStatement, Block, ExpressionStatement, ExitForStatement, ExitWhileStatement, FunctionStatement, IfStatement, IncrementStatement, PrintStatement, GotoStatement, LabelStatement, ReturnStatement, EndStatement, StopStatement, ForStatement, ForEachStatement, WhileStatement, DottedSetStatement, IndexedSetStatement, LibraryStatement, NamespaceStatement, ImportStatement, ClassStatement, EnumStatement, EnumMemberStatement, DimStatement, TryCatchStatement, CatchStatement, ThrowStatement, InterfaceStatement, InterfaceFieldStatement, InterfaceMethodStatement, FieldStatement, MethodStatement, ConstStatement, ContinueStatement, TypecastStatement, AliasStatement, ConditionalCompileStatement, ConditionalCompileErrorStatement, ConditionalCompileConstStatement, AugmentedAssignmentStatement } from '../parser/Statement';
import type { Body, AssignmentStatement, Block, ExpressionStatement, FunctionStatement, IfStatement, IncrementStatement, PrintStatement, GotoStatement, LabelStatement, ReturnStatement, EndStatement, StopStatement, ForStatement, ForEachStatement, WhileStatement, DottedSetStatement, IndexedSetStatement, LibraryStatement, NamespaceStatement, ImportStatement, ClassStatement, EnumStatement, EnumMemberStatement, DimStatement, TryCatchStatement, CatchStatement, ThrowStatement, InterfaceStatement, InterfaceFieldStatement, InterfaceMethodStatement, FieldStatement, MethodStatement, ConstStatement, ContinueStatement, TypecastStatement, AliasStatement, ConditionalCompileStatement, ConditionalCompileErrorStatement, ConditionalCompileConstStatement, AugmentedAssignmentStatement, ExitStatement } from '../parser/Statement';
import type { AALiteralExpression, AAMemberExpression, AnnotationExpression, ArrayLiteralExpression, BinaryExpression, CallExpression, CallfuncExpression, DottedGetExpression, EscapedCharCodeLiteralExpression, FunctionExpression, FunctionParameterExpression, GroupingExpression, IndexedGetExpression, LiteralExpression, NewExpression, NullCoalescingExpression, RegexLiteralExpression, SourceLiteralExpression, TaggedTemplateStringExpression, TemplateStringExpression, TemplateStringQuasiExpression, TernaryExpression, TypecastExpression, TypeExpression, UnaryExpression, VariableExpression, XmlAttributeGetExpression } from '../parser/Expression';
import { isExpression, isStatement } from './reflection';
import type { Editor } from './Editor';
Expand Down Expand Up @@ -116,8 +116,7 @@ export function createVisitor(
AssignmentStatement?: (statement: AssignmentStatement, parent?: Statement, owner?: any, key?: any) => Statement | void;
Block?: (statement: Block, parent?: Statement, owner?: any, key?: any) => Statement | void;
ExpressionStatement?: (statement: ExpressionStatement, parent?: Statement, owner?: any, key?: any) => Statement | void;
ExitForStatement?: (statement: ExitForStatement, parent?: Statement, owner?: any, key?: any) => Statement | void;
ExitWhileStatement?: (statement: ExitWhileStatement, parent?: Statement, owner?: any, key?: any) => Statement | void;
ExitStatement?: (statement: ExitStatement, parent?: Statement, owner?: any, key?: any) => Statement | void;
FunctionStatement?: (statement: FunctionStatement, parent?: Statement, owner?: any, key?: any) => Statement | void;
IfStatement?: (statement: IfStatement, parent?: Statement, owner?: any, key?: any) => Statement | void;
IncrementStatement?: (statement: IncrementStatement, parent?: Statement, owner?: any, key?: any) => Statement | void;
Expand Down
49 changes: 49 additions & 0 deletions src/files/BrsFile.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2953,6 +2953,55 @@ describe('BrsFile', () => {
expect(location.column).eql(4);
});

describe('jump statements', () => {
it('handles exit for', async () => {
await testTranspile(`
sub main()
for i = 1 to 10
exit for
end for
end sub
`);
});

it('handles exit while', async () => {
await testTranspile(`
sub main()
while true
exit while
end while
end sub
`);
});

it('handles exitWhile (one word)', async () => {
await testTranspile(`
sub main()
while true
exitWhile
end while
end sub
`);
});

it('transpiles case correctly', async () => {
await testTranspile(`
sub main()
for i = 1 to 10
eXiT fOr
end for
while true
exIt whILE
end while
while true
eXitWhile
end while
end sub
`);
});
});


describe('sourcemap validation', () => {
it('computes correct source and position in sourcemap', async () => {
program.options.sourceMap = true;
Expand Down
9 changes: 6 additions & 3 deletions src/lexer/Lexer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -932,7 +932,7 @@ describe('lexer', () => {
it('matches single-word keywords', () => {
// test just a sample of single-word reserved words for now.
// if we find any that we've missed
let { tokens } = Lexer.scan('and then or if else endif return true false line_num');
let { tokens } = Lexer.scan('and then or if else endif return true false line_num exitwhile');
expect(tokens.map(w => w.kind)).to.deep.equal([
TokenKind.And,
TokenKind.Then,
Expand All @@ -944,6 +944,7 @@ describe('lexer', () => {
TokenKind.True,
TokenKind.False,
TokenKind.LineNumLiteral,
TokenKind.ExitWhile,
TokenKind.Eof
]);
});
Expand All @@ -955,15 +956,17 @@ describe('lexer', () => {
TokenKind.EndWhile,
TokenKind.EndSub,
TokenKind.EndFunction,
TokenKind.ExitWhile,
TokenKind.Exit,
TokenKind.While,
TokenKind.Eof
]);
});

it('accepts \'exit for\' but not \'exitfor\'', () => {
let { tokens } = Lexer.scan('exit for exitfor');
expect(tokens.map(w => w.kind)).to.deep.equal([
TokenKind.ExitFor,
TokenKind.Exit,
TokenKind.For,
TokenKind.Identifier,
TokenKind.Eof
]);
Expand Down
5 changes: 0 additions & 5 deletions src/lexer/TokenKind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ export enum TokenKind {
EndWhile = 'EndWhile',
Eval = 'Eval',
Exit = 'Exit',
ExitFor = 'ExitFor', // not technically a reserved word, but definitely a tokenKind
ExitWhile = 'ExitWhile',
False = 'False',
For = 'For',
Expand Down Expand Up @@ -269,9 +268,7 @@ export const Keywords: Record<string, TokenKind> = {
endwhile: TokenKind.EndWhile,
'end while': TokenKind.EndWhile,
exit: TokenKind.Exit,
'exit for': TokenKind.ExitFor, // note: 'exitfor' (no space) is *not* a keyword
exitwhile: TokenKind.ExitWhile,
'exit while': TokenKind.ExitWhile,
false: TokenKind.False,
for: TokenKind.For,
'for each': TokenKind.ForEach, // note: 'foreach' (no space) is *not* a keyword
Expand Down Expand Up @@ -400,7 +397,6 @@ export const AllowedProperties = [
TokenKind.EndWhile,
TokenKind.Eval,
TokenKind.Exit,
TokenKind.ExitFor,
TokenKind.ExitWhile,
TokenKind.False,
TokenKind.For,
Expand Down Expand Up @@ -476,7 +472,6 @@ export const AllowedProperties = [
/** List of TokenKind that are allowed as local var identifiers. */
export const AllowedLocalIdentifiers = [
TokenKind.EndFor,
TokenKind.ExitFor,
TokenKind.ForEach,
TokenKind.Void,
TokenKind.Boolean,
Expand Down
3 changes: 1 addition & 2 deletions src/parser/AstNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,7 @@ export enum AstNodeKind {
EmptyStatement = 'EmptyStatement',
AssignmentStatement = 'AssignmentStatement',
ExpressionStatement = 'ExpressionStatement',
ExitForStatement = 'ExitForStatement',
ExitWhileStatement = 'ExitWhileStatement',
ExitStatement = 'ExitStatement',
FunctionStatement = 'FunctionStatement',
IfStatement = 'IfStatement',
IncrementStatement = 'IncrementStatement',
Expand Down
Loading

0 comments on commit 43cbf8b

Please sign in to comment.