From 9389ef0b02c6f83e1ba2f23beadefb5906d4836e Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Mon, 5 Oct 2020 22:32:56 -0400 Subject: [PATCH 1/9] Initial refactor. Many bugs remain --- src/astUtils/creators.ts | 46 +- src/astUtils/reflection.spec.ts | 36 +- src/astUtils/reflection.ts | 78 +- src/astUtils/visitors.spec.ts | 11 +- src/brsTypes/Boxing.ts | 10 - src/brsTypes/BrsNumber.ts | 85 -- src/brsTypes/BrsType.ts | 304 -------- src/brsTypes/Callable.ts | 322 -------- src/brsTypes/Double.ts | 183 ----- src/brsTypes/Float.ts | 197 ----- src/brsTypes/Int32.ts | 204 ----- src/brsTypes/Int64.ts | 211 ----- src/brsTypes/components/BrsComponent.ts | 51 -- src/brsTypes/components/BrsObjects.ts | 17 - src/brsTypes/components/RoArray.ts | 183 ----- src/brsTypes/components/RoAssociativeArray.ts | 219 ------ src/brsTypes/components/RoRegex.ts | 166 ---- src/brsTypes/components/RoSGNode.ts | 733 ------------------ src/brsTypes/components/RoString.ts | 436 ----------- src/brsTypes/components/Timespan.ts | 93 --- src/brsTypes/index.ts | 102 --- src/files/BrsFile.ts | 25 +- src/interfaces.ts | 24 +- src/lexer/Lexer.spec.ts | 65 +- src/lexer/Lexer.ts | 31 +- src/lexer/Token.ts | 3 - src/parser/Expression.ts | 92 ++- src/parser/Parser.ts | 74 +- src/parser/Statement.ts | 18 +- src/parser/tests/Parser.spec.ts | 3 +- src/parser/tests/controlFlow/For.spec.ts | 18 +- src/parser/tests/controlFlow/If.spec.ts | 48 +- src/parser/tests/controlFlow/While.spec.ts | 13 +- src/parser/tests/expression/Additive.spec.ts | 17 +- .../tests/expression/ArrayLiterals.spec.ts | 44 +- .../AssociativeArrayLiterals.spec.ts | 34 +- src/parser/tests/expression/Boolean.spec.ts | 12 +- src/parser/tests/expression/Call.spec.ts | 8 +- .../tests/expression/Exponential.spec.ts | 12 +- src/parser/tests/expression/Function.spec.ts | 32 +- src/parser/tests/expression/Indexing.spec.ts | 17 +- .../tests/expression/Multiplicative.spec.ts | 26 +- .../tests/expression/PrefixUnary.spec.ts | 11 +- src/parser/tests/expression/Primary.spec.ts | 15 +- .../tests/expression/Relational.spec.ts | 26 +- .../statement/AssignmentOperators.spec.ts | 16 +- .../tests/statement/Declaration.spec.ts | 9 +- src/parser/tests/statement/Function.spec.ts | 26 +- .../tests/statement/PrintStatement.spec.ts | 15 +- .../tests/statement/ReturnStatement.spec.ts | 5 +- src/parser/tests/statement/Set.spec.ts | 15 +- src/preprocessor/Preprocessor.spec.ts | 36 +- src/preprocessor/PreprocessorParser.spec.ts | 4 +- src/types/ArrayType.ts | 12 +- src/types/BooleanType.ts | 8 +- src/types/BrsType.ts | 5 - src/types/BscType.ts | 5 + src/types/DoubleType.ts | 8 +- src/types/DynamicType.ts | 8 +- src/types/FloatType.ts | 8 +- src/types/FunctionType.ts | 14 +- src/types/IntegerType.ts | 8 +- src/types/InterfaceType.ts | 8 +- src/types/InvalidType.ts | 8 +- src/types/LongIntegerType.ts | 8 +- src/types/ObjectType.ts | 8 +- src/types/StringType.ts | 8 +- src/types/UninitializedType.ts | 8 +- src/types/VoidType.ts | 8 +- src/util.ts | 77 +- 70 files changed, 568 insertions(+), 4122 deletions(-) delete mode 100644 src/brsTypes/Boxing.ts delete mode 100644 src/brsTypes/BrsNumber.ts delete mode 100644 src/brsTypes/BrsType.ts delete mode 100644 src/brsTypes/Callable.ts delete mode 100644 src/brsTypes/Double.ts delete mode 100644 src/brsTypes/Float.ts delete mode 100644 src/brsTypes/Int32.ts delete mode 100644 src/brsTypes/Int64.ts delete mode 100644 src/brsTypes/components/BrsComponent.ts delete mode 100644 src/brsTypes/components/BrsObjects.ts delete mode 100644 src/brsTypes/components/RoArray.ts delete mode 100644 src/brsTypes/components/RoAssociativeArray.ts delete mode 100644 src/brsTypes/components/RoRegex.ts delete mode 100644 src/brsTypes/components/RoSGNode.ts delete mode 100644 src/brsTypes/components/RoString.ts delete mode 100644 src/brsTypes/components/Timespan.ts delete mode 100644 src/brsTypes/index.ts delete mode 100644 src/types/BrsType.ts create mode 100644 src/types/BscType.ts diff --git a/src/astUtils/creators.ts b/src/astUtils/creators.ts index 4a5d11618..cc1fcb71d 100644 --- a/src/astUtils/creators.ts +++ b/src/astUtils/creators.ts @@ -1,52 +1,50 @@ -import { Position } from 'vscode-languageserver'; +import { Range } from 'vscode-languageserver'; import { Token } from '../lexer/Token'; import { TokenKind } from '../lexer/TokenKind'; import { LiteralExpression, Expression, CallExpression, NamespacedVariableNameExpression, DottedGetExpression, VariableExpression } from '../parser/Expression'; -import { BrsType, BrsString, BrsInvalid, Int32, Float } from '../brsTypes'; -import util from '../util'; -export function createRange(pos: Position) { - return util.createRange(pos.line, pos.character, pos.line, pos.character); -} +export const interpolatedRange = Range.create(-1, -1, -1, -1); -export function createToken(kind: T, pos: Position, text?: string, literal?: BrsType): Token & { kind: T } { +export function createToken(kind: T, text?: string, range = interpolatedRange): Token & { kind: T } { return { kind: kind, text: text || kind.toString(), isReserved: !text || text === kind.toString(), - range: createRange(pos), - literal: literal, + range: range, leadingWhitespace: '' }; } -export function createIdentifier(ident: string, pos: Position, namespaceName?: NamespacedVariableNameExpression): VariableExpression { - return new VariableExpression(createToken(TokenKind.Identifier, pos, ident), namespaceName); +export function createIdentifier(ident: string, range?: Range, namespaceName?: NamespacedVariableNameExpression): VariableExpression { + return new VariableExpression(createToken(TokenKind.Identifier, ident, range), namespaceName); } -export function createDottedIdentifier(path: string[], pos: Position, namespaceName?: NamespacedVariableNameExpression): DottedGetExpression { +export function createDottedIdentifier(path: string[], range?: Range, namespaceName?: NamespacedVariableNameExpression): DottedGetExpression { const ident = path.pop(); - const obj = path.length > 1 ? createDottedIdentifier(path, pos, namespaceName) : createIdentifier(path[0], pos, namespaceName); - return new DottedGetExpression(obj, createToken(TokenKind.Identifier, pos, ident), createToken(TokenKind.Dot, pos, '.')); + const obj = path.length > 1 ? createDottedIdentifier(path, range, namespaceName) : createIdentifier(path[0], range, namespaceName); + return new DottedGetExpression(obj, createToken(TokenKind.Identifier, ident, range), createToken(TokenKind.Dot, '.', range)); } -export function createStringLiteral(value: string, pos: Position) { - return new LiteralExpression(new BrsString(value), createRange(pos)); +export function createStringLiteral(value: string, range?: Range) { + return new LiteralExpression(createToken(TokenKind.StringLiteral, value, range)); +} +export function createIntegerLiteral(value: string, range?: Range) { + return new LiteralExpression(createToken(TokenKind.IntegerLiteral, value, range)); } -export function createIntegerLiteral(value: number, pos: Position) { - return new LiteralExpression(new Int32(value), createRange(pos)); +export function createFloatLiteral(value: string, range?: Range) { + return new LiteralExpression(createToken(TokenKind.FloatLiteral, value, range)); } -export function createFloatLiteral(value: number, pos: Position) { - return new LiteralExpression(new Float(value), createRange(pos)); +export function createInvalidLiteral(range?: Range) { + return new LiteralExpression(createToken(TokenKind.Invalid, null, range)); } -export function createInvalidLiteral(pos: Position) { - return new LiteralExpression(new BrsInvalid(), createRange(pos)); +export function createBooleanLiteral(value: 'true' | 'false', range?: Range) { + return new LiteralExpression(createToken(value === 'true' ? TokenKind.True : TokenKind.False, value, range)); } export function createCall(callee: Expression, args?: Expression[], namespaceName?: NamespacedVariableNameExpression) { return new CallExpression( callee, - createToken(TokenKind.LeftParen, callee.range.end, '('), - createToken(TokenKind.RightParen, callee.range.end, ')'), + createToken(TokenKind.LeftParen, '('), + createToken(TokenKind.RightParen, ')'), args || [], namespaceName ); diff --git a/src/astUtils/reflection.spec.ts b/src/astUtils/reflection.spec.ts index 1c5938dac..f28e3776d 100644 --- a/src/astUtils/reflection.spec.ts +++ b/src/astUtils/reflection.spec.ts @@ -1,12 +1,10 @@ /* eslint-disable no-multi-spaces */ -import { Position, Range } from 'vscode-languageserver'; import { expect } from 'chai'; import { PrintStatement, Block, Body, AssignmentStatement, CommentStatement, ExitForStatement, ExitWhileStatement, ExpressionStatement, FunctionStatement, IfStatement, IncrementStatement, GotoStatement, LabelStatement, ReturnStatement, EndStatement, StopStatement, ForStatement, ForEachStatement, WhileStatement, DottedSetStatement, IndexedSetStatement, LibraryStatement, NamespaceStatement, ImportStatement, ClassStatement, EmptyStatement } from '../parser/Statement'; -import { FunctionExpression, NamespacedVariableNameExpression, BinaryExpression, CallExpression, DottedGetExpression, IndexedGetExpression, GroupingExpression, LiteralExpression, EscapedCharCodeLiteralExpression, ArrayLiteralExpression, AALiteralExpression, UnaryExpression, VariableExpression, SourceLiteralExpression, NewExpression, CallfuncExpression, TemplateStringQuasiExpression, XmlAttributeGetExpression, TemplateStringExpression, TaggedTemplateStringExpression } from '../parser/Expression'; +import { FunctionExpression, NamespacedVariableNameExpression, BinaryExpression, CallExpression, DottedGetExpression, IndexedGetExpression, GroupingExpression, EscapedCharCodeLiteralExpression, ArrayLiteralExpression, AALiteralExpression, UnaryExpression, VariableExpression, SourceLiteralExpression, NewExpression, CallfuncExpression, TemplateStringQuasiExpression, XmlAttributeGetExpression, TemplateStringExpression, TaggedTemplateStringExpression } from '../parser/Expression'; import { TokenKind, Token } from '../lexer'; -import { BrsString } from '../brsTypes'; import { isPrintStatement, isIfStatement, isBody, isAssignmentStatement, isBlock, isExpressionStatement, isCommentStatement, isExitForStatement, isExitWhileStatement, isFunctionStatement, isIncrementStatement, isGotoStatement, isLabelStatement, isReturnStatement, isEndStatement, isStopStatement, isForStatement, isForEachStatement, isWhileStatement, isDottedSetStatement, isIndexedSetStatement, isLibraryStatement, isNamespaceStatement, isImportStatement, isExpression, isBinaryExpression, isCallExpression, isFunctionExpression, isNamespacedVariableNameExpression, isDottedGetExpression, isXmlAttributeGetExpression, isIndexedGetExpression, isGroupingExpression, isLiteralExpression, isEscapedCharCodeLiteralExpression, isArrayLiteralExpression, isAALiteralExpression, isUnaryExpression, isVariableExpression, isSourceLiteralExpression, isNewExpression, isCallfuncExpression, isTemplateStringQuasiExpression, isTemplateStringExpression, isTaggedTemplateStringExpression, isBrsFile, isXmlFile, isClassStatement, isStatement } from './reflection'; -import { createRange, createToken, createStringLiteral, createIdentifier } from './creators'; +import { createToken, createStringLiteral, createIdentifier, interpolatedRange as range } from './creators'; import { Program } from '../Program'; import { BrsFile } from '../files/BrsFile'; import { XmlFile } from '../files/XmlFile'; @@ -23,11 +21,9 @@ describe('reflection', () => { }); describe('Statements', () => { - const pos = Position.create(0, 0); - const range = createRange(pos); - const ident = createToken(TokenKind.Identifier, pos, 'a'); - const expr = createStringLiteral('', pos); - const token = createToken(TokenKind.StringLiteral, pos, ''); + const ident = createToken(TokenKind.Identifier, 'a', range); + const expr = createStringLiteral('', range); + const token = createToken(TokenKind.StringLiteral, '', range); const body = new Body([]); const assignment = new AssignmentStatement(undefined, ident, expr, undefined); const block = new Block([], range); @@ -35,7 +31,7 @@ describe('reflection', () => { const comment = new CommentStatement([token]); const exitFor = new ExitForStatement({ exitFor: token }); const exitWhile = new ExitWhileStatement({ exitWhile: token }); - const funs = new FunctionStatement(ident, new FunctionExpression([], undefined, block, token, token, token, token), undefined); + const funs = new FunctionStatement(ident, new FunctionExpression([], block, token, token, token, token), undefined); const ifs = new IfStatement({ if: token }, expr, block, []); const increment = new IncrementStatement(expr, token); const print = new PrintStatement({ print: token }, []); @@ -50,7 +46,7 @@ describe('reflection', () => { const dottedSet = new DottedSetStatement(expr, ident, expr); const indexedSet = new IndexedSetStatement(expr, expr, expr, token, token); const library = new LibraryStatement({ library: token, filePath: token }); - const namespace = new NamespaceStatement(token, new NamespacedVariableNameExpression(createIdentifier('a', pos)), body, token); + const namespace = new NamespaceStatement(token, new NamespacedVariableNameExpression(createIdentifier('a', range)), body, token); const cls = new ClassStatement(token, ident, [], token); const imports = new ImportStatement(token, token); @@ -59,8 +55,7 @@ describe('reflection', () => { expect(isStatement(library)).to.be.true; expect( isStatement( - new LiteralExpression(new BrsString('test'), Range.create(0, 0, 0, 0) - ) + createStringLiteral('test') ) ).to.be.false; //doesn't fail for undefined @@ -170,12 +165,9 @@ describe('reflection', () => { }); describe('Expressions', () => { - const pos = Position.create(0, 0); - const range = createRange(pos); - const ident = createToken(TokenKind.Identifier, pos, 'a'); - const expr = createStringLiteral('', pos); - const token = createToken(TokenKind.StringLiteral, pos, ''); - const value = new BrsString(''); + const ident = createToken(TokenKind.Identifier, 'a', range); + const expr = createStringLiteral('', range); + const token = createToken(TokenKind.StringLiteral, '', range); const block = new Block([], range); const charCode: Token & { charCode: number } = { kind: TokenKind.EscapedCharCodeLiteral, @@ -185,15 +177,15 @@ describe('reflection', () => { charCode: 0, leadingWhitespace: '' }; - const nsVar = new NamespacedVariableNameExpression(createIdentifier('a', pos)); + const nsVar = new NamespacedVariableNameExpression(createIdentifier('a', range)); const binary = new BinaryExpression(expr, token, expr); const call = new CallExpression(expr, token, token, [], undefined); - const fun = new FunctionExpression([], undefined, block, token, token, token, token); + const fun = new FunctionExpression([], block, token, token, token, token); const dottedGet = new DottedGetExpression(expr, ident, token); const xmlAttrGet = new XmlAttributeGetExpression(expr, ident, token); const indexedGet = new IndexedGetExpression(expr, expr, token, token); const grouping = new GroupingExpression({ left: token, right: token }, expr); - const literal = new LiteralExpression(value, range); + const literal = createStringLiteral('test'); const escapedCarCode = new EscapedCharCodeLiteralExpression(charCode); const arrayLit = new ArrayLiteralExpression([], token, token); const aaLit = new AALiteralExpression([], token, token); diff --git a/src/astUtils/reflection.ts b/src/astUtils/reflection.ts index 571139d1e..04f94c59a 100644 --- a/src/astUtils/reflection.ts +++ b/src/astUtils/reflection.ts @@ -1,13 +1,17 @@ import { Body, AssignmentStatement, Block, ExpressionStatement, CommentStatement, ExitForStatement, ExitWhileStatement, FunctionStatement, IfStatement, IncrementStatement, PrintStatement, GotoStatement, LabelStatement, ReturnStatement, EndStatement, StopStatement, ForStatement, ForEachStatement, WhileStatement, DottedSetStatement, IndexedSetStatement, LibraryStatement, NamespaceStatement, ImportStatement, ClassFieldStatement, ClassMethodStatement, ClassStatement, Statement } from '../parser/Statement'; -import { LiteralExpression, Expression, BinaryExpression, CallExpression, FunctionExpression, NamespacedVariableNameExpression, DottedGetExpression, XmlAttributeGetExpression, IndexedGetExpression, GroupingExpression, EscapedCharCodeLiteralExpression, ArrayLiteralExpression, AALiteralExpression, UnaryExpression, VariableExpression, SourceLiteralExpression, NewExpression, CallfuncExpression, TemplateStringQuasiExpression, TemplateStringExpression, TaggedTemplateStringExpression } from '../parser/Expression'; -import { BrsString, ValueKind, BrsInvalid, BrsBoolean, RoString, RoArray, RoAssociativeArray, RoSGNode, FunctionParameterExpression } from '../brsTypes'; -import { BrsNumber } from '../brsTypes/BrsNumber'; +import { LiteralExpression, Expression, BinaryExpression, CallExpression, FunctionExpression, NamespacedVariableNameExpression, DottedGetExpression, XmlAttributeGetExpression, IndexedGetExpression, GroupingExpression, EscapedCharCodeLiteralExpression, ArrayLiteralExpression, AALiteralExpression, UnaryExpression, VariableExpression, SourceLiteralExpression, NewExpression, CallfuncExpression, TemplateStringQuasiExpression, TemplateStringExpression, TaggedTemplateStringExpression, FunctionParameterExpression } from '../parser/Expression'; import { BrsFile } from '../files/BrsFile'; import { XmlFile } from '../files/XmlFile'; import { InternalWalkMode } from './visitors'; import { FunctionType } from '../types/FunctionType'; import { File } from '../interfaces'; import { StringType } from '../types/StringType'; +import { BooleanType } from '../types/BooleanType'; +import { InvalidType } from '../types/InvalidType'; +import { LongIntegerType } from '../types/LongIntegerType'; +import { DoubleType } from '../types/DoubleType'; +import { FloatType } from '../types/FloatType'; +import { IntegerType } from '../types/IntegerType'; // File reflection @@ -191,56 +195,48 @@ export function isFunctionParameterExpression(element: Expression | Statement): return element?.constructor.name === 'FunctionParameterExpression'; } -// Value/Type reflection - -export function isInvalid(value: any): value is BrsInvalid { - return value?.kind === ValueKind.Invalid; -} -export function isBoolean(value: any): value is BrsBoolean { - return value?.kind === ValueKind.Boolean; +// BscType reflection +export function isStringType(value: any): value is StringType { + return value?.constructor.name === StringType.name; } -export function isString(value: any): value is BrsString { - return value?.kind === ValueKind.String; +export function isFunctionType(e: any): e is FunctionType { + return e?.constructor.name === FunctionType.name; } -export function isNumber(value: any): value is BrsNumber { - return value && ( - value.kind === ValueKind.Int32 || - value.kind === ValueKind.Int64 || - value.kind === ValueKind.Float || - value.kind === ValueKind.Double - ); +export function isBooleanType(e: any): e is BooleanType { + return e?.constructor.name === BooleanType.name; } -export function isStringType(value: any): value is StringType { - return value?.constructor.name === 'StringType'; +export function isIntegerType(e: any): e is IntegerType { + return e?.constructor.name === IntegerType.name; } - -export function isFunctionType(e: any): e is FunctionType { - return e?.constructor.name === 'FunctionType'; +export function isLongIntegerType(e: any): e is LongIntegerType { + return e?.constructor.name === LongIntegerType.name; } -export function isRoArray(e: any): e is RoArray { - return e?.constructor.name === 'RoArray'; +export function isFloatType(e: any): e is FloatType { + return e?.constructor.name === FloatType.name; } -export function isRoAssociativeArray(e: any): e is RoAssociativeArray { - return e?.constructor.name === 'RoAssociativeArray'; +export function isDoubleType(e: any): e is DoubleType { + return e?.constructor.name === DoubleType.name; } -export function isRoSGNode(e: any): e is RoSGNode { - return e?.constructor.name === 'RoSGNode'; +export function isNumberType(e: any): e is IntegerType | LongIntegerType | FloatType | DoubleType { + return [ + IntegerType.name, + LongIntegerType.name, + FloatType.name, + DoubleType.name + ].includes(e?.constructor.name); } // Literal reflection -export function isLiteralInvalid(e: any): e is LiteralExpression & { value: BrsInvalid } { - return isLiteralExpression(e) && isInvalid(e.value); -} -export function isLiteralBoolean(e: any): e is LiteralExpression & { value: BrsBoolean } { - return isLiteralExpression(e) && isBoolean(e.value); +export function isLiteralInvalid(e: any): e is LiteralExpression & { type: InvalidType } { + return isLiteralExpression(e) && isLiteralInvalid(e.type); } -export function isLiteralString(e: any): e is LiteralExpression & { value: BrsString } { - return isLiteralExpression(e) && isString(e.value); +export function isLiteralBoolean(e: any): e is LiteralExpression & { type: BooleanType } { + return isLiteralExpression(e) && isBooleanType(e.type); } -export function isLiteralNumber(e: any): e is LiteralExpression & { value: BrsNumber } { - return isLiteralExpression(e) && isNumber(e.value); +export function isLiteralString(e: any): e is LiteralExpression & { type: StringType } { + return isLiteralExpression(e) && isStringType(e.type); } -export function isRoString(s: any): s is RoString { - return s.constructor.name === 'RoString'; +export function isLiteralNumber(e: any): e is LiteralExpression & { type: IntegerType | LongIntegerType | FloatType | DoubleType } { + return isLiteralExpression(e) && isNumberType(e.type); } diff --git a/src/astUtils/visitors.spec.ts b/src/astUtils/visitors.spec.ts index 0e409c324..93165f9da 100644 --- a/src/astUtils/visitors.spec.ts +++ b/src/astUtils/visitors.spec.ts @@ -1,5 +1,5 @@ /* eslint-disable no-multi-spaces */ -import { CancellationToken, CancellationTokenSource, Position, Range } from 'vscode-languageserver'; +import { CancellationToken, CancellationTokenSource, Range } from 'vscode-languageserver'; import { expect } from 'chai'; import * as sinon from 'sinon'; import { Program } from '../Program'; @@ -207,7 +207,7 @@ describe('astUtils visitors', () => { Block: blockHandler }); const printStatement = new PrintStatement({ - print: createToken(TokenKind.Print, Position.create(0, 0)) + print: createToken(TokenKind.Print) }, []); const blockStatement = new Block([], Range.create(0, 0, 0, 0)); visitor(printStatement, undefined); @@ -221,16 +221,15 @@ describe('astUtils visitors', () => { describe('Statement editor', () => { it('allows replacing statements', () => { - const pos = Position.create(0, 0); const printStatement1 = new PrintStatement({ - print: createToken(TokenKind.Print, pos) + print: createToken(TokenKind.Print) }, []); const printStatement2 = new PrintStatement({ - print: createToken(TokenKind.Print, pos) + print: createToken(TokenKind.Print) }, []); const block = new Block([ printStatement1, - new ReturnStatement({ return: createToken(TokenKind.Return, pos) }) + new ReturnStatement({ return: createToken(TokenKind.Return) }) ], Range.create(0, 0, 0, 0)); const visitor = createVisitor({ PrintStatement: () => printStatement2 diff --git a/src/brsTypes/Boxing.ts b/src/brsTypes/Boxing.ts deleted file mode 100644 index a3e1316ea..000000000 --- a/src/brsTypes/Boxing.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { BrsComponent } from './components/BrsComponent'; -import { BrsValue } from '.'; - -export interface Boxable { - box(): BrsComponent; -} - -export interface Unboxable { - unbox(): BrsValue; -} diff --git a/src/brsTypes/BrsNumber.ts b/src/brsTypes/BrsNumber.ts deleted file mode 100644 index e2da9a41b..000000000 --- a/src/brsTypes/BrsNumber.ts +++ /dev/null @@ -1,85 +0,0 @@ -import Long from 'long'; -import { BrsValue } from './BrsType'; -import { Int32 } from './Int32'; -import { Int64 } from './Int64'; -import { Float } from './Float'; -import { Double } from './Double'; - -/** The set of operations available on a BrightScript numeric variable. */ -export interface Numeric extends BrsValue { - /** - * Returns the current value this instance represents. - * @returns the current value contained in this instance. - */ - getValue(): number | Long; - - /** - * Adds `rhs` to the current number and returns the result. - * @param rhs The right-hand side value to add to the current value. - * @returns The current value + `rhs`, with precision matching `max(current, rhs)`. - */ - add(rhs: BrsNumber): BrsNumber; - - /** - * Subtracts `rhs` from the current number and returns the result. - * @param rhs The right-hand side value to subtract from the current value. - * @returns The current value - `rhs`, with precision matching `max(current, rhs)`. - */ - subtract(rhs: BrsNumber): BrsNumber; - - /** - * Multiplies the current number by `rhs` and returns the result. - * @param rhs The right-hand side value to multiply the current value by. - * @returns The current value * `rhs`, with precision matching `max(current, rhs)`. - */ - multiply(rhs: BrsNumber): BrsNumber; - - /** - * Divides the current number by `rhs` and returns the result. - * @param rhs The right-hand side value to divide the current value by. - * @returns The current value / `rhs`, with floating-point precision matching `max(current, rhs)`. - */ - divide(rhs: BrsNumber): Float | Double; - - /** - * Modulos the current number by `rhs`. I.e. divides the current number by `rhs` and returns - * the *whole-number remainder* of the result. - * @param rhs The right-hand side value to modulo the current value by. - * @returns The current value MOD `rhs` with 64-bit integer precision if `rhs` is an Int64, - * otherwise 32-bit integer precision. - */ - modulo(rhs: BrsNumber): BrsNumber; - - /** - * Integer-divides the current number by `rhs`. I.e. divides the current number by `rhs` and - * returns the *integral part* of the result. - * @param rhs The right-hand side value to integer-divide the current value by. - * @returns The current value \ `rhs` with 64-bit integer precision if `rhs` is an Int64, - * otherwise 32-bit integer precision. - */ - intDivide(rhs: BrsNumber): Int32 | Int64; - - /** - * Calculates the current value to the power of `exponent`. - * @param exponent The exponent to take the current value to the power of. - * @returns The current value ^ `exponent`, with precision matching `max(current, rhs)`. - */ - pow(exponent: BrsNumber): BrsNumber; - - /** - * Bitwise ANDs the current value with `rhs`. - * @param rhs The right-hand side value to bitwise AND the current value with. - * @returns The current value ANDed with `rhs`. - */ - and(rhs: BrsNumber): BrsNumber; - - /** - * Bitwise ORs the current value with `rhs`. - * @param rhs The right-hand side value to bitwise OR the current value with. - * @returns The current value ORed with `rhs`. - */ - or(rhs: BrsNumber): BrsNumber; -} - -/** The union of all supported BrightScript number types. */ -export type BrsNumber = Int32 | Int64 | Float | Double; diff --git a/src/brsTypes/BrsType.ts b/src/brsTypes/BrsType.ts deleted file mode 100644 index 62643fb24..000000000 --- a/src/brsTypes/BrsType.ts +++ /dev/null @@ -1,304 +0,0 @@ -import { BrsType } from '.'; -import { Boxable } from './Boxing'; -import { RoString } from './components/RoString'; - -/** Set of values supported in BrightScript. */ -export enum ValueKind { - Invalid, - Boolean, - String, - Int32, - Int64, - Float, - Double, - Callable, - Uninitialized, - Dynamic, - Void, - Object -} - -/** - * Converts a `ValueKind` enum member to a human-readable string representation. - * @returns a textual representation of the provided value kind. - */ -export function valueKindToString(kind: ValueKind): string { - switch (kind) { - case ValueKind.Invalid: - return 'Invalid'; - case ValueKind.Boolean: - return 'Boolean'; - case ValueKind.String: - return 'String'; - case ValueKind.Int32: - return 'Integer'; - case ValueKind.Int64: - return 'LongInteger'; - case ValueKind.Float: - return 'Float'; - case ValueKind.Double: - return 'Double'; - case ValueKind.Callable: - return 'Function'; - case ValueKind.Dynamic: - return 'Dynamic'; - case ValueKind.Void: - return 'Void'; - case ValueKind.Uninitialized: - return ''; - case ValueKind.Object: - return 'Object'; - default: - return 'unknown'; - } -} - -/** - * Fetches a `ValueKind` enum member by its string representation. - * @param kind the string representation of a `ValueKind` - * @returns the corresponding `ValueKind` if one exists, otherwise `undefined`. - */ -export function valueKindFromString(kind: string): ValueKind | undefined { - switch (kind.toLowerCase()) { - case 'invalid': - return ValueKind.Invalid; - case 'boolean': - return ValueKind.Boolean; - case 'string': - return ValueKind.String; - case 'integer': - return ValueKind.Int32; - case 'longinteger': - return ValueKind.Int64; - case 'float': - return ValueKind.Float; - case 'double': - return ValueKind.Double; - case 'function': - return ValueKind.Callable; - case 'dynamic': - return ValueKind.Dynamic; - case 'void': - return ValueKind.Void; - case '': - return ValueKind.Uninitialized; - case 'object': - return ValueKind.Object; - default: - return undefined; - } -} - -/** The base for all BrightScript types. */ -export interface BrsValue { - /** - * Type differentiator for all BrightScript values. Used to allow comparisons of `.kind` to - * produce valuable compile-time type inferences. - */ - readonly kind: ValueKind; - - /** - * Converts the current value to a human-readable string. - * @param parent The (optional) BrightScript value that this value is being printed in the context of. - * @returns A human-readable representation of this value. - */ - toString(parent?: BrsType): string; - - /** - * Determines whether or not this value is equal to some `other` value. - * @param other The value to compare this value to. - * @returns `true` if this value is strictly equal to the `other` value, otherwise `false`. - */ - equalTo(other: BrsType): BrsBoolean; -} - -/** The set of operations required for a BrightScript datatype to be compared to another. */ -export interface Comparable { - /** - * Determines whether or not this value is less than some `other` value. - * @param other The value to compare this value to. - * @returns `true` if this value is less than the `other` value, otherwise `false`. - */ - lessThan(other: BrsType): BrsBoolean; - - /** - * Determines whether or not this value is greater than some `other` value. - * @param other The value to compare this value to. - * @returns `true` if this value is greater than the `other` value, otherwise `false`. - */ - greaterThan(other: BrsType): BrsBoolean; -} - -/** Internal representation of a string in BrightScript. */ -export class BrsString implements BrsValue, Comparable, Boxable { - readonly kind = ValueKind.String; - constructor(readonly value: string) { } - - lessThan(other: BrsType): BrsBoolean { - if (other.kind === ValueKind.String) { - return BrsBoolean.from(this.value < other.value); - } else if (other instanceof RoString) { - return this.lessThan(other.unbox()); - } - - return BrsBoolean.False; - } - - greaterThan(other: BrsType): BrsBoolean { - if (other.kind === ValueKind.String) { - return BrsBoolean.from(this.value > other.value); - } else if (other instanceof RoString) { - return this.greaterThan(other.unbox()); - } - - return BrsBoolean.False; - } - - equalTo(other: BrsType): BrsBoolean { - if (other.kind === ValueKind.String) { - return BrsBoolean.from(this.value === other.value); - } else if (other instanceof RoString) { - return this.equalTo(other.unbox()); - } - return BrsBoolean.False; - } - - toString(parent?: BrsType) { - return this.value; - } - - concat(other: BrsString) { - return new BrsString(this.value + other.value); - } - - box() { - return new RoString(this); - } -} - -/** Internal representation of a boolean in BrightScript. */ -export class BrsBoolean implements BrsValue, Comparable { - readonly kind = ValueKind.Boolean; - private constructor(private readonly value: boolean) { } - - toBoolean(): boolean { - return this.value; - } - - static False = new BrsBoolean(false); - static True = new BrsBoolean(true); - static from(value: boolean) { - return value ? BrsBoolean.True : BrsBoolean.False; - } - - lessThan(other: BrsType): BrsBoolean { - // booleans aren't less than anything - // TODO: Validate on a Roku - return BrsBoolean.False; - } - - greaterThan(other: BrsType): BrsBoolean { - // but isn't greater than anything either - // TODO: Validate on a Roku - return BrsBoolean.False; - } - - equalTo(other: BrsType): BrsBoolean { - if (other.kind === ValueKind.Boolean) { - return BrsBoolean.from(this === other); - } - return BrsBoolean.False; - } - - toString(parent?: BrsType) { - return this.value.toString(); - } - - /** - * Returns the boolean AND of this value with another value. - * @param other the other value to AND with this one. - * @returns `BrsBoolean.True` if both this value and the other are true, otherwise - * `BrsBoolean.False`. - */ - and(other: BrsBoolean): BrsBoolean { - return BrsBoolean.from(this.value && other.value); - } - - /** - * Returns the boolean OR of this value with another value. - * @param other the other value to AND with this one. - * @returns `BrsBoolean.True` if either this value or the other are true, otherwise - * `BrsBoolean.False`. - */ - or(other: BrsBoolean): BrsBoolean { - return BrsBoolean.from(this.value || other.value); - } - - /** - * Returns the boolean negation of this value with another value. - * @returns `BrsBoolean.True` if either this value is false, otherwise - * `BrsBoolean.False`. - */ - not(): BrsBoolean { - return BrsBoolean.from(!this.value); - } -} - -/** Internal representation of the BrightScript `invalid` value. */ -export class BrsInvalid implements BrsValue, Comparable { - readonly kind = ValueKind.Invalid; - static Instance = new BrsInvalid(); - - lessThan(other: BrsType): BrsBoolean { - // invalid isn't less than anything - // TODO: Validate on a Roku - return BrsBoolean.False; - } - - greaterThan(other: BrsType): BrsBoolean { - // but isn't greater than anything either - // TODO: Validate on a Roku - return BrsBoolean.False; - } - - equalTo(other: BrsType): BrsBoolean { - if (other.kind === ValueKind.Invalid) { - return BrsBoolean.True; - } - return BrsBoolean.False; - } - - toString(parent?: BrsType) { - return 'invalid'; - } -} - -/** Internal representation of uninitialized BrightScript variables. */ -export class Uninitialized implements BrsValue, Comparable { - readonly kind = ValueKind.Uninitialized; - static Instance = new Uninitialized(); - - lessThan(other: BrsType): BrsBoolean { - // uninitialized values aren't less than anything - return BrsBoolean.False; - } - - greaterThan(other: BrsType): BrsBoolean { - // uninitialized values aren't less than anything - return BrsBoolean.False; - } - - equalTo(other: BrsType): BrsBoolean { - if (other.kind === ValueKind.String) { - // Allow variables to be compared to the string "" to test if they've - // been initialized - return BrsBoolean.from(other.value === this.toString()); - } - - return BrsBoolean.False; - } - - toString(parent?: BrsType) { - return ''; - } -} diff --git a/src/brsTypes/Callable.ts b/src/brsTypes/Callable.ts deleted file mode 100644 index 75c3823a0..000000000 --- a/src/brsTypes/Callable.ts +++ /dev/null @@ -1,322 +0,0 @@ -declare type Interpreter = any; -import * as Brs from '.'; -declare let Scope: any; -import { Identifier, Token } from '../lexer'; -import { SourceNode } from 'source-map'; -import { Range } from 'vscode-languageserver'; -import { TranspileState } from '../parser/TranspileState'; -import { walk, InternalWalkMode, WalkOptions, WalkVisitor } from '../astUtils'; -import { Expression, LiteralExpression } from '../parser/Expression'; -import util from '../util'; - -/** An argument to a BrightScript `function` or `sub`. */ -export interface Argument { - /** Where the argument exists in the parsed source file(s). */ - readonly range: Range; - - /** The argument's name. */ - readonly name: { - text: string; - range: Range; - }; - - /** The type of the argument expected by the BrightScript runtime. */ - readonly type: { - kind: Brs.ValueKind; - range: Range; - }; - - /** The default value to use for the argument if none is provided. */ - readonly defaultValue?: Expression; -} - -/** - * A variant of the `Argument` interface intended for use only when creating standard library - * functions. - */ -export class StdlibArgument implements Argument { - readonly range: Argument['range']; - readonly name: Argument['name']; - readonly type: Argument['type']; - readonly defaultValue: Argument['defaultValue']; - - /** - * Creates an `Argument` without requiring locations to be specified. - * @param name the name of the argument, used for presentation to users - * @param type the type of value accepted at runtime - * @param defaultValue the optional default value to use for this argument if one isn't - * provided at runtime - */ - constructor(name: string, type: Brs.ValueKind, defaultValue?: Brs.BrsType) { - this.range = StdlibArgument.InternalRange; - this.name = { text: name, range: StdlibArgument.InternalRange }; - this.type = { kind: type, range: StdlibArgument.InternalRange }; - if (defaultValue) { - this.defaultValue = new LiteralExpression(defaultValue, StdlibArgument.InternalRange); - } - } - - /** A fake location exists only within the BRS runtime. */ - static InternalRange = util.createRange(-1, -1, -1, -1); -} - -export class FunctionParameterExpression extends Expression { - constructor( - public name: Identifier, - public type: { - kind: Brs.ValueKind; - range: Range; - }, - public typeToken?: Token, - public defaultValue?: Expression, - public asToken?: Token - ) { - super(); - - } - - public get range(): Range { - return { - start: this.name.range.start, - end: this.typeToken ? this.typeToken.range.end : this.name.range.end - }; - } - - public transpile(state: TranspileState) { - let result = [ - //name - new SourceNode(this.name.range.start.line + 1, this.name.range.start.character, state.pathAbsolute, this.name.text) - ] as any[]; - //default value - if (this.defaultValue) { - result.push(' = '); - result.push(this.defaultValue.transpile(state)); - } - //type declaration - if (this.asToken) { - result.push(' '); - result.push(new SourceNode(this.asToken.range.start.line + 1, this.asToken.range.start.character, state.pathAbsolute, 'as')); - result.push(' '); - result.push(new SourceNode(this.typeToken.range.start.line + 1, this.typeToken.range.start.character, state.pathAbsolute, this.typeToken.text)); - } - - return result; - } - - walk(visitor: WalkVisitor, options: WalkOptions) { - // eslint-disable-next-line no-bitwise - if (this.defaultValue && options.walkMode & InternalWalkMode.walkExpressions) { - walk(this, 'defaultValue', visitor, options); - } - } -} - -/** A BrightScript `function` or `sub`'s signature. */ -export interface Signature { - /** The set of arguments a function accepts. */ - readonly args: ReadonlyArray; - /** The type of BrightScript value the function will return. `sub`s must use `ValueKind.Void`. */ - readonly returns: Brs.ValueKind; -} - -/** A BrightScript function signature paired with its implementation. */ -export interface SignatureAndImplementation { - /** A BrightScript function's signature. */ - signature: Signature; - /** The implementation corresponding to `signature`. */ - impl: CallableImplementation; -} - -type SignatureMismatch = AnonymousMismatch | ArgumentMismatch; - -/** A mismatch between a BrightScript function's signature and its received arguments. */ -export interface AnonymousMismatch { - /** The type of mismatch that was received. */ - reason: MismatchReason.TooFewArguments | MismatchReason.TooManyArguments; - /** The number of arguments that was expected. */ - expected: string; - /** The number of arguments that was actually received. */ - received: string; -} - -/** A mismatch between a function argument's expected type and its runtime type. */ -export interface ArgumentMismatch { - /** The type of mismatch that was received. */ - reason: MismatchReason.ArgumentTypeMismatch; - /** The BrightScript type that was expected for argument `argName`. */ - expected: string; - /** The BrightScript type that was actually received. */ - received: string; - /** The name of the argument that had a type mismatch. */ - argName: string; -} - -/** The set of possible reasons why a signature and runtime arguments don't match. */ -export enum MismatchReason { - /** Not enough arguments were provided to satisfy a signature. */ - TooFewArguments, - /** Too many arguments were provided to satisfy a signature. */ - TooManyArguments, - /** An argument's type didn't match the signature's type. */ - ArgumentTypeMismatch, -} - -/** A BrightScript function's signature, paired with a set of detected signature mismatches. */ -export interface SignatureAndMismatches { - /** A BrightScript function's signature. */ - signature: Signature; - /** The set of mismatches between `signature` and the detected mismatches. */ - mismatches: SignatureMismatch[]; -} - -/* - * Note that TypeScript's `--strictFunctionTypes` compiler argument prevents the `args` parameter - * from being typed as `...args: Brs.BrsType[]` here. See - * https://www.stephanboyer.com/post/132/what-are-covariance-and-contravariance for a wonderful - * description of why. - */ -/** The function type required for all concrete Callables to provide. */ -export type CallableImplementation = (interpreter: Interpreter, ...args: any[]) => Brs.BrsType; - -/** A `function` or `sub` (either "native" or implemented in BrightScript) that can be called in a BrightScript file. */ -export class Callable implements Brs.BrsValue { - readonly kind = Brs.ValueKind.Callable; - - /** The name of this function within the BrightScript runtime. */ - readonly name: string | undefined; - - /** The signature of this callable within the BrightScript runtime. */ - readonly signatures: SignatureAndImplementation[]; - - /** - * Calls the function this `Callable` represents with the provided `arg`uments using the - * provided `Interpreter` instance. - * - * @param interpreter the interpreter to execute this callable in. - * @param args the arguments to pass to the callable routine. - * - * @returns the return value of the function, or `invalid` if nothing is explicitly returned. - */ - call(interpreter: Interpreter, ...args: Brs.BrsType[]) { - let satisfiedSignature = this.getFirstSatisfiedSignature(args); - if (satisfiedSignature === null) { - throw new Error( - 'BrightScript function called without first checking for satisfied signatures. ' + - 'Ensure `Callable#getAllSignatureMismatches` is called before `Callable#call`.' - ); - } - - let { signature, impl } = satisfiedSignature; - - let mutableArgs = args.slice(); - - return interpreter.inSubEnv(subInterpreter => { - // first, we need to evaluate all of the parameter default values - // and define them in a new environment - signature.args.forEach((param, index) => { - if (param.defaultValue && mutableArgs[index] === null) { - mutableArgs[index] = subInterpreter.evaluate(param.defaultValue); - } - - subInterpreter.environment.define( - Scope.Function, - param.name.text, - mutableArgs[index] - ); - }); - - // then return whatever the selected implementation would return - return impl(subInterpreter, ...mutableArgs); - }); - } - - /** - * Creates a new BrightScript `function` or `sub`. - * @param name the name this callable should have within the BrightScript runtime. - * @param signatures the signatures and associated (JavaScript) implementations this callable should - * have within the BrightScript runtime. - */ - constructor(name: string | undefined, ...signatures: SignatureAndImplementation[]) { - this.name = name; - this.signatures = signatures; - } - - lessThan(): Brs.BrsBoolean { - return Brs.BrsBoolean.False; - } - - greaterThan(): Brs.BrsBoolean { - return Brs.BrsBoolean.False; - } - - equalTo(other: Brs.BrsType): Brs.BrsBoolean { - return Brs.BrsBoolean.from(this === other); - } - - toString(): string { - if (this.name) { - return `[Function ${this.name}]`; - } else { - return '[anonymous function]'; - } - } - - getName(): string { - return this.name || ''; - } - - getFirstSatisfiedSignature(args: Brs.BrsType[]): SignatureAndImplementation | undefined { - return this.signatures.filter( - sigAndImpl => this.getSignatureMismatches(sigAndImpl.signature, args).length === 0 - )[0]; - } - - getAllSignatureMismatches(args: Brs.BrsType[]): SignatureAndMismatches[] { - return this.signatures.map(sigAndImpl => ({ - signature: sigAndImpl.signature, - mismatches: this.getSignatureMismatches(sigAndImpl.signature, args) - })); - } - - private getSignatureMismatches(sig: Signature, args: Brs.BrsType[]): SignatureMismatch[] { - let reasons: SignatureMismatch[] = []; - let requiredArgCount = sig.args.filter(arg => !arg.defaultValue).length; - - if (args.length < requiredArgCount) { - reasons.push({ - reason: MismatchReason.TooFewArguments, - expected: sig.args.length.toString(), - received: args.length.toString() - }); - } else if (args.length > sig.args.length) { - reasons.push({ - reason: MismatchReason.TooManyArguments, - expected: sig.args.length.toString(), - received: args.length.toString() - }); - } - - sig.args.slice(0, Math.min(sig.args.length, args.length)).forEach((_value, index) => { - let expected = sig.args[index]; - let received = args[index]; - - if ( - expected.type.kind === Brs.ValueKind.Dynamic || - expected.type.kind === Brs.ValueKind.Object - ) { - return; - } - - if (expected.type.kind !== received.kind) { - reasons.push({ - reason: MismatchReason.ArgumentTypeMismatch, - expected: Brs.valueKindToString(expected.type.kind), - received: Brs.valueKindToString(received.kind), - argName: expected.name.text - }); - } - }); - - return reasons; - } -} diff --git a/src/brsTypes/Double.ts b/src/brsTypes/Double.ts deleted file mode 100644 index 6dcc1ef55..000000000 --- a/src/brsTypes/Double.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { BrsType, BrsBoolean } from '.'; -import { ValueKind, Comparable } from './BrsType'; -import { BrsNumber, Numeric } from './BrsNumber'; -import { Int32 } from './Int32'; -import { Int64 } from './Int64'; -import { Float } from './Float'; - -export class Double implements Numeric, Comparable { - readonly kind = ValueKind.Double; - private readonly value: number; - - getValue(): number { - return this.value; - } - - /** - * Creates a new BrightScript double-precision value representing the provided `value`. - * @param value the value to store in the BrightScript double, rounded to 64-bit (double) - * precision. - */ - constructor(value: number) { - this.value = value; - } - - /** - * Creates a new BrightScript double-precision value representing the floating point value - * contained in `asString`. - * @param asString the string representation of the value to store in the BrightScript double. - * Will be rounded to 64-bit (double) precision. - * @returns a BrightScript double value representing `asString`. - */ - static fromString(asString: string): Double { - return new Double(Number.parseFloat(asString)); - } - - add(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int64: - // TODO: Confirm that (double) + (int64) -> (double) - return new Double(this.getValue() + rhs.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Double(this.getValue() + rhs.getValue()); - } - } - - subtract(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int64: - // TODO: Confirm that (double) - (int64) -> (double) - return new Double(this.getValue() - rhs.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Double(this.getValue() - rhs.getValue()); - } - } - - multiply(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int64: - // TODO: Confirm that (double) - (int64) -> (double) - return new Double(this.getValue() * rhs.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Double(this.getValue() * rhs.getValue()); - } - } - - divide(rhs: BrsNumber): Float | Double { - switch (rhs.kind) { - case ValueKind.Int64: - // TODO: Confirm that (double) - (int64) -> (double) - return new Double(this.getValue() / rhs.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Double(this.getValue() / rhs.getValue()); - } - } - - modulo(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Double(this.getValue() % rhs.getValue()); - case ValueKind.Int64: - return new Double(this.getValue() % rhs.getValue().toNumber()); - } - } - - intDivide(rhs: BrsNumber): Int32 | Int64 { - switch (rhs.kind) { - case ValueKind.Int64: - return new Int64(Math.trunc(this.getValue() / rhs.getValue().toNumber())); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Int32(Math.trunc(this.getValue() / rhs.getValue())); - } - } - - pow(exponent: BrsNumber): BrsNumber { - switch (exponent.kind) { - case ValueKind.Int32: - return new Float(this.getValue() ** exponent.getValue()); - case ValueKind.Int64: - return new Int64(this.getValue()).pow(exponent); - case ValueKind.Float: - return new Float(this.getValue() ** exponent.getValue()); - case ValueKind.Double: - return new Double(this.getValue() ** exponent.getValue()); - } - } - - and(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int64: - return new Int64(this.getValue()).and(rhs); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Int32(this.getValue() & rhs.getValue());//eslint-disable-line - } - } - - or(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int64: - return new Int64(this.getValue()).or(rhs); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Int32(this.getValue() | rhs.getValue()); //eslint-disable-line - } - } - - lessThan(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int64: - return BrsBoolean.from(this.getValue() < other.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return BrsBoolean.from(this.getValue() < other.getValue()); - default: - return BrsBoolean.False; - } - } - - greaterThan(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int64: - return BrsBoolean.from(this.getValue() > other.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return BrsBoolean.from(this.getValue() > other.getValue()); - default: - return BrsBoolean.False; - } - } - - equalTo(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int64: - return BrsBoolean.from(this.getValue() === other.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return BrsBoolean.from(this.getValue() === other.getValue()); - default: - return BrsBoolean.False; - } - } - - toString(parent?: BrsType): string { - return this.value.toString(); - } -} diff --git a/src/brsTypes/Float.ts b/src/brsTypes/Float.ts deleted file mode 100644 index 567229b21..000000000 --- a/src/brsTypes/Float.ts +++ /dev/null @@ -1,197 +0,0 @@ -import { BrsType, BrsBoolean } from '.'; -import { ValueKind, Comparable } from './BrsType'; -import { BrsNumber, Numeric } from './BrsNumber'; -import { Int32 } from './Int32'; -import { Double } from './Double'; -import { Int64 } from './Int64'; - -/** - * Number of significant digits represented in an IEEE 32-bit floating point number. - * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays#Typed_array_views - */ -const IEEE_FLOAT_SIGFIGS = 7; - -export class Float implements Numeric, Comparable { - readonly kind = ValueKind.Float; - private readonly value: number; - - getValue(): number { - return this.value; - } - - /** - * Creates a new BrightScript floating-point value representing the provided `value`. - * @param value the value to store in the BrightScript float, rounded to 32-bit floating point - * precision and maintaining only seven significant digits of accuracy. - */ - constructor(value: number) { - this.value = parseFloat(Math.fround(value).toPrecision(IEEE_FLOAT_SIGFIGS)); - } - - /** - * Creates a new BrightScript floating-point value representing the floating point value - * contained in `asString`. - * @param asString the string representation of the value to store in the BrightScript float. - * Will be rounded to 32-bit floating point precision. - * @returns a BrightScript floating-point value representing `asString`. - */ - static fromString(asString: string): Float { - return new Float(Number.parseFloat(asString)); - } - - add(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int64: - // TODO: Confirm that (double) + (int64) -> (double) - return new Float(this.getValue() + rhs.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - return new Float(this.getValue() + rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue() + rhs.getValue()); - } - } - - subtract(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int64: - // TODO: Confirm that (float) - (int64) -> (float) - return new Float(this.getValue() - rhs.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - return new Float(this.getValue() - rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue() - rhs.getValue()); - } - } - - multiply(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int64: - // TODO: Confirm that (float) * (int64) -> (float) - return new Float(this.getValue() * rhs.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - return new Float(this.getValue() * rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue() * rhs.getValue()); - } - } - - divide(rhs: BrsNumber): Float | Double { - switch (rhs.kind) { - case ValueKind.Int64: - // TODO: Confirm that (float) / (int64) -> (float) - return new Float(this.getValue() / rhs.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - return new Float(this.getValue() / rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue() / rhs.getValue()); - } - } - - modulo(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Float: - return new Float(this.getValue() % rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue() % rhs.getValue()); - case ValueKind.Int64: - return new Float(this.getValue() % rhs.getValue().toNumber()); - } - } - - intDivide(rhs: BrsNumber): Int32 | Int64 { - switch (rhs.kind) { - case ValueKind.Int64: - return new Int64(Math.trunc(this.getValue() / rhs.getValue().toNumber())); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Int32(Math.trunc(this.getValue() / rhs.getValue())); - } - } - - pow(exponent: BrsNumber): BrsNumber { - switch (exponent.kind) { - case ValueKind.Int32: - return new Float(this.getValue() ** exponent.getValue()); - case ValueKind.Int64: - return new Float(this.getValue() ** exponent.getValue().toNumber()); - case ValueKind.Float: - return new Float(this.getValue() ** exponent.getValue()); - case ValueKind.Double: - return new Double(this.getValue() ** exponent.getValue()); - } - } - - and(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int64: - return new Int64(this.getValue()).and(rhs); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Int32(this.getValue() & rhs.getValue()); //eslint-disable-line - } - } - - or(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int64: - return new Int64(this.getValue()).or(rhs); - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - return new Int32(this.getValue() | rhs.getValue()); //eslint-disable-line - } - } - - lessThan(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int64: - return BrsBoolean.from(this.getValue() < other.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - return BrsBoolean.from(this.getValue() < other.getValue()); - case ValueKind.Double: - return new Double(this.getValue()).lessThan(other); - default: - return BrsBoolean.False; - } - } - - greaterThan(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int64: - return BrsBoolean.from(this.getValue() > other.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - return BrsBoolean.from(this.getValue() > other.getValue()); - case ValueKind.Double: - return new Double(this.getValue()).greaterThan(other); - default: - return BrsBoolean.False; - } - } - - equalTo(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int64: - return BrsBoolean.from(this.getValue() === other.getValue().toNumber()); - case ValueKind.Int32: - case ValueKind.Float: - return BrsBoolean.from(this.getValue() === other.getValue()); - case ValueKind.Double: - return new Double(this.getValue()).equalTo(other); - default: - return BrsBoolean.False; - } - } - - toString(parent?: BrsType): string { - return this.value.toString(); - } -} diff --git a/src/brsTypes/Int32.ts b/src/brsTypes/Int32.ts deleted file mode 100644 index 31096c02c..000000000 --- a/src/brsTypes/Int32.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { ValueKind, Comparable, BrsBoolean } from './BrsType'; -import { BrsNumber, Numeric } from './BrsNumber'; -import { BrsType } from '.'; -import { Float } from './Float'; -import { Double } from './Double'; -import { Int64 } from './Int64'; - -export class Int32 implements Numeric, Comparable { - readonly kind = ValueKind.Int32; - private readonly value: number; - - getValue(): number { - return this.value; - } - - /** - * Creates a new BrightScript 32-bit integer value representing the provided `value`. - * @param value the value to store in the BrightScript number, rounded to the nearest 32-bit - * integer. - */ - constructor(initialValue: number) { - this.value = Math.round(initialValue); - } - - /** - * Creates a new BrightScript 32-bit integer value representing the integer contained in - * `asString`. - * @param asString the string representation of the value to store in the BrightScript 32-bit - * int. Will be rounded to the nearest 32-bit integer. - * @returns a BrightScript 32-bit integer value representing `asString`. - */ - static fromString(asString: string): Int32 { - if (asString.toLowerCase().startsWith('&h')) { - asString = asString.slice(2); // remove "&h" from the string representation - return new Int32(Number.parseInt(asString, 16)); - } - return new Int32(Number.parseFloat(asString)); - } - - add(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - return new Int32(this.getValue() + rhs.getValue()); - case ValueKind.Int64: - return new Int64(rhs.getValue().add(this.getValue())); - case ValueKind.Float: - return new Float(this.getValue() + rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue() + rhs.getValue()); - } - } - - subtract(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - return new Int32(this.getValue() - rhs.getValue()); - case ValueKind.Int64: - return new Int64(this.getValue()).subtract(rhs); - case ValueKind.Float: - return new Float(this.getValue() - rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue() - rhs.getValue()); - } - } - - multiply(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - return new Int32(this.getValue() * rhs.getValue()); - case ValueKind.Int64: - return new Int64(rhs.getValue().multiply(this.getValue())); - case ValueKind.Float: - return new Float(this.getValue() * rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue() * rhs.getValue()); - } - } - - divide(rhs: BrsNumber): Float | Double { - switch (rhs.kind) { - case ValueKind.Int32: - return new Float(this.getValue() / rhs.getValue()); - case ValueKind.Int64: - return new Float(this.getValue() / rhs.getValue().toNumber()); - case ValueKind.Float: - return new Float(this.getValue() / rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue() / rhs.getValue()); - } - } - - modulo(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - return new Int32(this.getValue() % rhs.getValue()); - case ValueKind.Float: - return new Float(this.getValue() % rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue() % rhs.getValue()); - case ValueKind.Int64: - return new Int64(this.getValue()).modulo(rhs); - } - } - - intDivide(rhs: BrsNumber): Int32 | Int64 { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Float: - case ValueKind.Double: - // TODO: Is 32-bit precision enough here? - return new Int32(Math.trunc(this.getValue() / rhs.getValue())); - case ValueKind.Int64: - return new Int64(Math.trunc(this.getValue() / rhs.getValue().toNumber())); - } - } - - pow(exponent: BrsNumber): BrsNumber { - switch (exponent.kind) { - case ValueKind.Int32: - return new Float(this.getValue() ** exponent.getValue()); - case ValueKind.Int64: - return new Int64(this.getValue()).pow(exponent); - case ValueKind.Float: - return new Float(this.getValue() ** exponent.getValue()); - case ValueKind.Double: - return new Double(this.getValue() ** exponent.getValue()); - } - } - - and(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - return new Int32(this.getValue() & rhs.getValue());//eslint-disable-line - case ValueKind.Int64: - return new Int64(this.getValue()).and(rhs); - case ValueKind.Float: - return new Int32(this.getValue() & rhs.getValue());//eslint-disable-line - case ValueKind.Double: - return new Int32(this.getValue() & rhs.getValue());//eslint-disable-line - } - } - - or(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - return new Int32(this.getValue() | rhs.getValue());//eslint-disable-line - case ValueKind.Int64: - return new Int64(this.getValue()).or(rhs); - case ValueKind.Float: - return new Int32(this.getValue() | rhs.getValue());//eslint-disable-line - case ValueKind.Double: - return new Int32(this.getValue() | rhs.getValue());//eslint-disable-line - } - } - - lessThan(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int32: - return BrsBoolean.from(this.getValue() < other.getValue()); - case ValueKind.Int64: - return new Int64(this.getValue()).lessThan(other); - case ValueKind.Float: - return new Float(this.getValue()).lessThan(other); - case ValueKind.Double: - return new Double(this.getValue()).lessThan(other); - default: - return BrsBoolean.False; - } - } - - greaterThan(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int32: - return BrsBoolean.from(this.getValue() > other.getValue()); - case ValueKind.Int64: - return new Int64(this.getValue()).greaterThan(other); - case ValueKind.Float: - return new Float(this.getValue()).greaterThan(other); - case ValueKind.Double: - return new Double(this.getValue()).greaterThan(other); - default: - return BrsBoolean.False; - } - } - - equalTo(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int32: - return BrsBoolean.from(this.getValue() === other.getValue()); - case ValueKind.Int64: - return new Int64(this.getValue()).equalTo(other); - case ValueKind.Float: - return new Float(this.getValue()).equalTo(other); - case ValueKind.Double: - return new Double(this.getValue()).equalTo(other); - default: - return BrsBoolean.False; - } - } - - toString(parent?: BrsType): string { - return this.value.toString(); - } -} diff --git a/src/brsTypes/Int64.ts b/src/brsTypes/Int64.ts deleted file mode 100644 index fda03801b..000000000 --- a/src/brsTypes/Int64.ts +++ /dev/null @@ -1,211 +0,0 @@ -import * as Long from 'long'; - -import { BrsType, BrsBoolean } from '.'; -import { BrsNumber, Numeric } from './BrsNumber'; -import { ValueKind, Comparable } from './BrsType'; -import { Float } from './Float'; -import { Double } from './Double'; - -export class Int64 implements Numeric, Comparable { - readonly kind = ValueKind.Int64; - private readonly value: Long; - - getValue(): Long { - return this.value; - } - - /** - * Creates a new BrightScript 64-bit integer value representing the provided `value`. - * @param value the value to store in the BrightScript integer. - */ - constructor(value: number | Long) { - if (value instanceof Long) { - this.value = value; - } else { - this.value = Long.fromNumber(Math.round(value)); - } - } - - /** - * Creates a new BrightScript 64-bit integer value representing the integer contained in - * `asString`. - * @param asString the string representation of the value to store in the BrightScript 64-bit - * int. Will be rounded to the nearest 64-bit integer. - * @returns a BrightScript 64-bit integer value representing `asString`. - */ - static fromString(asString: string): Int64 { - let radix = 10; - - if (asString.toLowerCase().startsWith('&h')) { - radix = 16; // it's a hex literal! - asString = asString.slice(2); // remove "&h" from the string representation - } - - let i64 = new Int64(Long.fromString(asString, undefined, radix)); - const decimalLocation = asString.indexOf('.'); - if (decimalLocation > -1 && decimalLocation + 1 < asString.length) { - // Long.fromString truncates to integers instead of rounding, so manually add one to - // compensate if necessary - if (asString[decimalLocation + 1] >= '5' && asString[decimalLocation + 1] <= '9') { - i64 = new Int64(i64.getValue().add(Long.ONE)); - } - } - return i64; - } - - add(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - return new Int64(this.getValue().add(rhs.getValue())); - case ValueKind.Float: - return new Float(this.getValue().toNumber() + rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue().toNumber() + rhs.getValue()); - } - } - - subtract(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - return new Int64(this.getValue().subtract(rhs.getValue())); - case ValueKind.Float: - return new Float(this.getValue().toNumber() - rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue().toNumber() - rhs.getValue()); - } - } - - multiply(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - return new Int64(this.getValue().multiply(rhs.getValue())); - case ValueKind.Float: - return new Float(this.getValue().toNumber() * rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue().toNumber() * rhs.getValue()); - } - } - - divide(rhs: BrsNumber): Float | Double { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - return new Float( - this.getValue() - .divide(rhs.getValue()) - .toNumber() - ); - case ValueKind.Float: - return new Float(this.getValue().toNumber() / rhs.getValue()); - case ValueKind.Double: - return new Double(this.getValue().toNumber() / rhs.getValue()); - } - } - - modulo(rhs: BrsNumber): Int64 { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - return new Int64(this.getValue().modulo(rhs.getValue())); - case ValueKind.Float: - return new Int64(this.getValue().toNumber() % rhs.getValue()); - case ValueKind.Double: - return new Int64(this.getValue().toNumber() % rhs.getValue()); - } - } - - intDivide(rhs: BrsNumber): Int64 { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - return new Int64(this.getValue().divide(rhs.getValue())); - case ValueKind.Float: - case ValueKind.Double: - return new Int64(Math.floor(this.getValue().toNumber() / rhs.getValue())); - } - } - - pow(exponent: BrsNumber): BrsNumber { - switch (exponent.kind) { - case ValueKind.Int32: - return new Int64(this.getValue().toNumber() ** exponent.getValue()); - case ValueKind.Float: - return new Float(this.getValue().toNumber() ** exponent.getValue()); - case ValueKind.Double: - return new Double(this.getValue().toNumber() ** exponent.getValue()); - case ValueKind.Int64: - return new Int64( - this.getValue().toNumber() ** exponent.getValue().toNumber() - ); - } - } - - and(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - case ValueKind.Float: - case ValueKind.Double: - return new Int64(this.getValue().and(rhs.getValue())); - } - } - - or(rhs: BrsNumber): BrsNumber { - switch (rhs.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - case ValueKind.Float: - case ValueKind.Double: - return new Int64(this.getValue().or(rhs.getValue())); - } - } - - lessThan(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - return BrsBoolean.from(this.getValue().lessThan(other.getValue())); - case ValueKind.Float: - return new Float(this.getValue().toNumber()).lessThan(other); - case ValueKind.Double: - return new Double(this.getValue().toNumber()).lessThan(other); - default: - return BrsBoolean.False; - } - } - - greaterThan(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - return BrsBoolean.from(this.getValue().greaterThan(other.getValue())); - case ValueKind.Float: - return new Float(this.getValue().toNumber()).greaterThan(other); - case ValueKind.Double: - return new Double(this.getValue().toNumber()).greaterThan(other); - default: - return BrsBoolean.False; - } - } - - equalTo(other: BrsType): BrsBoolean { - switch (other.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - return BrsBoolean.from(this.getValue().equals(other.getValue())); - case ValueKind.Float: - return new Float(this.getValue().toNumber()).equalTo(other); - case ValueKind.Double: - return new Double(this.getValue().toNumber()).equalTo(other); - default: - return BrsBoolean.False; - } - } - - toString(parent?: BrsType): string { - return this.value.toString(); - } -} diff --git a/src/brsTypes/components/BrsComponent.ts b/src/brsTypes/components/BrsComponent.ts deleted file mode 100644 index b52e77280..000000000 --- a/src/brsTypes/components/BrsComponent.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { BrsType } from '..'; -import { BrsInvalid } from '../BrsType'; -import { Callable } from '../Callable'; - -export class BrsComponent { - private methods: Map = new Map(); - private readonly componentName: string; - - readonly interfaces: Set; - - constructor(name: string, interfaces: string[] = []) { - this.componentName = name; - this.interfaces = new Set(interfaces); - } - - /** - * Returns the name of the component, used to create instances via `createObject`. - * @returns the name of this component. - */ - getComponentName(): string { - return this.componentName; - } - - protected registerMethods(methods: Callable[]) { - this.methods = new Map( - methods.map(m => [(m.name || '').toLowerCase(), m] as [string, Callable]) - ); - } - - getMethod(index: string): Callable | undefined { - return this.methods.get(index.toLowerCase()); - } -} - -/** Represents a BrightScript component that has elements that can be iterated across. */ -export interface BrsIterable { - /** - * Returns the set of iterable elements contained in this component. - * @returns an array of elements contained in this component. - */ - getElements(): ReadonlyArray; - - /** - * Retrieves an element from this component at the provided `index`. - * @param index the index in this component from which to retrieve the desired element. - * @returns the element at `index` if one exists, otherwise throws an Error. - */ - get(index: BrsType): BrsType; - - set(index: BrsType, value: BrsType): BrsInvalid; -} diff --git a/src/brsTypes/components/BrsObjects.ts b/src/brsTypes/components/BrsObjects.ts deleted file mode 100644 index 0c7a6171e..000000000 --- a/src/brsTypes/components/BrsObjects.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { RoAssociativeArray } from './RoAssociativeArray'; -import { RoArray } from './RoArray'; -import { Timespan } from './Timespan'; -import { createNodeByType } from './RoSGNode'; -import { RoRegex } from './RoRegex'; -import { BrsString } from '../BrsType'; -import { RoString } from './RoString'; - -/** Map containing a list of brightscript components that can be created. */ -export const BrsObjects = new Map([ - ['roassociativearray', () => new RoAssociativeArray([])], - ['roarray', () => new RoArray([])], - ['rotimespan', () => new Timespan()], - ['rosgnode', (nodeType: BrsString) => createNodeByType(nodeType)], - ['roregex', (expression: BrsString, flags: BrsString) => new RoRegex(expression, flags)], - ['rostring', (literal: BrsString) => new RoString(literal)] -]); diff --git a/src/brsTypes/components/RoArray.ts b/src/brsTypes/components/RoArray.ts deleted file mode 100644 index 02366f355..000000000 --- a/src/brsTypes/components/RoArray.ts +++ /dev/null @@ -1,183 +0,0 @@ -import { BrsValue, ValueKind, BrsBoolean, BrsInvalid } from '../BrsType'; -import { BrsType } from '..'; -import { BrsComponent, BrsIterable } from './BrsComponent'; -import { Callable, StdlibArgument } from '../Callable'; -declare type Interpreter = any; -import { Int32 } from '../Int32'; - -export class RoArray extends BrsComponent implements BrsValue, BrsIterable { - readonly kind = ValueKind.Object; - private elements: BrsType[]; - - constructor(elements: BrsType[]) { - super('roArray'); - this.elements = elements; - this.registerMethods([ - this.peek, - this.pop, - this.push, - this.shift, - this.unshift, - this.delete, - this.count, - this.clear, - this.append - ]); - } - - toString(parent?: BrsType): string { - if (parent) { - return ''; - } - - return [ - ' =', - '[', - ...this.elements.map((el: BrsValue) => ` ${el.toString(this)}`), - ']' - ].join('\n'); - } - - equalTo(other: BrsType) { - return BrsBoolean.False; - } - - getValue() { - return this.elements; - } - - getElements() { - return this.elements.slice(); - } - - get(index: BrsType) { - switch (index.kind) { - case ValueKind.Int32: - return this.getElements()[index.getValue()] || BrsInvalid.Instance; - case ValueKind.String: - return this.getMethod(index.value) || BrsInvalid.Instance; - default: - throw new Error( - 'Array indexes must be 32-bit integers, or method names must be strings' - ); - } - } - - set(index: BrsType, value: BrsType) { - if (index.kind !== ValueKind.Int32) { - throw new Error('Array indexes must be 32-bit integers'); - } - - this.elements[index.getValue()] = value; - - return BrsInvalid.Instance; - } - - private peek = new Callable('peek', { - signature: { - args: [], - returns: ValueKind.Dynamic - }, - impl: (interpreter: Interpreter) => { - return this.elements[this.elements.length - 1] || BrsInvalid.Instance; - } - }); - - private pop = new Callable('pop', { - signature: { - args: [], - returns: ValueKind.Dynamic - }, - impl: (interpreter: Interpreter) => { - return this.elements.pop() || BrsInvalid.Instance; - } - }); - - private push = new Callable('push', { - signature: { - args: [new StdlibArgument('talue', ValueKind.Dynamic)], - returns: ValueKind.Void - }, - impl: (interpreter: Interpreter, tvalue: BrsType) => { - this.elements.push(tvalue); - return BrsInvalid.Instance; - } - }); - - private shift = new Callable('shift', { - signature: { - args: [], - returns: ValueKind.Dynamic - }, - impl: (interpreter: Interpreter) => { - return this.elements.shift() || BrsInvalid.Instance; - } - }); - - private unshift = new Callable('unshift', { - signature: { - args: [new StdlibArgument('tvalue', ValueKind.Dynamic)], - returns: ValueKind.Void - }, - impl: (interpreter: Interpreter, tvalue: BrsType) => { - this.elements.unshift(tvalue); - return BrsInvalid.Instance; - } - }); - - private delete = new Callable('delete', { - signature: { - args: [new StdlibArgument('index', ValueKind.Int32)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, index: Int32) => { - if (index.lessThan(new Int32(0)).toBoolean()) { - return BrsBoolean.False; - } - - let deleted = this.elements.splice(index.getValue(), 1); - return BrsBoolean.from(deleted.length > 0); - } - }); - - private count = new Callable('count', { - signature: { - args: [], - returns: ValueKind.Int32 - }, - impl: (interpreter: Interpreter) => { - return new Int32(this.elements.length); - } - }); - - private clear = new Callable('clear', { - signature: { - args: [], - returns: ValueKind.Void - }, - impl: (interpreter: Interpreter) => { - this.elements = []; - return BrsInvalid.Instance; - } - }); - - private append = new Callable('append', { - signature: { - args: [new StdlibArgument('array', ValueKind.Object)], - returns: ValueKind.Void - }, - impl: (interpreter: Interpreter, array: BrsComponent) => { - if (!(array instanceof RoArray)) { - // TODO: validate against RBI - return BrsInvalid.Instance; - } - - this.elements = [ - ...this.elements, - ...array.elements.filter(element => !!element) // don't copy "holes" where no value exists - ]; - - return BrsInvalid.Instance; - } - }); -} diff --git a/src/brsTypes/components/RoAssociativeArray.ts b/src/brsTypes/components/RoAssociativeArray.ts deleted file mode 100644 index e0f5e03ba..000000000 --- a/src/brsTypes/components/RoAssociativeArray.ts +++ /dev/null @@ -1,219 +0,0 @@ -import { BrsValue, ValueKind, BrsString, BrsBoolean, BrsInvalid } from '../BrsType'; -import { BrsComponent, BrsIterable } from './BrsComponent'; -import { BrsType } from '..'; -import { Callable, StdlibArgument } from '../Callable'; -declare type Interpreter = any; -import { Int32 } from '../Int32'; -import { RoArray } from './RoArray'; - -/** A member of an `AssociativeArray` in BrightScript. */ -export interface AAMember { - /** The member's name. */ - name: BrsString; - /** The value associated with `name`. */ - value: BrsType; -} - -export class RoAssociativeArray extends BrsComponent implements BrsValue, BrsIterable { - readonly kind = ValueKind.Object; - elements = new Map(); - - constructor(elements: AAMember[]) { - super('roAssociativeArray'); - elements.forEach(member => this.elements.set(member.name.value.toLowerCase(), member.value) - ); - - this.registerMethods([ - this.clear, - this.delete, - this.addreplace, - this.count, - this.doesexist, - this.append, - this.keys, - this.items, - this.lookup - ]); - } - - toString(parent?: BrsType): string { - if (parent) { - return ''; - } - - return [ - ' =', - '{', - ...Array.from(this.elements.entries()).map( - ([key, value]) => ` ${key}: ${(value as any).toString(this)}` - ), - '}' - ].join('\n'); - } - - equalTo() { - return BrsBoolean.False; - } - - getValue() { - return this.elements; - } - - getElements() { - return Array.from(this.elements.keys()) - .sort() - .map(key => new BrsString(key)); - } - - getValues() { - return Array.from(this.elements.values()) - .sort() - .map((value: BrsType) => value); - } - - get(index: BrsType) { - if (index.kind !== ValueKind.String) { - throw new Error('Associative array indexes must be strings'); - } - - // TODO: this works for now, in that a property with the same name as a method essentially - // overwrites the method. The only reason this doesn't work is that getting a method from an - // associative array and _not_ calling it returns `invalid`, but calling it returns the - // function itself. I'm not entirely sure why yet, but it's gotta have something to do with - // how methods are implemented within RBI. - // - // Are they stored separately from elements, like they are here? Or does - // `Interpreter#visitCall` need to check for `invalid` in its callable, then try to find a - // method with the desired name separately? That last bit would work but it's pretty gross. - // That'd allow roArrays to have methods with the methods not accessible via `arr["count"]`. - // Same with RoAssociativeArrays I guess. - return ( - this.elements.get(index.value.toLowerCase()) || - this.getMethod(index.value) || - BrsInvalid.Instance - ); - } - - set(index: BrsType, value: BrsType) { - if (index.kind !== ValueKind.String) { - throw new Error('Associative array indexes must be strings'); - } - this.elements.set(index.value.toLowerCase(), value); - return BrsInvalid.Instance; - } - - /** Removes all elements from the associative array */ - private clear = new Callable('clear', { - signature: { - args: [], - returns: ValueKind.Void - }, - impl: (interpreter: Interpreter) => { - this.elements.clear(); - return BrsInvalid.Instance; - } - }); - - /** Removes a given item from the associative array */ - private delete = new Callable('delete', { - signature: { - args: [new StdlibArgument('str', ValueKind.String)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, str: BrsString) => { - let deleted = this.elements.delete(str.value); - return BrsBoolean.from(deleted); - } - }); - - /** Given a key and value, adds an item to the associative array if it doesn't exist - * Or replaces the value of a key that already exists in the associative array - */ - private addreplace = new Callable('addreplace', { - signature: { - args: [ - new StdlibArgument('key', ValueKind.String), - new StdlibArgument('value', ValueKind.Dynamic) - ], - returns: ValueKind.Void - }, - impl: (interpreter: Interpreter, key: BrsString, value: BrsType) => { - this.set(key, value); - return BrsInvalid.Instance; - } - }); - - /** Returns the number of items in the associative array */ - private count = new Callable('count', { - signature: { - args: [], - returns: ValueKind.Int32 - }, - impl: (interpreter: Interpreter) => { - return new Int32(this.elements.size); - } - }); - - /** Returns a boolean indicating whether or not a given key exists in the associative array */ - private doesexist = new Callable('doesexist', { - signature: { - args: [new StdlibArgument('str', ValueKind.String)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, str: BrsString) => { - return this.get(str) !== BrsInvalid.Instance ? BrsBoolean.True : BrsBoolean.False; - } - }); - - /** Appends a new associative array to another. If two keys are the same, the value of the original AA is replaced with the new one. */ - private append = new Callable('append', { - signature: { - args: [new StdlibArgument('obj', ValueKind.Object)], - returns: ValueKind.Void - }, - impl: (interpreter: Interpreter, obj: BrsType) => { - if (!(obj instanceof RoAssociativeArray)) { - // TODO: validate against RBI - return BrsInvalid.Instance; - } - - this.elements = new Map([...this.elements, ...obj.elements]); - - return BrsInvalid.Instance; - } - }); - - /** Returns an array of keys from the associative array in lexicographical order */ - private keys = new Callable('keys', { - signature: { - args: [], - returns: ValueKind.Object - }, - impl: (interpreter: Interpreter) => { - return new RoArray(this.getElements()); - } - }); - - /** Returns an array of values from the associative array in lexicographical order */ - private items = new Callable('items', { - signature: { - args: [], - returns: ValueKind.Object - }, - impl: (interpreter: Interpreter) => { - return new RoArray(this.getValues()); - } - }); - - /** Given a key, returns the value associated with that key. This method is case insensitive. */ - private lookup = new Callable('lookup', { - signature: { - args: [new StdlibArgument('key', ValueKind.String)], - returns: ValueKind.Dynamic - }, - impl: (interpreter: Interpreter, key: BrsString) => { - let lKey = key.value.toLowerCase(); - return this.get(new BrsString(lKey)); - } - }); -} diff --git a/src/brsTypes/components/RoRegex.ts b/src/brsTypes/components/RoRegex.ts deleted file mode 100644 index 84d51ec90..000000000 --- a/src/brsTypes/components/RoRegex.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { BrsBoolean, BrsString, BrsValue, ValueKind } from '../BrsType'; -import { BrsComponent } from './BrsComponent'; -import { BrsType } from '..'; -import { Callable, StdlibArgument } from '../Callable'; -declare type Interpreter = any; -import { RoArray } from './RoArray'; - -export class RoRegex extends BrsComponent implements BrsValue { - readonly kind = ValueKind.Object; - readonly supportedFlags = 'ims'; - private jsRegex: RegExp; - - constructor(expression: BrsString, flags = new BrsString('')) { - super('roRegex'); - this.jsRegex = new RegExp(expression.value, this.parseFlags(flags.value)); - - this.registerMethods([ - this.isMatch, - this.match, - this.replace, - this.replaceAll, - this.split, - this.matchAll - ]); - } - - toString(parent?: BrsType) { - return ''; - } - - equalTo(other: BrsType) { - return BrsBoolean.False; - } - - /** - * Checks and parses the flags to avoid passing flags - * that are not supported - * @param inputFlags Flags passed to constructor - * @returns parsed flags - */ - private parseFlags(inputFlags: string): string { - let parsedFlags = ''; - if (inputFlags.length === 0) { - return parsedFlags; - } - - for (const flag of inputFlags) { - if (flag === 'x') { - console.warn('\'x\' flag is not implemented yet, ignoring flag.'); - } else if (!this.supportedFlags.includes(flag)) { - throw new Error(`${flag} is not supported.`); - } else { - parsedFlags += flag; - } - } - - return parsedFlags; - } - - /** - * Transforms positional pattern replacements to javascript syntax - * by replacing backslashes with dollar symbols - * @param pattern Pattern to replace - * @returns Replaced string - */ - private parseReplacementPattern(pattern: string): string { - return pattern.replace(/\\/g, '$'); - } - - /** Returns whether the string matched the regex or not */ - private isMatch = new Callable('ismatch', { - signature: { - args: [new StdlibArgument('str', ValueKind.String)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, str: BrsString) => { - return BrsBoolean.from(this.jsRegex.test(str.value)); - } - }); - - /** Returns an array of matches */ - private match = new Callable('match', { - signature: { - args: [new StdlibArgument('str', ValueKind.String)], - returns: ValueKind.Object - }, - impl: (interpreter: Interpreter, str: BrsString) => { - const result = this.jsRegex.exec(str.value); - let arr: BrsString[] = []; - if (result !== null) { - arr = result.map(match => new BrsString(match || '')); - } - - return new RoArray(arr); - } - }); - - /** Returns a new string with first match replaced */ - private replace = new Callable('replace', { - signature: { - args: [ - new StdlibArgument('str', ValueKind.String), - new StdlibArgument('replacement', ValueKind.String) - ], - returns: ValueKind.String - }, - impl: (interpreter: Interpreter, str: BrsString, replacement: BrsString) => { - let replacementPattern = this.parseReplacementPattern(replacement.value); - const newStr = this.jsRegex[Symbol.replace](str.value, replacementPattern); - return new BrsString(newStr); - } - }); - - /** Returns a new string with all matches replaced */ - private replaceAll = new Callable('replaceall', { - signature: { - args: [ - new StdlibArgument('str', ValueKind.String), - new StdlibArgument('replacement', ValueKind.String) - ], - returns: ValueKind.String - }, - impl: (interpreter: Interpreter, str: BrsString, replacement: BrsString) => { - const source = this.jsRegex.source; - const flags = this.jsRegex.flags + 'g'; - this.jsRegex = new RegExp(source, flags); - const newStr = this.jsRegex[Symbol.replace](str.value, replacement.value); - - return new BrsString(newStr); - } - }); - - /** Returns an array of strings split by match */ - private split = new Callable('split', { - signature: { - args: [new StdlibArgument('str', ValueKind.String)], - returns: ValueKind.Object - }, - impl: (interpreter: Interpreter, str: BrsString) => { - let items = this.jsRegex[Symbol.split](str.value); - let brsItems = items.map(item => new BrsString(item)); - return new RoArray(brsItems); - } - }); - - /** Returns an array of array with all matches found */ - private matchAll = new Callable('matchall', { - signature: { - args: [new StdlibArgument('str', ValueKind.String)], - returns: ValueKind.Object - }, - impl: (interpreter: Interpreter, str: BrsString) => { - const source = this.jsRegex.source; - const flags = this.jsRegex.flags + 'g'; - this.jsRegex = new RegExp(source, flags); - let arr = []; - let matches: string[] | null; - - while ((matches = this.jsRegex.exec(str.value)) !== null) { - let item = new BrsString(matches[0] || ''); - arr.push(new RoArray([item])); - } - return new RoArray(arr); - } - }); -} diff --git a/src/brsTypes/components/RoSGNode.ts b/src/brsTypes/components/RoSGNode.ts deleted file mode 100644 index e97436e33..000000000 --- a/src/brsTypes/components/RoSGNode.ts +++ /dev/null @@ -1,733 +0,0 @@ -import { BrsValue, ValueKind, BrsString, BrsInvalid, BrsBoolean, Uninitialized, valueKindToString } from '../BrsType'; -import { BrsComponent, BrsIterable } from './BrsComponent'; -import { BrsType } from '..'; -import { Callable, StdlibArgument } from '../Callable'; -declare type Interpreter = any; -import { Int32 } from '../Int32'; -import { AAMember, RoAssociativeArray } from './RoAssociativeArray'; -import { RoArray } from './RoArray'; -import { Float } from '../Float'; - -class Field { - private type: string; - private value: BrsType; - private observers: string[] = []; - - constructor(value: BrsType, private alwaysNotify: boolean) { - this.type = valueKindToString(value.kind); - this.value = value; - } - - toString(parent?: BrsType): string { - return this.value.toString(parent); - } - - getType(): string { - return this.type; - } - - getValue(): BrsType { - return this.value; - } - - setValue(value: BrsType) { - // This is where the Callbacks are called - if (this.alwaysNotify || this.value !== value) { - this.executeCallbacks(); - } - this.value = value; - } - - addObserver(functionName: BrsString) { - this.observers.push(functionName.value); - } - - private executeCallbacks() { } -} - -export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable { - readonly kind = ValueKind.Object; - private fields = new Map(); - private children: RoSGNode[] = []; - private parent: RoSGNode | BrsInvalid = BrsInvalid.Instance; - readonly builtInFields = [ - { name: 'change', type: 'roAssociativeArray' }, - { name: 'focusable', type: 'boolean' }, - { name: 'focusedChild', type: 'dynamic' }, - { name: 'id', type: 'string' } - ]; - - constructor(members: AAMember[], readonly type: string = 'Node') { - super('roSGNode'); - - // All nodes start have some built-in fields when created - this.builtInFields.forEach(field => { - this.fields.set( - field.name.toLowerCase(), - new Field(this.getDefaultValue(field.type), false) - ); - }); - - members.forEach(member => this.fields.set(member.name.value.toLowerCase(), new Field(member.value, false)) - ); - - this.registerMethods([ - // ifAssociativeArray methods - this.clear, - this.delete, - this.addreplace, - this.count, - this.doesexist, - this.append, - this.keys, - this.items, - this.lookup, - //ifSGNodeField methods - this.addfield, - this.addfields, - this.getfield, - this.observefield, - this.removefield, - this.setfield, - this.setfields, - this.update, - // ifSGNodeChildren methods - this.appendchild, - this.getchildcount, - this.getchildren, - this.removechild, - this.getparent, - this.createchild, - // ifSGNodeFocus methods - this.hasfocus, - this.setfocus, - this.isinfocuschain, - //ifSGNodeDict - this.findnode - ]); - } - - toString(parent?: BrsType): string { - let componentName = 'roSGNode:' + this.type; - - if (parent) { - return ``; - } - - return [ - ` =`, - '{', - ...Array.from(this.fields.entries()).map( - ([key, value]) => ` ${key}: ${value.toString(this)}` - ), - '}' - ].join('\n'); - } - - equalTo(other: BrsType) { - // SceneGraph nodes are never equal to anything - return BrsBoolean.False; - } - - getElements() { - return Array.from(this.fields.keys()) - .sort() - .map(key => new BrsString(key)); - } - - getValues() { - return Array.from(this.fields.values()) - .sort() - .map((field: Field) => field.getValue()); - } - - getFields() { - return this.fields; - } - - get(index: BrsType) { - if (index.kind !== ValueKind.String) { - throw new Error('RoSGNode indexes must be strings'); - } - - // TODO: this works for now, in that a property with the same name as a method essentially - // overwrites the method. The only reason this doesn't work is that getting a method from an - // associative array and _not_ calling it returns `invalid`, but calling it returns the - // function itself. I'm not entirely sure why yet, but it's gotta have something to do with - // how methods are implemented within RBI. - // - // Are they stored separately from elements, like they are here? Or does - // `Interpreter#visitCall` need to check for `invalid` in its callable, then try to find a - // method with the desired name separately? That last bit would work but it's pretty gross. - // That'd allow roArrays to have methods with the methods not accessible via `arr["count"]`. - // Same with RoAssociativeArrays I guess. - let field = this.fields.get(index.value.toLowerCase()); - if (field) { - return field.getValue(); - } - return this.getMethod(index.value) || BrsInvalid.Instance; - } - - set(index: BrsType, value: BrsType, alwaysNotify = false) { - if (index.kind !== ValueKind.String) { - throw new Error('RoSGNode indexes must be strings'); - } - let mapKey = index.value.toLowerCase(); - let field = this.fields.get(mapKey); - let valueType = valueKindToString(value.kind); - - if (!field) { - field = new Field(value, alwaysNotify); - } else if (field.getType() === valueType) { - //Fields are not overwritten if they haven't the same type - field.setValue(value); - } - this.fields.set(mapKey, field); - return BrsInvalid.Instance; - } - - setParent(parent: RoSGNode) { - this.parent = parent; - } - - removeParent() { - this.parent = BrsInvalid.Instance; - } - - // recursively search for any child that's focused via DFS - isChildrenFocused(interpreter: Interpreter): boolean { - if (this.children.length === 0) { - return false; - } - - for (let childNode of this.children) { - if (interpreter.environment.getFocusedNode() === childNode) { - return true; - } else if (childNode.isChildrenFocused(interpreter)) { - return true; - } - } - return false; - } - - private getDefaultValue(type: string): BrsType { - let value: BrsType; - - switch (type.toLowerCase()) { - case 'boolean': - value = BrsBoolean.False; - break; - case 'dynamic': - value = BrsInvalid.Instance; - break; - case 'integer': - value = new Int32(0); - break; - case 'float': - value = new Float(0); - break; - case 'roArray': - value = BrsInvalid.Instance; - break; - case 'roAssociativeArray': - value = BrsInvalid.Instance; - break; - case 'string': - value = new BrsString(''); - break; - default: - value = Uninitialized.Instance; - break; - } - - return value; - } - - /* searches the node tree for a node with the given id */ - private findNodeById(node: RoSGNode, id: BrsString): RoSGNode | BrsInvalid { - // test current node in tree - let currentId = node.get(new BrsString('id')); - if (currentId.toString() === id.toString()) { - return node; - } - - // visit each child - for (let child of node.children) { - let result = this.findNodeById(child, id); - if (result instanceof RoSGNode) { - return result; - } - } - - // name was not found anywhere in tree - return BrsInvalid.Instance; - } - - /** Removes all fields from the node */ - // ToDo: Built-in fields shouldn't be removed - private clear = new Callable('clear', { - signature: { - args: [], - returns: ValueKind.Void - }, - impl: (interpreter: Interpreter) => { - this.fields.clear(); - return BrsInvalid.Instance; - } - }); - - /** Removes a given item from the node */ - // ToDo: Built-in fields shouldn't be removed - private delete = new Callable('delete', { - signature: { - args: [new StdlibArgument('str', ValueKind.String)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, str: BrsString) => { - this.fields.delete(str.value); - return BrsBoolean.True; //RBI always returns true - } - }); - - /** Given a key and value, adds an item to the node if it doesn't exist - * Or replaces the value of a key that already exists in the node - */ - private addreplace = new Callable('addreplace', { - signature: { - args: [ - new StdlibArgument('key', ValueKind.String), - new StdlibArgument('value', ValueKind.Dynamic) - ], - returns: ValueKind.Void - }, - impl: (interpreter: Interpreter, key: BrsString, value: BrsType) => { - this.set(key, value); - return BrsInvalid.Instance; - } - }); - - /** Returns the number of items in the node */ - private count = new Callable('count', { - signature: { - args: [], - returns: ValueKind.Int32 - }, - impl: (interpreter: Interpreter) => { - return new Int32(this.fields.size); - } - }); - - /** Returns a boolean indicating whether or not a given key exists in the node */ - private doesexist = new Callable('doesexist', { - signature: { - args: [new StdlibArgument('str', ValueKind.String)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, str: BrsString) => { - return this.get(str) !== BrsInvalid.Instance ? BrsBoolean.True : BrsBoolean.False; - } - }); - - /** Appends a new node to another. If two keys are the same, the value of the original AA is replaced with the new one. */ - private append = new Callable('append', { - signature: { - args: [new StdlibArgument('obj', ValueKind.Object)], - returns: ValueKind.Void - }, - impl: (interpreter: Interpreter, obj: BrsType) => { - if (obj instanceof RoAssociativeArray) { - obj.elements.forEach((value, key) => { - this.fields.set(key, new Field(value, false)); - }); - } else if (obj instanceof RoSGNode) { - obj.getFields().forEach((value, key) => { - this.fields.set(key, value); - }); - } - - return BrsInvalid.Instance; - } - }); - - /** Returns an array of keys from the node in lexicographical order */ - private keys = new Callable('keys', { - signature: { - args: [], - returns: ValueKind.Object - }, - impl: (interpreter: Interpreter) => { - return new RoArray(this.getElements()); - } - }); - - /** Returns an array of values from the node in lexicographical order */ - private items = new Callable('items', { - signature: { - args: [], - returns: ValueKind.Object - }, - impl: (interpreter: Interpreter) => { - return new RoArray(this.getValues()); - } - }); - - /** Given a key, returns the value associated with that key. This method is case insensitive. */ - private lookup = new Callable('lookup', { - signature: { - args: [new StdlibArgument('key', ValueKind.String)], - returns: ValueKind.Dynamic - }, - impl: (interpreter: Interpreter, key: BrsString) => { - let lKey = key.value.toLowerCase(); - return this.get(new BrsString(lKey)); - } - }); - - /** Adds a new field to the node, if the field already exists it doesn't change the current value. */ - private addfield = new Callable('addfield', { - signature: { - args: [ - new StdlibArgument('fieldname', ValueKind.String), - new StdlibArgument('type', ValueKind.String), - new StdlibArgument('alwaysnotify', ValueKind.Boolean) - ], - returns: ValueKind.Boolean - }, - impl: ( - interpreter: Interpreter, - fieldname: BrsString, - type: BrsString, - alwaysnotify: BrsBoolean - ) => { - let defaultValue = this.getDefaultValue(type.value); - - if (defaultValue !== Uninitialized.Instance && !this.fields.has(fieldname.value)) { - this.set(fieldname, defaultValue, alwaysnotify.toBoolean()); - } - - return BrsBoolean.True; - } - }); - - /** Adds one or more fields defined as an associative aray of key values. */ - private addfields = new Callable('addfields', { - signature: { - args: [new StdlibArgument('fields', ValueKind.Object)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, fields: RoAssociativeArray) => { - if (!(fields instanceof RoAssociativeArray)) { - return BrsBoolean.False; - } - - fields.getValue().forEach((value, key) => { - let fieldName = new BrsString(key); - if (!this.fields.has(key)) { - this.set(fieldName, value); - } - }); - - return BrsBoolean.True; - } - }); - - /** Returns the value of the field passed as argument, if the field doesn't exist it returns invalid. */ - private getfield = new Callable('getfield', { - signature: { - args: [new StdlibArgument('fieldname', ValueKind.String)], - returns: ValueKind.Dynamic - }, - impl: (interpreter: Interpreter, fieldname: BrsString) => { - return this.get(fieldname); - } - }); - - /** Registers a callback to be executed when the value of the field changes */ - private observefield = new Callable('observefield', { - signature: { - args: [ - new StdlibArgument('fieldname', ValueKind.String), - new StdlibArgument('functionname', ValueKind.String) - ], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, fieldname: BrsString, functionname: BrsString) => { - let field = this.fields.get(fieldname.value); - if (field instanceof Field) { - field.addObserver(functionname); - } - return BrsBoolean.True; - } - }); - - /** Removes the given field from the node */ - /** TODO: node built-in fields shouldn't be removable (i.e. id, change, focusable,) */ - private removefield = new Callable('removefield', { - signature: { - args: [new StdlibArgument('fieldname', ValueKind.String)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, fieldname: BrsString) => { - this.fields.delete(fieldname.value); - return BrsBoolean.True; //RBI always returns true - } - }); - - /** Updates the value of an existing field only if the types match. */ - private setfield = new Callable('setfield', { - signature: { - args: [ - new StdlibArgument('fieldname', ValueKind.String), - new StdlibArgument('value', ValueKind.Dynamic) - ], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, fieldname: BrsString, value: BrsType) => { - let field = this.get(fieldname); - - if (!this.fields.has(fieldname.value)) { - return BrsBoolean.False; - } - - if (valueKindToString(field.kind) !== valueKindToString(value.kind)) { - return BrsBoolean.False; - } - - this.set(fieldname, value); - return BrsBoolean.True; - } - }); - - /** Updates the value of multiple existing field only if the types match. */ - private setfields = new Callable('setfields', { - signature: { - args: [new StdlibArgument('fields', ValueKind.Object)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, fields: RoAssociativeArray) => { - if (!(fields instanceof RoAssociativeArray)) { - return BrsBoolean.False; - } - - fields.getValue().forEach((value, key) => { - let fieldName = new BrsString(key); - if (this.fields.has(key)) { - this.set(fieldName, value); - } - }); - - return BrsBoolean.True; - } - }); - - /* Updates the value of multiple existing field only if the types match. - In contrast to setFields method, update always return Uninitialized */ - private update = new Callable('update', { - signature: { - args: [new StdlibArgument('aa', ValueKind.Object)], - returns: ValueKind.Uninitialized - }, - impl: (interpreter: Interpreter, aa: RoAssociativeArray) => { - if (!(aa instanceof RoAssociativeArray)) { - return Uninitialized.Instance; - } - - aa.getValue().forEach((value, key) => { - let fieldName = new BrsString(key); - if (this.fields.has(key)) { - this.set(fieldName, value); - } - }); - - return Uninitialized.Instance; - } - }); - - /* Return the current number of children in the subject node list of children. - This is always a non-negative number. */ - private getchildcount = new Callable('getchildcount', { - signature: { - args: [], - returns: ValueKind.Int32 - }, - impl: (interpreter: Interpreter) => { - return new Int32(this.children.length); - } - }); - - /* Adds a child node to the end of the subject node list of children so that it is - traversed last (of those children) during render. */ - private appendchild = new Callable('appendchild', { - signature: { - args: [new StdlibArgument('child', ValueKind.Dynamic)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, child: BrsType) => { - if (child instanceof RoSGNode) { - if (this.children.includes(child)) { - return BrsBoolean.True; - } - this.children.push(child); - child.setParent(this); - return BrsBoolean.True; - } - return BrsBoolean.False; - } - }); - - /* Retrieves the number of child nodes specified by num_children from the subject - node, starting at the position specified by index. Returns an array of the child nodes - retrieved. If num_children is -1, return all the children. */ - private getchildren = new Callable('getchildren', { - signature: { - args: [ - new StdlibArgument('num_children', ValueKind.Int32), - new StdlibArgument('index', ValueKind.Int32) - ], - returns: ValueKind.Object - }, - impl: (interpreter: Interpreter, num_children: Int32, index: Int32) => { //eslint-disable-line - let numChildrenValue = num_children.getValue();//eslint-disable-line - let indexValue = index.getValue(); - let childrenSize = this.children.length; - if (numChildrenValue <= -1 && indexValue === 0) { - //short hand to return all children - return new RoArray(this.children.slice()); - } else if (numChildrenValue <= 0 || indexValue < 0 || indexValue >= childrenSize) { - //these never return any children - return new RoArray([]); - } else { - //only valid cases - return new RoArray(this.children.slice(indexValue, indexValue + numChildrenValue)); - } - - return new RoArray([]);//eslint-disable-line - } - }); - - /* Finds a child node in the subject node list of children, and if found, - remove it from the list of children. The match is made on the basis of actual - object identity, that is, the value of the pointer to the child node. - return false if trying to remove anything that's not a node */ - private removechild = new Callable('removechild', { - signature: { - args: [new StdlibArgument('child', ValueKind.Dynamic)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, child: BrsType) => { - if (child instanceof RoSGNode) { - let spliceIndex = this.children.indexOf(child); - if (spliceIndex >= 0) { - child.removeParent(); - this.children.splice(spliceIndex, 1); - } - return BrsBoolean.True; - } - return BrsBoolean.False; - } - }); - /* If the subject node has been added to a parent node list of children, - return the parent node, otherwise return invalid.*/ - private getparent = new Callable('getparent', { - signature: { - args: [], - returns: ValueKind.Dynamic - }, - impl: (interpreter: Interpreter) => { - return this.parent; - } - }); - - /* Creates a child node of type nodeType, and adds the new node to the end of the - subject node list of children */ - private createchild = new Callable('createchild', { - signature: { - args: [new StdlibArgument('nodetype', ValueKind.String)], - returns: ValueKind.Object - }, - impl: (interpreter: Interpreter, nodetype: BrsString) => { - // currently we can't create a custom subclass object of roSGNode, - // so we'll always create generic RoSGNode object as child - let child = createNodeByType(nodetype); - if (child instanceof RoSGNode) { - this.children.push(child); - child.setParent(this); - } - return child; - } - }); - - /* Returns true if the subject node has the remote control focus, and false otherwise */ - private hasfocus = new Callable('hasfocus', { - signature: { - args: [], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter) => { - return BrsBoolean.from(interpreter.environment.getFocusedNode() === this); - } - }); - - /** - * If on is set to true, sets the current remote control focus to the subject node, - * also automatically removing it from the node on which it was previously set. - * If on is set to false, removes focus from the subject node if it had it - */ - private setfocus = new Callable('setfocus', { - signature: { - args: [new StdlibArgument('on', ValueKind.Boolean)], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter, on: BrsBoolean) => { - interpreter.environment.setFocusedNode(on.toBoolean() ? this : BrsInvalid.Instance); - return BrsBoolean.False; //brightscript always returns false for some reason - } - }); - - /** - * Returns true if the subject node or any of its descendants in the SceneGraph node tree - * has remote control focus - */ - private isinfocuschain = new Callable('isinfocuschain', { - signature: { - args: [], - returns: ValueKind.Boolean - }, - impl: (interpreter: Interpreter) => { - // loop through all children DFS and check if any children has focus - if (interpreter.environment.getFocusedNode() === this) { - return BrsBoolean.True; - } - - return BrsBoolean.from(this.isChildrenFocused(interpreter)); - } - }); - - /* Returns the node that is a descendant of the nearest component ancestor of the subject node whose id field matches the given name, - otherwise return invalid. - Implemented as a DFS from the top of parent hierarchy to match the observed behavior as opposed to the BFS mentioned in the docs. */ - private findnode = new Callable('findnode', { - signature: { - args: [new StdlibArgument('name', ValueKind.String)], - returns: ValueKind.Dynamic - }, - impl: (interpreter: Interpreter, name: BrsString) => { - // climb parent hierarchy to find node to start search at - let root: RoSGNode = this; - while (root.parent && root.parent instanceof RoSGNode) { - root = root.parent; - } - - // perform search - return this.findNodeById(root, name); - } - }); -} - -export function createNodeByType(type: BrsString) { - if (type.value === 'Node') { - return new RoSGNode([]); - } else { - return BrsInvalid.Instance; - } -} diff --git a/src/brsTypes/components/RoString.ts b/src/brsTypes/components/RoString.ts deleted file mode 100644 index bf8a2a256..000000000 --- a/src/brsTypes/components/RoString.ts +++ /dev/null @@ -1,436 +0,0 @@ -import { BrsComponent } from './BrsComponent'; -import { RoArray } from './RoArray'; -import { BrsValue, ValueKind, BrsString, BrsBoolean, BrsInvalid, Comparable } from '../BrsType'; -import { Callable, StdlibArgument } from '../Callable'; -import { BrsType } from '..'; -import { Unboxable } from '../Boxing'; -import { Int32 } from '../Int32'; -import { Float } from '../Float'; - -export class RoString extends BrsComponent implements BrsValue, Comparable, Unboxable { - readonly kind = ValueKind.Object; - private intrinsic: BrsString; - - public getValue(): string { - return this.intrinsic.value; - } - - constructor(initialValue: BrsString) { - super('roString', ['ifStringOps']); - - this.intrinsic = initialValue; - this.registerMethods([ - this.setString, - this.appendString, - this.len, - this.left, - this.right, - this.mid, - this.instr, - this.replace, - this.trim, - this.toInt, - this.toFloat, - this.tokenize, - this.split, - this.getEntityEncode, - this.escape, - this.unescape, - this.encodeUri, - this.decodeUri, - this.encodeUriComponent, - this.decodeUriComponent - ]); - } - - equalTo(other: BrsType): BrsBoolean { - if (other.kind === ValueKind.String) { - return BrsBoolean.from(other.value === this.intrinsic.value); - } - - if (other instanceof RoString) { - return BrsBoolean.from(other.intrinsic.value === this.intrinsic.value); - } - - return BrsBoolean.False; - } - - lessThan(other: BrsType): BrsBoolean { - if (other.kind === ValueKind.String) { - return this.unbox().lessThan(other); - } - - if (other instanceof RoString) { - return this.unbox().lessThan(other.unbox()); - } - - return BrsBoolean.False; - } - - greaterThan(other: BrsType): BrsBoolean { - if (other.kind === ValueKind.String) { - return this.unbox().greaterThan(other); - } - - if (other instanceof RoString) { - return this.unbox().greaterThan(other.unbox()); - } - - return BrsBoolean.False; - } - - unbox() { - return this.intrinsic; - } - - toString(_parent?: BrsType): string { - return this.intrinsic.toString(); - } - - // ---------- ifStringOps ---------- - /** Sets the string to the first len characters of s. */ - private setString = new Callable('SetString', { - signature: { - args: [ - new StdlibArgument('s', ValueKind.String), - new StdlibArgument('len', ValueKind.Int32) - ], - returns: ValueKind.Void - }, - impl: (_interpreter, s: BrsString, len: Int32) => { - this.intrinsic = new BrsString(s.value.substr(0, len.getValue())); - return BrsInvalid.Instance; - } - }); - - /** Appends the first len characters of s to the end of the string. */ - private appendString = new Callable('AppendString', { - signature: { - args: [ - new StdlibArgument('s', ValueKind.String), - new StdlibArgument('len', ValueKind.Int32) - ], - returns: ValueKind.Void - }, - impl: (_interpreter, s: BrsString, len: Int32) => { - this.intrinsic = this.intrinsic.concat( - new BrsString(s.value.substr(0, len.getValue())) - ); - return BrsInvalid.Instance; - } - }); - - /** Returns the number of characters in the string. */ - private len = new Callable('Len', { - signature: { - args: [], - returns: ValueKind.Int32 - }, - impl: _interpreter => { - return new Int32(this.intrinsic.value.length); - } - }); - - /** Returns a string consisting of the first len characters of the string. */ - private left = new Callable('Left', { - signature: { - args: [new StdlibArgument('len', ValueKind.Int32)], - returns: ValueKind.String - }, - impl: (_interpreter, len: Int32) => { - return new BrsString(this.intrinsic.value.substr(0, len.getValue())); - } - }); - - /** Returns a string consisting of the last len characters of the string. */ - private right = new Callable('Right', { - signature: { - args: [new StdlibArgument('len', ValueKind.Int32)], - returns: ValueKind.String - }, - impl: (_interpreter, len: Int32) => { - let source = this.intrinsic.value; - return new BrsString(source.substr(source.length - len.getValue())); - } - }); - - private mid = new Callable( - 'Mid', - /** - * Returns a string consisting of the last characters of the string, starting at the - * zero-based start_index. - */ - { - signature: { - args: [new StdlibArgument('start_index', ValueKind.Int32)], - returns: ValueKind.String - }, - impl: (_interpreter, startIndex: Int32) => { - return new BrsString(this.intrinsic.value.substr(startIndex.getValue())); - } - }, - - /** - * Returns a string consisting of num_chars characters of the string, starting at the - * zero-based start_index. - */ - { - signature: { - args: [ - new StdlibArgument('start_index', ValueKind.Int32), - new StdlibArgument('num_chars', ValueKind.Int32) - ], - returns: ValueKind.String - }, - impl: (_interpreter, startIndex: Int32, numChars: Int32) => { - return new BrsString( - this.intrinsic.value.substr(startIndex.getValue(), numChars.getValue()) - ); - } - } - ); - - private instr = new Callable( - 'Instr', - /** Returns the zero-based index of the first occurrence of substring in the string. */ - { - signature: { - args: [new StdlibArgument('substring', ValueKind.String)], - returns: ValueKind.Int32 - }, - impl: (_interpreter, substring: BrsString) => { - return new Int32(this.intrinsic.value.indexOf(substring.value)); - } - }, - /** - * Returns the zero-based index of the first occurrence of substring in the string, starting - * at the specified zero-based start_index. - */ - { - signature: { - args: [ - new StdlibArgument('start_index', ValueKind.Int32), - new StdlibArgument('substring', ValueKind.String) - ], - returns: ValueKind.Int32 - }, - impl: (_interpreter, startIndex: Int32, substring: BrsString) => { - return new Int32( - this.intrinsic.value.indexOf(substring.value, startIndex.getValue()) - ); - } - } - ); - - /** - * Returns a copy of the string with all instances of fromStr replaced with toStr. If fromStr is - * empty the return value is the same as the source string. - */ - private replace = new Callable('Replace', { - signature: { - args: [ - new StdlibArgument('from', ValueKind.String), - new StdlibArgument('to', ValueKind.String) - ], - returns: ValueKind.String - }, - impl: (_interpreter, from: BrsString, to: BrsString) => { - if (from.value === '') { - return this.intrinsic; - } - - return new BrsString( - this.intrinsic.value.replace(new RegExp(from.value, 'g'), to.value) - ); - } - }); - - /** - * Returns the string with any leading and trailing whitespace characters (space, TAB, LF, CR, - * VT, FF, NO-BREAK SPACE, et al) removed. - */ - private trim = new Callable('Trim', { - signature: { - args: [], - returns: ValueKind.String - }, - impl: _interpreter => { - return new BrsString(this.intrinsic.value.trim()); - } - }); - - /** Returns the value of the string interpreted as a decimal number. */ - private toInt = new Callable('ToInt', { - signature: { - args: [], - returns: ValueKind.Int32 - }, - impl: _interpreter => { - let int = Math.trunc(Number.parseFloat(this.intrinsic.value)); - - if (Number.isNaN(int)) { - // non-integers are returned as "0" - return new Int32(0); - } - - return new Int32(int); - } - }); - - /** Returns the value of the string interpreted as a floating point number. */ - private toFloat = new Callable('ToFloat', { - signature: { - args: [], - returns: ValueKind.Float - }, - impl: _interpreter => { - let float = Number.parseFloat(this.intrinsic.value); - - if (Number.isNaN(float)) { - // non-integers are returned as "0" - return new Float(0); - } - - return new Float(float); - } - }); - - /** - * Splits the string into separate substrings separated by a single delimiter character. Returns - * an roList containing each of the substrings. The delimiters are not returned. - */ - private tokenize = new Callable('Tokenize', { - signature: { - args: [new StdlibArgument('delim', ValueKind.String)], - returns: ValueKind.Object - }, - impl: _interpreter => { - _interpreter.stderr.write( - 'WARNING: tokenize not yet implemented, because it returns an RoList. Returning `invalid`.' - ); - return BrsInvalid.Instance; - } - }); - - /** - * Splits the input string using the separator string as a delimiter, and returns an array of - * the split token strings (not including the delimiter). An empty separator string indicates - * to split the string by character. - */ - private split = new Callable('Split', { - signature: { - args: [new StdlibArgument('separator', ValueKind.String)], - returns: ValueKind.Object - }, - impl: (_interpreter, separator: BrsString) => { - let parts; - if (separator.value === '') { - // split characters apart, preserving multi-character unicode structures - parts = Array.from(this.intrinsic.value); - } else { - parts = this.intrinsic.value.split(separator.value); - } - - return new RoArray(parts.map(part => new BrsString(part))); - } - }); - - /** - * Returns the string with certain characters ("'<>&) replaced with the corresponding HTML - * entity encoding. - */ - private getEntityEncode = new Callable('GetEntityEncode', { - signature: { - args: [], - returns: ValueKind.String - }, - impl: _interpreter => { - return new BrsString(this.intrinsic.value.replace(/(['"<>&])/g, '\\$1')); - } - }); - - /** URL encodes the specified string per RFC 3986 and returns the encoded string. */ - private escape = new Callable('Escape', { - signature: { - args: [], - returns: ValueKind.String - }, - impl: _interpreter => { - return new BrsString( - // encoding courtesy of - // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent#Description - encodeURIComponent(this.intrinsic.value).replace( - /[!'()*]/g, - c => '%' + - c - .charCodeAt(0) - .toString(16) - .toUpperCase() - ) - ); - } - }); - - /** URL decodes the specified string per RFC 3986 and returns the decoded string. */ - private unescape = new Callable('Unescape', { - signature: { - args: [], - returns: ValueKind.String - }, - impl: _interpreter => { - return new BrsString(decodeURIComponent(this.intrinsic.value)); - } - }); - - /** - * Encode the specified string with escape sequences for reserved Uniform Resource Identifier - * (URI) characters. - */ - private encodeUri = new Callable('EncodeUri', { - signature: { - args: [], - returns: ValueKind.String - }, - impl: _interpreter => { - return new BrsString(encodeURI(this.intrinsic.value)); - } - }); - - /** - * Decode the specified string with escape sequences for reserved Uniform Resource Identifier - * (URI) characters. - */ - private decodeUri = new Callable('DecodeUri', { - signature: { - args: [], - returns: ValueKind.String - }, - impl: _interpreter => { - return new BrsString(decodeURI(this.intrinsic.value)); - } - }); - - /** - * Encode the specified string with escape sequences for reserved Uniform Resource Identifier - * (URI) component characters. - */ - private encodeUriComponent = new Callable('EncodeUriComponent', { - signature: { - args: [], - returns: ValueKind.String - }, - impl: _interpreter => { - return new BrsString(encodeURIComponent(this.intrinsic.value)); - } - }); - - private decodeUriComponent = new Callable('DecodeUriCOmponent', { - signature: { - args: [], - returns: ValueKind.String - }, - impl: _interpreter => { - return new BrsString(decodeURIComponent(this.intrinsic.value)); - } - }); -} diff --git a/src/brsTypes/components/Timespan.ts b/src/brsTypes/components/Timespan.ts deleted file mode 100644 index 0e66b4e2f..000000000 --- a/src/brsTypes/components/Timespan.ts +++ /dev/null @@ -1,93 +0,0 @@ -import { BrsValue, ValueKind, BrsString, BrsInvalid, BrsBoolean } from '../BrsType'; -import { BrsComponent } from './BrsComponent'; -import { BrsType } from '..'; -import { Callable, StdlibArgument } from '../Callable'; -declare type Interpreter = any; -import { Int32 } from '../Int32'; -import * as luxon from 'luxon'; - -export class Timespan extends BrsComponent implements BrsValue { - readonly kind = ValueKind.Object; - private markTime = Date.now(); - - constructor() { - super('roTimespan'); - this.registerMethods([ - this.mark, - this.totalmilliseconds, - this.totalseconds, - this.getsecondstoiso8601date - ]); - - this.resetTime(); - } - - resetTime() { - this.markTime = Date.now(); - } - - toString(parent?: BrsType): string { - return ''; - } - - equalTo(other: BrsType) { - return BrsBoolean.False; - } - - /** Sets timespan object to the current time */ - private mark = new Callable('mark', { - signature: { - args: [], - returns: ValueKind.Void - }, - impl: (_: Interpreter) => { - this.resetTime(); - return BrsInvalid.Instance; - } - }); - - /** Returns total milliseconds from the mark time to now */ - private totalmilliseconds = new Callable('totalmilliseconds', { - signature: { - args: [], - returns: ValueKind.Int32 - }, - impl: (_: Interpreter) => { - return new Int32(Date.now() - this.markTime); - } - }); - - /** Returns total seconds from the mark time to now */ - private totalseconds = new Callable('totalseconds', { - signature: { - args: [], - returns: ValueKind.Int32 - }, - impl: (_: Interpreter) => { - return new Int32((Date.now() - this.markTime) / 1000); - } - }); - - /** Parses an ISO8601 date and returns number of seconds from now until the given date. - * If the date is not a valid ISO8601 date string and can't be parsed, the int 2077252342 is returned, consistent with the brightscript method. - */ - private getsecondstoiso8601date = new Callable('getsecondstoiso8601date', { - signature: { - args: [new StdlibArgument('date', ValueKind.String)], - returns: ValueKind.Int32 - }, - impl: (_: Interpreter, date: BrsString) => { - let dateAsSeconds; - let now = Date.now(); - let dateToParse = luxon.DateTime.fromISO(date.value, { zone: 'utc' }); - - if (dateToParse.isValid) { - dateAsSeconds = (Date.parse(dateToParse.toISO()) - now) / 1000; - } else { - dateAsSeconds = 2077252342; - } - - return new Int32(dateAsSeconds); - } - }); -} diff --git a/src/brsTypes/index.ts b/src/brsTypes/index.ts deleted file mode 100644 index 1f422afd5..000000000 --- a/src/brsTypes/index.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { - ValueKind, - BrsInvalid, - BrsBoolean, - BrsString, - Uninitialized, - BrsValue -} from './BrsType'; -import { RoArray } from './components/RoArray'; -import { RoAssociativeArray } from './components/RoAssociativeArray'; -import { Int32 } from './Int32'; -import { Int64 } from './Int64'; -import { Float } from './Float'; -import { Double } from './Double'; -import { Callable } from './Callable'; -import { BrsComponent } from './components/BrsComponent'; -import { RoString } from './components/RoString'; - -export * from './BrsType'; -export * from './Int32'; -export * from './Int64'; -export * from './Float'; -export * from './Double'; -export * from './components/RoArray'; -export * from './components/RoAssociativeArray'; -export * from './components/Timespan'; -export * from './components/RoSGNode'; -export * from './components/BrsObjects'; -export * from './components/RoRegex'; -export * from './components/RoString'; -export * from './Callable'; - -/** - * Determines whether or not the given value is a number. - * @param value the BrightScript value in question. - * @returns `true` if `value` is a numeric value, otherwise `false`. - */ -export function isBrsNumber(value: BrsType): value is BrsNumber { - switch (value.kind) { - case ValueKind.Int32: - case ValueKind.Int64: - case ValueKind.Float: - case ValueKind.Double: - return true; - default: - return false; - } -} - -/** - * Determines whether or not the given value is a string. - * @param value the BrightScript value in question. - * @returns `true` if `value` is a string, otherwise `false`. - */ -export function isBrsString(value: BrsType): value is BrsString { - return value.kind === ValueKind.String || value instanceof RoString; -} - -/** - * Determines whether or not the given value is a boolean. - * @param value the BrightScript value in question. - * @returns `true` if `value` if a boolean, otherwise `false`. - */ -export function isBrsBoolean(value: BrsType): value is BrsBoolean { - return value.kind === ValueKind.Boolean; -} - -/** - * Determines whether or not the given value is a BrightScript callable. - * @param value the BrightScript value in question. - * @returns `true` if `value` is a Callable value, otherwise `false`. - */ -export function isBrsCallable(value: BrsType): value is Callable { - return value.kind === ValueKind.Callable; -} - -/** - * Determines whether or not the provided value is an instance of a iterable BrightScript type. - * @param value the BrightScript value in question. - * @returns `true` if `value` can be iterated across, otherwise `false`. - */ -export function isIterable(value: BrsType): value is Iterable { - return 'get' in value && 'getElements' in value && 'set' in value; -} - -/** The set of BrightScript numeric types. */ -export type BrsNumber = Int32 | Int64 | Float | Double; - -/** - * The set of all comparable BrightScript types. Only primitive (i.e. intrinsic * and unboxed) - * BrightScript types are comparable to each other. - */ -export type BrsPrimitive = BrsInvalid | BrsBoolean | BrsString | BrsNumber; - -/** The set of BrightScript iterable types. */ -export type Iterable = RoArray | RoAssociativeArray; - -// this is getting weird - we need a lesThan and greaterThan function?! -export type AllComponents = { kind: ValueKind.Object } & BrsComponent & BrsValue; - -/** The set of all supported types in BrightScript. */ -export type BrsType = BrsPrimitive | Iterable | Callable | AllComponents | Uninitialized; diff --git a/src/files/BrsFile.ts b/src/files/BrsFile.ts index 27a7caf8c..4c7f40f28 100644 --- a/src/files/BrsFile.ts +++ b/src/files/BrsFile.ts @@ -12,7 +12,7 @@ import { Parser, ParseMode } from '../parser'; import { FunctionExpression, VariableExpression, Expression } from '../parser/Expression'; import { AssignmentStatement, ClassStatement, LibraryStatement, ImportStatement } from '../parser/Statement'; import { Program } from '../Program'; -import { BrsType } from '../types/BrsType'; +import { BscType } from '../types/BscType'; import { DynamicType } from '../types/DynamicType'; import { FunctionType } from '../types/FunctionType'; import { VoidType } from '../types/VoidType'; @@ -453,7 +453,7 @@ export class BrsFile { nameRange: param.name.range, lineIndex: param.name.range.start.line, name: param.name.text, - type: util.valueKindToBrsType(param.type.kind) + type: param.type }); } @@ -477,7 +477,7 @@ export class BrsFile { nameRange: statement.name.range, lineIndex: statement.name.range.start.line, name: statement.name.text, - type: this.getBRSTypeFromAssignment(statement, scope) + type: this.getBscTypeFromAssignment(statement, scope) }); } } @@ -502,27 +502,27 @@ export class BrsFile { return ancestors; } - private getBRSTypeFromAssignment(assignment: AssignmentStatement, scope: FunctionScope): BrsType { + private getBscTypeFromAssignment(assignment: AssignmentStatement, scope: FunctionScope): BscType { try { //function if (isFunctionExpression(assignment.value)) { - let functionType = new FunctionType(util.valueKindToBrsType(assignment.value.returns)); + let functionType = new FunctionType(assignment.value.returnType); functionType.isSub = assignment.value.functionType.text === 'sub'; if (functionType.isSub) { functionType.returnType = new VoidType(); } functionType.setName(assignment.name.text); - for (let argument of assignment.value.parameters) { - let isRequired = !argument.defaultValue; + for (let param of assignment.value.parameters) { + let isRequired = !param.defaultValue; //TODO compute optional parameters - functionType.addParameter(argument.name.text, util.valueKindToBrsType(argument.type.kind), isRequired); + functionType.addParameter(param.name.text, param.type, isRequired); } return functionType; //literal } else if (isLiteralExpression(assignment.value)) { - return util.valueKindToBrsType((assignment.value as any).value.kind); + return assignment.value.type; //function call } else if (isCallExpression(assignment.value)) { @@ -560,7 +560,7 @@ export class BrsFile { private findCallables() { for (let statement of this.parser.references.functionStatements ?? []) { - let functionType = new FunctionType(util.valueKindToBrsType(statement.func.returns)); + let functionType = new FunctionType(statement.func.returnType); functionType.setName(statement.name.text); functionType.isSub = statement.func.functionType.text.toLowerCase() === 'sub'; if (functionType.isSub) { @@ -572,7 +572,7 @@ export class BrsFile { for (let param of statement.func.parameters) { let callableParam = { name: param.name.text, - type: util.valueKindToBrsType(param.type.kind), + type: param.type, isOptional: !!param.defaultValue, isRestArgument: false }; @@ -637,7 +637,8 @@ export class BrsFile { } let callableArg = { range: arg.range, - type: util.valueKindToBrsType(arg.value.kind), + //TODO not sure what to do here + type: new DynamicType(), // util.valueKindToBrsType(arg.value.kind), text: text }; //wrap the value in quotes because that's how it appears in the code diff --git a/src/interfaces.ts b/src/interfaces.ts index 5fc90157c..2d60ed338 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -4,7 +4,7 @@ import { Scope } from './Scope'; import { BrsFile } from './files/BrsFile'; import { XmlFile } from './files/XmlFile'; import { FunctionScope } from './FunctionScope'; -import { BrsType } from './types/BrsType'; +import { BscType } from './types/BscType'; import { FunctionType } from './types/FunctionType'; import { ParseMode } from './parser/Parser'; import { Program, SourceObj, TranspileObj } from './Program'; @@ -64,13 +64,13 @@ export interface FunctionCall { */ export interface CallableArg { text: string; - type: BrsType; + type: BscType; range: Range; } export interface CallableParam { name: string; - type: BrsType; + type: BscType; isOptional?: boolean; /** * Indicates that an unlimited number of arguments can be passed in @@ -116,7 +116,7 @@ export interface File { export interface VariableDeclaration { name: string; - type: BrsType; + type: BscType; /** * The range for the variable name */ @@ -128,22 +128,6 @@ export interface VariableDeclaration { lineIndex: number; } -//copied from brs (since it's not exported from there) -export enum ValueKind { - Invalid = 0, - Boolean = 1, - String = 2, - Int32 = 3, - Int64 = 4, - Float = 5, - Double = 6, - Callable = 7, - Uninitialized = 8, - Dynamic = 9, - Void = 10, - Object = 11 -} - /** * A wrapper around a callable to provide more information about where it came from */ diff --git a/src/lexer/Lexer.spec.ts b/src/lexer/Lexer.spec.ts index a560dcc24..ebcab9534 100644 --- a/src/lexer/Lexer.spec.ts +++ b/src/lexer/Lexer.spec.ts @@ -2,7 +2,6 @@ import { expect } from 'chai'; import { TokenKind } from '.'; -import { BrsString, Double, Float, Int32, Int64 } from '../brsTypes'; import { Lexer } from './Lexer'; import { isToken } from './Token'; import { rangeToArray } from '../parser/Parser.spec'; @@ -296,7 +295,6 @@ describe('lexer', () => { TokenKind.RightCurlyBrace, TokenKind.Eof ]); - expect(tokens.filter(t => !!t.literal).length).to.equal(0); }); it('reads operators', () => { @@ -314,7 +312,6 @@ describe('lexer', () => { TokenKind.PlusPlus, TokenKind.Eof ]); - expect(tokens.filter(t => !!t.literal).length).to.equal(0); }); it('reads bitshift operators', () => { @@ -325,7 +322,6 @@ describe('lexer', () => { TokenKind.LeftShift, TokenKind.Eof ]); - expect(tokens.filter(t => !!t.literal).length).to.equal(0); }); it('reads bitshift assignment operators', () => { @@ -335,7 +331,6 @@ describe('lexer', () => { TokenKind.RightShiftEqual, TokenKind.Eof ]); - expect(tokens.filter(t => !!t.literal).length).to.equal(0); }); it('reads comparators', () => { @@ -349,7 +344,6 @@ describe('lexer', () => { TokenKind.LessGreater, TokenKind.Eof ]); - expect(tokens.filter(t => !!t.literal).length).to.equal(0); }); }); // non-literals @@ -357,23 +351,21 @@ describe('lexer', () => { it('produces string literal tokens', () => { let { tokens } = Lexer.scan(`"hello world"`); expect(tokens.map(t => t.kind)).to.deep.equal([TokenKind.StringLiteral, TokenKind.Eof]); - expect(tokens[0].literal).to.deep.equal(new BrsString('hello world')); }); it(`safely escapes " literals`, () => { let { tokens } = Lexer.scan(`"the cat says ""meow"""`); expect(tokens[0].kind).to.equal(TokenKind.StringLiteral); - expect(tokens[0].literal).to.deep.equal(new BrsString(`the cat says "meow"`)); }); it('captures text to end of line for unterminated strings with LF', () => { let { tokens } = Lexer.scan(`"unterminated!\n`); - expect(tokens[0].literal.toString()).to.equal('unterminated!'); + expect(tokens[0].kind).to.eql(TokenKind.StringLiteral); }); it('captures text to end of line for unterminated strings with CRLF', () => { let { tokens } = Lexer.scan(`"unterminated!\r\n`); - expect(tokens[0].literal.toString()).to.equal('unterminated!'); + expect(tokens[0].text).to.equal('"unterminated!'); }); it('disallows multiline strings', () => { @@ -469,17 +461,22 @@ describe('lexer', () => { TokenKind.BackTick, TokenKind.Eof ]); - expect(tokens[1].literal).to.eql(new BrsString('the cat says ')); + expect(tokens[1].text).to.eql('"the cat says "'); expect(tokens[2].text).to.eql('\\`'); - expect(tokens[3].literal).to.eql(new BrsString('meow')); + expect(tokens[3].text).to.eql('"meow"'); expect(tokens[4].text).to.eql('\\`'); - expect(tokens[5].literal).to.eql(new BrsString(' a lot')); + expect(tokens[5].text).to.eql('" a lot"'); }); it('produces template string literal tokens', () => { let { tokens } = Lexer.scan('`hello world`'); - expect(tokens.map(t => t.kind)).to.deep.equal([TokenKind.BackTick, TokenKind.TemplateStringQuasi, TokenKind.BackTick, TokenKind.Eof]); - expect(tokens[1].literal).to.deep.equal(new BrsString('hello world')); + expect(tokens.map(t => t.kind)).to.deep.equal([ + TokenKind.BackTick, + TokenKind.TemplateStringQuasi, + TokenKind.BackTick, + TokenKind.Eof + ]); + expect(tokens[1].text).to.deep.equal('"hello world"'); }); it('collects quasis outside and expressions inside of template strings', () => { @@ -494,7 +491,7 @@ describe('lexer', () => { TokenKind.BackTick, TokenKind.Eof ]); - expect(tokens[1].literal).to.deep.equal(new BrsString(`hello `)); + expect(tokens[1].text).to.deep.equal(`hello `); }); it('real example, which is causing issues in the formatter', () => { @@ -644,7 +641,7 @@ describe('lexer', () => { TokenKind.BackTick, TokenKind.Eof ]); - expect(tokens[1].literal).to.eql(new BrsString(`multi-line`)); + expect(tokens[1].text).to.eql(`"multi-line"`); expect(tokens[2].text).to.equal('\n'); expect(tokens[2].text).to.equal('\n'); }); @@ -720,31 +717,31 @@ describe('lexer', () => { it('respects \'#\' suffix', () => { let d = Lexer.scan('123#').tokens[0]; expect(d.kind).to.equal(TokenKind.DoubleLiteral); - expect(d.literal).to.deep.equal(new Double(123)); + expect(d.text).to.eql(123); }); it('forces literals >= 10 digits into doubles', () => { let d = Lexer.scan('0000000005').tokens[0]; expect(d.kind).to.equal(TokenKind.DoubleLiteral); - expect(d.literal).to.deep.equal(new Double(5)); + expect(d.text).to.eql(5); }); it('forces literals with \'D\' in exponent into doubles', () => { let d = Lexer.scan('2.5d3').tokens[0]; expect(d.kind).to.equal(TokenKind.DoubleLiteral); - expect(d.literal).to.deep.equal(new Double(2500)); + expect(d.text).to.eql(2500); }); it('allows digits before `.` to be elided', () => { let f = Lexer.scan('.123#').tokens[0]; expect(f.kind).to.equal(TokenKind.DoubleLiteral); - expect(f.literal).to.deep.equal(new Double(0.123)); + expect(f.text).to.eql(0.123); }); it('allows digits after `.` to be elided', () => { let f = Lexer.scan('12.#').tokens[0]; expect(f.kind).to.equal(TokenKind.DoubleLiteral); - expect(f.literal).to.deep.equal(new Double(12)); + expect(f.text).to.eql('12'); }); }); @@ -753,32 +750,32 @@ describe('lexer', () => { let f = Lexer.scan('0.00000008!').tokens[0]; expect(f.kind).to.equal(TokenKind.FloatLiteral); // Floating precision will make this *not* equal - expect(f.literal).not.to.equal(8e-8); - expect(f.literal).to.deep.equal(new Float(0.00000008)); + expect(f.text).not.to.equal(8e-8); + expect(f.text).to.eql('0.00000008!'); }); it('forces literals with a decimal into floats', () => { let f = Lexer.scan('1.0').tokens[0]; expect(f.kind).to.equal(TokenKind.FloatLiteral); - expect(f.literal).to.deep.equal(new Float(1000000000000e-12)); + expect(f.text).to.equal('1.0'); }); it('forces literals with \'E\' in exponent into floats', () => { let f = Lexer.scan('2.5e3').tokens[0]; expect(f.kind).to.equal(TokenKind.FloatLiteral); - expect(f.literal).to.deep.equal(new Float(2500)); + expect(f.text).to.eql('2.5e3'); }); it('allows digits before `.` to be elided', () => { let f = Lexer.scan('.123').tokens[0]; expect(f.kind).to.equal(TokenKind.FloatLiteral); - expect(f.literal).to.deep.equal(new Float(0.123)); + expect(f.text).to.equal('.123'); }); it('allows digits after `.` to be elided', () => { let f = Lexer.scan('12.').tokens[0]; expect(f.kind).to.equal(TokenKind.FloatLiteral); - expect(f.literal).to.deep.equal(new Float(12)); + expect(f.text).to.equal('12.'); }); }); @@ -786,19 +783,19 @@ describe('lexer', () => { it('supports hexadecimal literals', () => { let i = Lexer.scan('&hf00d&').tokens[0]; expect(i.kind).to.equal(TokenKind.LongIntegerLiteral); - expect(i.literal).to.deep.equal(new Int64(61453)); + expect(i.text).to.equal('&hf00d&'); }); it('allows very long Int64 literals', () => { let li = Lexer.scan('9876543210&').tokens[0]; expect(li.kind).to.equal(TokenKind.LongIntegerLiteral); - expect(li.literal).to.deep.equal(Int64.fromString('9876543210')); + expect(li.text).to.equal('9876543210&'); }); it('forces literals with \'&\' suffix into Int64s', () => { let li = Lexer.scan('123&').tokens[0]; expect(li.kind).to.equal(TokenKind.LongIntegerLiteral); - expect(li.literal).to.deep.equal(new Int64(123)); + expect(li.text).to.deep.equal('123'); }); }); @@ -806,13 +803,13 @@ describe('lexer', () => { it('supports hexadecimal literals', () => { let i = Lexer.scan('&hFf').tokens[0]; expect(i.kind).to.equal(TokenKind.IntegerLiteral); - expect(i.literal).to.deep.equal(new Int32(255)); + expect(i.text).to.deep.equal('255'); }); it('falls back to a regular integer', () => { let i = Lexer.scan('123').tokens[0]; expect(i.kind).to.equal(TokenKind.IntegerLiteral); - expect(i.literal).to.deep.equal(new Int32(123)); + expect(i.text).to.deep.equal('123'); }); }); @@ -855,7 +852,6 @@ describe('lexer', () => { TokenKind.LineNumLiteral, TokenKind.Eof ]); - expect(tokens.filter(w => !!w.literal).length).to.equal(0); }); it('matches multi-word keywords', () => { @@ -869,7 +865,6 @@ describe('lexer', () => { TokenKind.ExitWhile, TokenKind.Eof ]); - expect(tokens.filter(w => !!w.literal).length).to.equal(0); }); it('accepts \'exit for\' but not \'exitfor\'', () => { diff --git a/src/lexer/Lexer.ts b/src/lexer/Lexer.ts index b4f9b514c..9c00f79e2 100644 --- a/src/lexer/Lexer.ts +++ b/src/lexer/Lexer.ts @@ -2,8 +2,6 @@ import { TokenKind, ReservedWords, Keywords } from './TokenKind'; import { Token } from './Token'; import { isAlpha, isDecimalDigit, isAlphaNumeric, isHexDigit } from './Characters'; - -import { BrsType, BrsString, Int32, Int64, Float, Double } from '../brsTypes/index'; import { Range, Diagnostic } from 'vscode-languageserver'; import { DiagnosticMessages } from '../DiagnosticMessages'; import util from '../util'; @@ -457,7 +455,7 @@ export class Lexer { //replace escaped quotemarks "" with a single quote value = value.replace(/""/g, '"'); - this.addToken(TokenKind.StringLiteral, new BrsString(value)); + this.addToken(TokenKind.StringLiteral); } /** * Reads characters within a string literal, advancing through escaped characters to the @@ -592,7 +590,7 @@ export class Lexer { private templateQuasiString() { let value = this.source.slice(this.start, this.current); if (value !== '`') { // if this is an empty string straight after an expression, then we'll accidentally consume the backtick - this.addToken(TokenKind.TemplateStringQuasi, new BrsString(value)); + this.addToken(TokenKind.TemplateStringQuasi); } } @@ -630,13 +628,13 @@ export class Lexer { if (numberOfDigits >= 10 && designator !== '&') { // numeric literals over 10 digits with no type designator are implicitly Doubles - this.addToken(TokenKind.DoubleLiteral, Double.fromString(asString)); + this.addToken(TokenKind.DoubleLiteral); return; } else if (designator === '#') { // numeric literals ending with "#" are forced to Doubles this.advance(); asString = this.source.slice(this.start, this.current); - this.addToken(TokenKind.DoubleLiteral, Double.fromString(asString)); + this.addToken(TokenKind.DoubleLiteral); return; } else if (designator === 'd') { // literals that use "D" as the exponent are also automatic Doubles @@ -656,7 +654,7 @@ export class Lexer { // replace the exponential marker with a JavaScript-friendly "e" asString = this.source.slice(this.start, this.current).replace(/[dD]/, 'e'); - this.addToken(TokenKind.DoubleLiteral, Double.fromString(asString)); + this.addToken(TokenKind.DoubleLiteral); return; } @@ -664,7 +662,7 @@ export class Lexer { // numeric literals ending with "!" are forced to Floats this.advance(); asString = this.source.slice(this.start, this.current); - this.addToken(TokenKind.FloatLiteral, Float.fromString(asString)); + this.addToken(TokenKind.FloatLiteral); return; } else if (designator === 'e') { // literals that use "E" as the exponent are also automatic Floats @@ -683,11 +681,11 @@ export class Lexer { } asString = this.source.slice(this.start, this.current); - this.addToken(TokenKind.FloatLiteral, Float.fromString(asString)); + this.addToken(TokenKind.FloatLiteral); return; } else if (containsDecimal) { // anything with a decimal but without matching Double rules is a Float - this.addToken(TokenKind.FloatLiteral, Float.fromString(asString)); + this.addToken(TokenKind.FloatLiteral); return; } @@ -695,11 +693,11 @@ export class Lexer { // numeric literals ending with "&" are forced to LongIntegers asString = this.source.slice(this.start, this.current); this.advance(); - this.addToken(TokenKind.LongIntegerLiteral, Int64.fromString(asString)); + this.addToken(TokenKind.LongIntegerLiteral); } else { // otherwise, it's a regular integer - this.addToken(TokenKind.IntegerLiteral, Int32.fromString(asString)); + this.addToken(TokenKind.IntegerLiteral); } } @@ -729,11 +727,9 @@ export class Lexer { if (this.peek() === '&') { // literals ending with "&" are forced to LongIntegers this.advance(); - let asString = this.source.slice(this.start, this.current); - this.addToken(TokenKind.LongIntegerLiteral, Int64.fromString(asString)); + this.addToken(TokenKind.LongIntegerLiteral); } else { - let asString = this.source.slice(this.start, this.current); - this.addToken(TokenKind.IntegerLiteral, Int32.fromString(asString)); + this.addToken(TokenKind.IntegerLiteral); } } @@ -926,13 +922,12 @@ export class Lexer { * @param kind the type of token to produce. * @param literal an optional literal value to include in the token. */ - private addToken(kind: TokenKind, literal?: BrsType) { + private addToken(kind: TokenKind) { let text = this.source.slice(this.start, this.current); let token: Token = { kind: kind, text: text, isReserved: ReservedWords.has(text.toLowerCase()), - literal: literal, range: this.rangeOf(), leadingWhitespace: this.leadingWhitespace }; diff --git a/src/lexer/Token.ts b/src/lexer/Token.ts index e19f275bb..ed4bb6d01 100644 --- a/src/lexer/Token.ts +++ b/src/lexer/Token.ts @@ -1,5 +1,4 @@ import { TokenKind } from './TokenKind'; -import { BrsType } from '../brsTypes'; import { Range } from 'vscode-languageserver'; /** @@ -12,8 +11,6 @@ export interface Token { text: string; /** True if this token's `text` is a reserved word, otherwise `false`. */ isReserved: boolean; - /** The literal value (using the BRS type system) associated with this token, if any. */ - literal?: BrsType; /** Where the token was found. */ range: Range; /** diff --git a/src/parser/Expression.ts b/src/parser/Expression.ts index 11954ae5b..50c180c3c 100644 --- a/src/parser/Expression.ts +++ b/src/parser/Expression.ts @@ -1,6 +1,5 @@ /* eslint-disable no-bitwise */ import { Token, Identifier, TokenKind } from '../lexer'; -import { BrsType, ValueKind, BrsString, FunctionParameterExpression } from '../brsTypes'; import { Block, CommentStatement, FunctionStatement } from './Statement'; import { SourceNode } from 'source-map'; import { Range } from 'vscode-languageserver'; @@ -9,7 +8,9 @@ import { TranspileState } from './TranspileState'; import { ParseMode } from './Parser'; import * as fileUrl from 'file-url'; import { walk, InternalWalkMode, WalkOptions, WalkVisitor } from '../astUtils/visitors'; -import { isCommentStatement, isEscapedCharCodeLiteralExpression, isLiteralExpression, isVariableExpression } from '../astUtils/reflection'; +import { isCommentStatement, isEscapedCharCodeLiteralExpression, isLiteralExpression, isStringType, isVariableExpression } from '../astUtils/reflection'; +import { BscType } from '../types/BscType'; +import { DynamicType } from '../types/DynamicType'; export type ExpressionVisitor = (expression: Expression, parent: Expression) => void; @@ -111,7 +112,6 @@ export class CallExpression extends Expression { export class FunctionExpression extends Expression { constructor( readonly parameters: FunctionParameterExpression[], - readonly returns: ValueKind, public body: Block, readonly functionType: Token | null, public end: Token, @@ -125,8 +125,16 @@ export class FunctionExpression extends Expression { readonly parentFunction?: FunctionExpression ) { super(); + if (this.returnTypeToken) { + this.returnType = util.tokenToBscType(this.returnTypeToken); + } } + /** + * The type this function returns + */ + public returnType: BscType; + /** * The list of function calls that are declared within this function scope. This excludes CallExpressions * declared in child functions @@ -223,6 +231,55 @@ export class FunctionExpression extends Expression { } } +export class FunctionParameterExpression extends Expression { + constructor( + public name: Identifier, + public typeToken?: Token, + public defaultValue?: Expression, + public asToken?: Token + ) { + super(); + this.type = util.tokenToBscType(typeToken) ?? new DynamicType(); + } + + public type: BscType; + + public get range(): Range { + return { + start: this.name.range.start, + end: this.typeToken ? this.typeToken.range.end : this.name.range.end + }; + } + + public transpile(state: TranspileState) { + let result = [ + //name + new SourceNode(this.name.range.start.line + 1, this.name.range.start.character, state.pathAbsolute, this.name.text) + ] as any[]; + //default value + if (this.defaultValue) { + result.push(' = '); + result.push(this.defaultValue.transpile(state)); + } + //type declaration + if (this.asToken) { + result.push(' '); + result.push(new SourceNode(this.asToken.range.start.line + 1, this.asToken.range.start.character, state.pathAbsolute, 'as')); + result.push(' '); + result.push(new SourceNode(this.typeToken.range.start.line + 1, this.typeToken.range.start.character, state.pathAbsolute, this.typeToken.text)); + } + + return result; + } + + walk(visitor: WalkVisitor, options: WalkOptions) { + // eslint-disable-next-line no-bitwise + if (this.defaultValue && options.walkMode & InternalWalkMode.walkExpressions) { + walk(this, 'defaultValue', visitor, options); + } + } +} + export class NamespacedVariableNameExpression extends Expression { constructor( //if this is a `DottedGetExpression`, it must be comprised only of `VariableExpression`s @@ -396,22 +453,30 @@ export class GroupingExpression extends Expression { export class LiteralExpression extends Expression { constructor( - readonly value: BrsType, - range: Range + public token: Token ) { super(); - this.range = range ?? util.createRange(-1, -1, -1, -1); + this.type = util.tokenToBscType(token); } - public readonly range: Range; + public get range() { + return this.token.range; + } + + /** + * The (data) type of this expression + */ + public type: BscType; transpile(state: TranspileState) { let text: string; - if (this.value.kind === ValueKind.String) { + if (isStringType(this.type)) { //escape quote marks with another quote mark - text = `"${this.value.value.replace(/"/g, '""')}"`; + //TODO do we need to do this anymore? If not, remove the above and below comments + //`"${this.value.value.replace(/"/g, '""')}"`; + text = this.token.text; } else { - text = this.value.toString(); + text = this.token.text; } return [ @@ -537,8 +602,6 @@ export class ArrayLiteralExpression extends Expression { export class AAMemberExpression extends Expression { constructor( - /** The name of the member. */ - public key: BrsString, public keyToken: Token, public colonToken: Token, /** The expression evaluated to determine the member's initial value. */ @@ -939,7 +1002,8 @@ export class TemplateStringQuasiExpression extends Expression { let plus = ''; for (let expression of this.expressions) { //skip empty strings - if (((expression as LiteralExpression)?.value as BrsString)?.value === '' && skipEmptyStrings === true) { + //TODO what does an empty string literal expression look like? + if ((expression as LiteralExpression).token.text === '""' && skipEmptyStrings === true) { continue; } result.push( @@ -1013,7 +1077,7 @@ export class TemplateStringExpression extends Expression { //skip the toString wrapper around certain expressions if ( isEscapedCharCodeLiteralExpression(expression) || - (isLiteralExpression(expression) && expression.value.kind === ValueKind.String) + (isLiteralExpression(expression) && isStringType(expression.type)) ) { add( ...expression.transpile(state) diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts index 7d13da546..dd0ef005a 100644 --- a/src/parser/Parser.ts +++ b/src/parser/Parser.ts @@ -11,17 +11,6 @@ import { BrighterScriptSourceLiterals } from '../lexer'; -import { - BrsInvalid, - BrsBoolean, - BrsString, - Int32, - ValueKind, - Argument, - StdlibArgument, - FunctionParameterExpression, - valueKindFromString -} from '../brsTypes'; import { Statement, FunctionStatement, @@ -76,12 +65,13 @@ import { EscapedCharCodeLiteralExpression, TemplateStringQuasiExpression, TaggedTemplateStringExpression, - SourceLiteralExpression + SourceLiteralExpression, FunctionParameterExpression } from './Expression'; import { Diagnostic, Range } from 'vscode-languageserver'; import { Logger } from '../Logger'; import { isCallExpression, isCallfuncExpression, isClassMethodStatement, isDottedGetExpression, isIndexedGetExpression, isVariableExpression } from '../astUtils/reflection'; import { createVisitor, WalkMode } from '../astUtils/visitors'; +import { createStringLiteral } from '../astUtils/creators'; export class Parser { /** @@ -489,7 +479,7 @@ export class Parser { fieldType = this.advance(); //no field type specified - if (!valueKindFromString(`${fieldType.text}`) && !this.check(TokenKind.Identifier)) { + if (!util.tokenToBscType(fieldType) && !this.check(TokenKind.Identifier)) { this.diagnostics.push({ ...DiagnosticMessages.expectedValidTypeToFollowAsKeyword(), range: this.peek().range @@ -551,15 +541,8 @@ export class Parser { let isSub = functionType && functionType.kind === TokenKind.Sub; let functionTypeText = isSub ? 'sub' : 'function'; let name: Identifier; - let returnType: ValueKind; let leftParen: Token; - if (isSub) { - returnType = ValueKind.Void; - } else { - returnType = ValueKind.Dynamic; - } - if (isAnonymous) { leftParen = this.consume( DiagnosticMessages.expectedLeftParenAfterCallable(functionTypeText), @@ -587,7 +570,7 @@ export class Parser { } } - let params: FunctionParameterExpression[] = []; + let params = [] as FunctionParameterExpression[]; let asToken: Token; let typeToken: Token; if (!this.check(TokenKind.RightParen)) { @@ -608,28 +591,24 @@ export class Parser { asToken = this.advance(); typeToken = this.advance(); - let typeString = typeToken.text || ''; - let maybeReturnType = valueKindFromString(typeString); - if (!maybeReturnType) { + if (!util.tokenToBscType(typeToken)) { this.diagnostics.push({ - ...DiagnosticMessages.invalidFunctionReturnType(typeString), + ...DiagnosticMessages.invalidFunctionReturnType(typeToken.text ?? ''), range: typeToken.range }); } - - returnType = maybeReturnType; } - params.reduce((haveFoundOptional: boolean, arg: Argument) => { - if (haveFoundOptional && !arg.defaultValue) { + params.reduce((haveFoundOptional: boolean, param: FunctionParameterExpression) => { + if (haveFoundOptional && !param.defaultValue) { this.diagnostics.push({ - ...DiagnosticMessages.requiredParameterMayNotFollowOptionalParameter(arg.name.text), - range: arg.range + ...DiagnosticMessages.requiredParameterMayNotFollowOptionalParameter(param.name.text), + range: param.range }); } - return haveFoundOptional || !!arg.defaultValue; + return haveFoundOptional || !!param.defaultValue; }, false); let comment: CommentStatement; //get a comment if available @@ -645,7 +624,6 @@ export class Parser { while (this.match(TokenKind.Newline)) { } let func = new FunctionExpression( params, - returnType, undefined, //body functionType, undefined, //ending keyword @@ -730,7 +708,6 @@ export class Parser { // force the name into an identifier so the AST makes some sense name.kind = TokenKind.Identifier; - let type: ValueKind = ValueKind.Dynamic; let typeToken: Token | undefined; let defaultValue; @@ -745,25 +722,18 @@ export class Parser { asToken = this.advance(); typeToken = this.advance(); - let typeValueKind = valueKindFromString(typeToken.text); - if (!typeValueKind) { + if (!util.tokenToBscType(typeToken)) { this.diagnostics.push({ ...DiagnosticMessages.functionParameterTypeIsInvalid(name.text, typeToken.text), range: typeToken.range }); throw this.lastDiagnosticAsError(); } - - type = typeValueKind; } return new FunctionParameterExpression( name, - { - kind: type, - range: typeToken ? typeToken.range : StdlibArgument.InternalRange - }, typeToken, defaultValue, asToken @@ -956,7 +926,7 @@ export class Parser { increment = this.expression(); } else { // BrightScript for/to/step loops default to a step of 1 if no `step` is provided - increment = new LiteralExpression(new Int32(1), this.peek().range); + increment = new LiteralExpression(this.peek()); } while (this.match(TokenKind.Newline)) { @@ -1262,7 +1232,7 @@ export class Parser { if (next.kind === TokenKind.TemplateStringQuasi) { //a quasi can actually be made up of multiple quasis when it includes char literals currentQuasiExpressionParts.push( - new LiteralExpression(next.literal, next.range) + new LiteralExpression(next) ); this.advance(); } else if (next.kind === TokenKind.EscapedCharCodeLiteral) { @@ -1663,7 +1633,8 @@ export class Parser { //print statements can be empty, so look for empty print conditions if (this.isAtEnd() || this.check(TokenKind.Newline, TokenKind.Colon)) { - let emptyStringLiteral = new LiteralExpression(new BrsString(''), printKeyword.range); + //TODO we aren't a runtime, so do we need to do this? + let emptyStringLiteral = createStringLiteral(''); values.push(emptyStringLiteral); } else { values.push(this.expression()); @@ -2064,11 +2035,11 @@ export class Parser { private primary(): Expression { switch (true) { case this.match(TokenKind.False): - return new LiteralExpression(BrsBoolean.False, this.previous().range); + return new LiteralExpression(this.previous()); case this.match(TokenKind.True): - return new LiteralExpression(BrsBoolean.True, this.previous().range); + return new LiteralExpression(this.previous()); case this.match(TokenKind.Invalid): - return new LiteralExpression(BrsInvalid.Instance, this.previous().range); + return new LiteralExpression(this.previous()); case this.match( TokenKind.IntegerLiteral, TokenKind.LongIntegerLiteral, @@ -2076,7 +2047,7 @@ export class Parser { TokenKind.DoubleLiteral, TokenKind.StringLiteral ): - return new LiteralExpression(this.previous().literal, this.previous().range); + return new LiteralExpression(this.previous()); //capture source literals (LINE_NUM if brightscript, or a bunch of them if brighterscript case this.match(TokenKind.LineNumLiteral, ...(this.options.mode === ParseMode.BrightScript ? [] : BrighterScriptSourceLiterals)): return new SourceLiteralExpression(this.previous()); @@ -2139,15 +2110,12 @@ export class Parser { let result = { colonToken: null as Token, keyToken: null as Token, - key: null as BrsString, range: null as Range }; if (this.check(TokenKind.Identifier, ...AllowedProperties)) { result.keyToken = this.advance(); - result.key = new BrsString(result.keyToken.text); } else if (this.check(TokenKind.StringLiteral)) { result.keyToken = this.advance(); - result.key = result.keyToken.literal as BrsString; } else { this.diagnostics.push({ ...DiagnosticMessages.unexpectedAAKey(), @@ -2174,7 +2142,6 @@ export class Parser { let k = key(); let expr = this.expression(); members.push(new AAMemberExpression( - k.key, k.keyToken, k.colonToken, expr @@ -2203,7 +2170,6 @@ export class Parser { let k = key(); let expr = this.expression(); members.push(new AAMemberExpression( - k.key, k.keyToken, k.colonToken, expr diff --git a/src/parser/Statement.ts b/src/parser/Statement.ts index 1feedbe7f..1bde080e0 100644 --- a/src/parser/Statement.ts +++ b/src/parser/Statement.ts @@ -1,14 +1,14 @@ /* eslint-disable no-bitwise */ import { Token, Identifier, TokenKind, CompoundAssignmentOperators } from '../lexer'; import { SourceNode } from 'source-map'; -import { BinaryExpression, Expression, NamespacedVariableNameExpression, FunctionExpression, CallExpression, VariableExpression, LiteralExpression } from './Expression'; +import { BinaryExpression, Expression, NamespacedVariableNameExpression, FunctionExpression, CallExpression, VariableExpression } from './Expression'; import { util } from '../util'; import { Range, Position } from 'vscode-languageserver'; import { TranspileState } from './TranspileState'; import { ParseMode, Parser } from './Parser'; import { walk, WalkVisitor, WalkOptions, InternalWalkMode } from '../astUtils/visitors'; import { isCallExpression, isClassFieldStatement, isClassMethodStatement, isCommentStatement, isDottedGetExpression, isExpression, isExpressionStatement, isFunctionStatement, isVariableExpression } from '../astUtils/reflection'; -import { BrsInvalid } from '../brsTypes/BrsType'; +import { createInvalidLiteral, createToken } from '../astUtils'; /** * A BrightScript statement @@ -1566,19 +1566,9 @@ export class ClassMethodStatement extends FunctionStatement { //if there is no initial value, set the initial value to `invalid` newStatements.push( new AssignmentStatement( - { - kind: TokenKind.Equal, - isReserved: false, - range: field.name.range, - text: '=', - leadingWhitespace: '' - }, + createToken(TokenKind.Equal, '='), thisQualifiedName, - new LiteralExpression( - BrsInvalid.Instance, - //set the range to the end of the name so locations don't get broken - Range.create(field.name.range.end, field.name.range.end) - ), + createInvalidLiteral(), this.func ) ); diff --git a/src/parser/tests/Parser.spec.ts b/src/parser/tests/Parser.spec.ts index cacb0ca40..ddb31a4a4 100644 --- a/src/parser/tests/Parser.spec.ts +++ b/src/parser/tests/Parser.spec.ts @@ -10,12 +10,11 @@ import { Range } from 'vscode-languageserver'; * @param {*} [literal] the literal value that the produced token should contain, if any * @returns {object} a token of `kind` representing `text` with value `literal`. */ -export function token(kind, text?, literal?): Token { +export function token(kind: TokenKind, text?: string): Token { return { kind: kind, text: text, isReserved: ReservedWords.has((text || '').toLowerCase()), - literal: literal, range: Range.create(-9, -9, -9, -9), leadingWhitespace: '' }; diff --git a/src/parser/tests/controlFlow/For.spec.ts b/src/parser/tests/controlFlow/For.spec.ts index 1b94a6810..132c0e850 100644 --- a/src/parser/tests/controlFlow/For.spec.ts +++ b/src/parser/tests/controlFlow/For.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser for loops', () => { it('accepts a \'step\' clause', () => { @@ -12,11 +12,11 @@ describe('parser for loops', () => { token(TokenKind.For, 'for'), identifier('i'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '0', new Int32(0)), + createToken(TokenKind.IntegerLiteral, '0'), token(TokenKind.To, 'to'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.Step, 'step'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Newline, '\n'), // body would go here, but it's not necessary for this test token(TokenKind.EndFor, 'end for'), @@ -36,9 +36,9 @@ describe('parser for loops', () => { token(TokenKind.For, 'for'), identifier('i'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '0', new Int32(0)), + createToken(TokenKind.IntegerLiteral, '0'), token(TokenKind.To, 'to'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.Newline, '\n'), // body would go here, but it's not necessary for this test token(TokenKind.EndFor, 'end for'), @@ -58,9 +58,9 @@ describe('parser for loops', () => { token(TokenKind.For, 'for'), identifier('i'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '0', new Int32(0)), + createToken(TokenKind.IntegerLiteral, '0'), token(TokenKind.To, 'to'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.Newline, '\n'), // body would go here, but it's not necessary for this test token(TokenKind.Next, 'next'), @@ -103,7 +103,6 @@ describe('parser for loops', () => { { kind: TokenKind.IntegerLiteral, text: '0', - literal: new Int32(0), isReserved: false, range: Range.create(0, 8, 0, 9) }, @@ -119,7 +118,6 @@ describe('parser for loops', () => { { kind: TokenKind.IntegerLiteral, text: '10', - literal: new Int32(10), isReserved: false, range: Range.create(0, 13, 0, 15) }, diff --git a/src/parser/tests/controlFlow/If.spec.ts b/src/parser/tests/controlFlow/If.spec.ts index ed8c6ceb3..0758e3793 100644 --- a/src/parser/tests/controlFlow/If.spec.ts +++ b/src/parser/tests/controlFlow/If.spec.ts @@ -1,15 +1,15 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsBoolean, Int32 } from '../../../brsTypes'; import { TokenKind, Lexer } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; +import { createToken } from '../../../astUtils/creators'; describe('parser if statements', () => { it('allows empty if blocks', () => { let { tokens } = Lexer.scan(` if true then - + else if true then stop else @@ -45,7 +45,7 @@ describe('parser if statements', () => { else if true then stop else - + end if `); let { statements, diagnostics } = Parser.parse(tokens); @@ -104,13 +104,13 @@ describe('parser if statements', () => { it('parses if only', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.If, 'if'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Less, '<'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Then, 'then'), identifier('foo'), token(TokenKind.Equal, '='), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.Newline, '\n'), EOF ]); @@ -122,17 +122,17 @@ describe('parser if statements', () => { it('parses if-else', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.If, 'if'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Less, '<'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Then, 'then'), identifier('foo'), token(TokenKind.Equal, '='), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.Else, 'else'), identifier('foo'), token(TokenKind.Equal, '='), - token(TokenKind.False, 'true', BrsBoolean.False), + createToken(TokenKind.False, 'true'), token(TokenKind.Newline, '\n'), EOF ]); @@ -144,25 +144,25 @@ describe('parser if statements', () => { it('parses if-elseif-else', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.If, 'if'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Less, '<'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Then, 'then'), identifier('foo'), token(TokenKind.Equal, '='), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.ElseIf, 'else if'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Then, 'then'), identifier('same'), token(TokenKind.Equal, '='), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.Else, 'else'), identifier('foo'), token(TokenKind.Equal, '='), - token(TokenKind.True, 'true', BrsBoolean.False), + createToken(TokenKind.True, 'true'), token(TokenKind.Newline, '\n'), EOF ]); @@ -174,23 +174,23 @@ describe('parser if statements', () => { it('allows \'then\' to be skipped', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.If, 'if'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Less, '<'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), identifier('foo'), token(TokenKind.Equal, '='), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.ElseIf, 'else if'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), identifier('same'), token(TokenKind.Equal, '='), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.Else, 'else'), identifier('foo'), token(TokenKind.Equal, '='), - token(TokenKind.False, 'false', BrsBoolean.False), + createToken(TokenKind.False, 'false'), token(TokenKind.Newline, '\n'), EOF ]); diff --git a/src/parser/tests/controlFlow/While.spec.ts b/src/parser/tests/controlFlow/While.spec.ts index 250be05c7..499afa0b8 100644 --- a/src/parser/tests/controlFlow/While.spec.ts +++ b/src/parser/tests/controlFlow/While.spec.ts @@ -1,20 +1,20 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsBoolean, BrsString, Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser while statements', () => { it('while without exit', () => { const { statements, diagnostics } = Parser.parse([ token(TokenKind.While, 'while'), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.Newline, '\n'), token(TokenKind.Print, 'print'), - token(TokenKind.StringLiteral, 'looping', new BrsString('looping')), + createToken(TokenKind.StringLiteral, 'looping'), token(TokenKind.Newline, '\n'), token(TokenKind.EndWhile, 'end while'), EOF @@ -27,10 +27,10 @@ describe('parser while statements', () => { it('while with exit', () => { const { statements, diagnostics } = Parser.parse([ token(TokenKind.While, 'while'), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.Newline, '\n'), token(TokenKind.Print, 'print'), - token(TokenKind.StringLiteral, 'looping', new BrsString('looping')), + createToken(TokenKind.StringLiteral, 'looping'), token(TokenKind.Newline, '\n'), token(TokenKind.ExitWhile, 'exit while'), token(TokenKind.Newline, '\n'), @@ -61,7 +61,6 @@ describe('parser while statements', () => { { kind: TokenKind.True, text: 'true', - literal: BrsBoolean.True, isReserved: true, range: Range.create(0, 6, 0, 10) }, @@ -74,7 +73,7 @@ describe('parser while statements', () => { // loop body isn't significant for location tracking, so helper functions are safe identifier('Rnd'), token(TokenKind.LeftParen, '('), - token(TokenKind.IntegerLiteral, '0', new Int32(0)), + createToken(TokenKind.IntegerLiteral), token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\n'), { diff --git a/src/parser/tests/expression/Additive.spec.ts b/src/parser/tests/expression/Additive.spec.ts index 729529b10..e4ad340f7 100644 --- a/src/parser/tests/expression/Additive.spec.ts +++ b/src/parser/tests/expression/Additive.spec.ts @@ -1,21 +1,21 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser additive expressions', () => { it('parses left-associative addition chains', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), EOF ]); @@ -27,11 +27,11 @@ describe('parser additive expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Minus, '-'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Minus, '-'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), EOF ]); @@ -62,7 +62,6 @@ describe('parser additive expressions', () => { kind: TokenKind.IntegerLiteral, text: '1', isReserved: false, - literal: new Int32(1), range: Range.create(0, 4, 0, 5) }, { @@ -75,7 +74,6 @@ describe('parser additive expressions', () => { kind: TokenKind.IntegerLiteral, text: '2', isReserved: false, - literal: new Int32(2), range: Range.create(0, 8, 0, 9) }, { @@ -88,7 +86,6 @@ describe('parser additive expressions', () => { kind: TokenKind.IntegerLiteral, text: '3', isReserved: false, - literal: new Int32(3), range: Range.create(0, 12, 0, 13) }, { diff --git a/src/parser/tests/expression/ArrayLiterals.spec.ts b/src/parser/tests/expression/ArrayLiterals.spec.ts index 21c429c75..48c38b16f 100644 --- a/src/parser/tests/expression/ArrayLiterals.spec.ts +++ b/src/parser/tests/expression/ArrayLiterals.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsBoolean, Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser array literals', () => { describe('empty arrays', () => { @@ -47,11 +47,11 @@ describe('parser array literals', () => { identifier('_'), token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -66,13 +66,13 @@ describe('parser array literals', () => { token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), token(TokenKind.Newline, '\n'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.Newline, '\n'), token(TokenKind.RightSquareBracket, ']'), EOF @@ -88,11 +88,11 @@ describe('parser array literals', () => { token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), token(TokenKind.Newline, '\n'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Newline, '\n'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Newline, '\n'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.Newline, '\n'), token(TokenKind.RightSquareBracket, ']'), EOF @@ -109,11 +109,11 @@ describe('parser array literals', () => { identifier('_'), token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -128,19 +128,19 @@ describe('parser array literals', () => { token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.Comma, ','), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '4', new Int32(4)), + createToken(TokenKind.IntegerLiteral, '4'), token(TokenKind.Comma, ','), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.Comma, ','), - token(TokenKind.IntegerLiteral, '6', new Int32(6)), + createToken(TokenKind.IntegerLiteral, '6'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.RightSquareBracket, ']'), EOF @@ -155,12 +155,12 @@ describe('parser array literals', () => { identifier('_'), token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), token(TokenKind.Not, 'not'), - token(TokenKind.False, 'false', BrsBoolean.False), + createToken(TokenKind.False, 'false'), token(TokenKind.RightSquareBracket, ']'), EOF ]); diff --git a/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts b/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts index 738e20e19..659f89785 100644 --- a/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts +++ b/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsString, Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser associative array literals', () => { describe('empty associative arrays', () => { @@ -49,15 +49,15 @@ describe('parser associative array literals', () => { token(TokenKind.LeftCurlyBrace, '{'), identifier('foo'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), identifier('bar'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), identifier('baz'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.RightCurlyBrace, '}'), EOF ]); @@ -74,17 +74,17 @@ describe('parser associative array literals', () => { token(TokenKind.Newline, '\n'), identifier('foo'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), identifier('bar'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), identifier('baz'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.Newline, '\n'), token(TokenKind.RightCurlyBrace, '}'), EOF @@ -102,15 +102,15 @@ describe('parser associative array literals', () => { token(TokenKind.Newline, '\n'), identifier('foo'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Newline, '\n'), identifier('bar'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Newline, '\n'), identifier('baz'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.Newline, '\n'), token(TokenKind.RightCurlyBrace, '}'), EOF @@ -133,7 +133,7 @@ describe('parser associative array literals', () => { token(TokenKind.LeftCurlyBrace, '{'), identifier('name'), token(TokenKind.Colon, ':'), - token(TokenKind.StringLiteral, 'Bob', new BrsString('Bob')), + createToken(TokenKind.StringLiteral, 'Bob'), token(TokenKind.Colon, ':'), token(TokenKind.Colon, ':'), token(TokenKind.Colon, ':'), @@ -141,7 +141,7 @@ describe('parser associative array literals', () => { token(TokenKind.Colon, ':'), identifier('age'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '50', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '50'), token(TokenKind.RightCurlyBrace, '}'), token(TokenKind.Newline, '\n'), token(TokenKind.EndSub, 'end sub'), @@ -157,19 +157,19 @@ describe('parser associative array literals', () => { token(TokenKind.Equal, '='), token(TokenKind.LeftCurlyBrace, '{'), token(TokenKind.Newline, '\n'), - token(TokenKind.StringLiteral, 'foo', new BrsString('foo')), + createToken(TokenKind.StringLiteral, 'foo'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), identifier('bar'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), - token(TokenKind.StringLiteral, 'requires-hyphens', new BrsString('requires-hyphens')), + createToken(TokenKind.StringLiteral, 'requires-hyphens'), token(TokenKind.Colon, ':'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.Newline, '\n'), token(TokenKind.RightCurlyBrace, '}'), EOF diff --git a/src/parser/tests/expression/Boolean.spec.ts b/src/parser/tests/expression/Boolean.spec.ts index a9bbd9af0..aad89b7b8 100644 --- a/src/parser/tests/expression/Boolean.spec.ts +++ b/src/parser/tests/expression/Boolean.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsBoolean } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser boolean expressions', () => { @@ -12,9 +12,9 @@ describe('parser boolean expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.And, 'and'), - token(TokenKind.False, 'false', BrsBoolean.False), + createToken(TokenKind.False, 'false'), EOF ]); @@ -26,9 +26,9 @@ describe('parser boolean expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.Or, 'or'), - token(TokenKind.False, 'false', BrsBoolean.False), + createToken(TokenKind.False, 'false'), EOF ]); @@ -59,7 +59,6 @@ describe('parser boolean expressions', () => { { kind: TokenKind.True, text: 'true', - literal: BrsBoolean.True, isReserved: true, range: Range.create(0, 4, 0, 8) }, @@ -72,7 +71,6 @@ describe('parser boolean expressions', () => { { kind: TokenKind.False, text: 'false', - literal: BrsBoolean.False, isReserved: true, range: Range.create(0, 13, 0, 18) }, diff --git a/src/parser/tests/expression/Call.spec.ts b/src/parser/tests/expression/Call.spec.ts index 464ebd107..d7fd21b22 100644 --- a/src/parser/tests/expression/Call.spec.ts +++ b/src/parser/tests/expression/Call.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsString, Int32 } from '../../../brsTypes'; import { TokenKind, Lexer } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser call expressions', () => { it('parses named function calls', () => { @@ -73,9 +73,9 @@ describe('parser call expressions', () => { const { statements, diagnostics } = Parser.parse([ identifier('add'), { kind: TokenKind.LeftParen, text: '(', line: 1 }, - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), { kind: TokenKind.Comma, text: ',', line: 1 }, - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.RightParen, ')'), EOF ]) as any; @@ -108,7 +108,6 @@ describe('parser call expressions', () => { { kind: TokenKind.StringLiteral, text: `"bar"`, - literal: new BrsString('bar'), isReserved: false, range: Range.create(0, 4, 0, 9) }, @@ -121,7 +120,6 @@ describe('parser call expressions', () => { { kind: TokenKind.StringLiteral, text: `"baz"`, - literal: new BrsString('baz'), isReserved: false, range: Range.create(0, 11, 0, 16) }, diff --git a/src/parser/tests/expression/Exponential.spec.ts b/src/parser/tests/expression/Exponential.spec.ts index fca072dcf..3ec2803ab 100644 --- a/src/parser/tests/expression/Exponential.spec.ts +++ b/src/parser/tests/expression/Exponential.spec.ts @@ -1,9 +1,9 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; +import { createToken } from '../../../astUtils/creators'; describe('parser', () => { describe('exponential expressions', () => { @@ -11,9 +11,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Caret, '^'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), EOF ]); @@ -25,11 +25,11 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Caret, '^'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.Caret, '^'), - token(TokenKind.IntegerLiteral, '4', new Int32(4)), + createToken(TokenKind.IntegerLiteral, '4'), EOF ]); diff --git a/src/parser/tests/expression/Function.spec.ts b/src/parser/tests/expression/Function.spec.ts index c1cf7ee3e..f1c609229 100644 --- a/src/parser/tests/expression/Function.spec.ts +++ b/src/parser/tests/expression/Function.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsString, Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser', () => { @@ -34,7 +34,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Colon, ':'), token(TokenKind.Print, 'print'), - token(TokenKind.StringLiteral, 'Lorem ipsum', new BrsString('Lorem ipsum')), + createToken(TokenKind.StringLiteral, 'Lorem ipsum'), token(TokenKind.Colon, ':'), token(TokenKind.EndFunction, 'end function'), EOF @@ -53,7 +53,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - token(TokenKind.StringLiteral, 'Lorem ipsum', new BrsString('Lorem ipsum')), + createToken(TokenKind.StringLiteral, 'Lorem ipsum'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndFunction, 'end function'), EOF @@ -118,19 +118,19 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.Comma, ','), identifier('b'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '4', new Int32(4)), + createToken(TokenKind.IntegerLiteral, '4'), token(TokenKind.Comma, ','), identifier('c'), token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), @@ -151,7 +151,7 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.Comma, ','), @@ -160,7 +160,7 @@ describe('parser', () => { token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.RightParen, ')'), @@ -219,7 +219,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - token(TokenKind.StringLiteral, 'Lorem ipsum', new BrsString('Lorem ipsum')), + createToken(TokenKind.StringLiteral, 'Lorem ipsum'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndSub, 'end sub'), EOF @@ -284,19 +284,19 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.Comma, ','), identifier('b'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '4', new Int32(4)), + createToken(TokenKind.IntegerLiteral, '4'), token(TokenKind.Comma, ','), identifier('c'), token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), @@ -317,7 +317,7 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.Comma, ','), @@ -326,7 +326,7 @@ describe('parser', () => { token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.RightParen, ')'), @@ -353,7 +353,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - token(TokenKind.StringLiteral, 'I\'m a callback', new BrsString('I\'m a callback')), + createToken(TokenKind.StringLiteral, 'I\'m a callback'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndFunction, 'end function'), token(TokenKind.Newline, '\\n'), @@ -376,7 +376,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - token(TokenKind.StringLiteral, 'I\'m anonymous', new BrsString('I\'m anonymous')), + createToken(TokenKind.StringLiteral, 'I\'m anonymous'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndFunction, 'end function'), diff --git a/src/parser/tests/expression/Indexing.spec.ts b/src/parser/tests/expression/Indexing.spec.ts index fc2c01ef6..32b61acda 100644 --- a/src/parser/tests/expression/Indexing.spec.ts +++ b/src/parser/tests/expression/Indexing.spec.ts @@ -1,12 +1,12 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; import { DiagnosticMessages } from '../../../DiagnosticMessages'; import { AssignmentStatement } from '../../Statement'; +import { createToken } from '../../../astUtils/creators'; describe('parser indexing', () => { describe('one level', () => { @@ -31,7 +31,7 @@ describe('parser indexing', () => { token(TokenKind.Equal, '='), identifier('foo'), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -49,7 +49,7 @@ describe('parser indexing', () => { identifier('foo'), token(TokenKind.Dot, '.'), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.Integer, '2', new Int32(2)), + createToken(TokenKind.Integer, '2'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -67,7 +67,7 @@ describe('parser indexing', () => { token(TokenKind.Dot, '.'), token(TokenKind.Dot, '.'), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.Integer, '2', new Int32(2)), + createToken(TokenKind.Integer, '2'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -153,7 +153,6 @@ describe('parser indexing', () => { { kind: TokenKind.IntegerLiteral, text: '2', - literal: new Int32(2), isReserved: false, range: Range.create(1, 8, 1, 9) }, @@ -201,13 +200,13 @@ describe('parser indexing', () => { token(TokenKind.Equal, '='), identifier('foo'), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '0', new Int32(0)), + createToken(TokenKind.IntegerLiteral, '0'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '6', new Int32(6)), + createToken(TokenKind.IntegerLiteral, '6'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -224,7 +223,7 @@ describe('parser indexing', () => { token(TokenKind.Dot, '.'), identifier('bar'), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '0', new Int32(0)), + createToken(TokenKind.IntegerLiteral, '0'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.Dot, '.'), identifier('baz'), diff --git a/src/parser/tests/expression/Multiplicative.spec.ts b/src/parser/tests/expression/Multiplicative.spec.ts index 88a7a781c..3e7785d44 100644 --- a/src/parser/tests/expression/Multiplicative.spec.ts +++ b/src/parser/tests/expression/Multiplicative.spec.ts @@ -1,9 +1,9 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { Float } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; +import { createToken } from '../../../astUtils/creators'; describe('parser', () => { @@ -12,11 +12,11 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.FloatLiteral, '3.0', new Float(3.0)), + createToken(TokenKind.FloatLiteral, '3.0'), token(TokenKind.Star, '*'), - token(TokenKind.FloatLiteral, '5.0', new Float(5.0)), + createToken(TokenKind.FloatLiteral, '5.0'), token(TokenKind.Star, '*'), - token(TokenKind.FloatLiteral, '7.0', new Float(7.0)), + createToken(TokenKind.FloatLiteral, '7.0'), EOF ]); @@ -28,11 +28,11 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.FloatLiteral, '7.0', new Float(7.0)), + createToken(TokenKind.FloatLiteral, '7.0'), token(TokenKind.Forwardslash, '/'), - token(TokenKind.FloatLiteral, '5.0', new Float(5.0)), + createToken(TokenKind.FloatLiteral, '5.0'), token(TokenKind.Forwardslash, '/'), - token(TokenKind.FloatLiteral, '3.0', new Float(3.0)), + createToken(TokenKind.FloatLiteral, '3.0'), EOF ]); @@ -44,11 +44,11 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.FloatLiteral, '7.0', new Float(7.0)), + createToken(TokenKind.FloatLiteral, '7.0'), token(TokenKind.Mod, 'MOD'), - token(TokenKind.FloatLiteral, '5.0', new Float(5.0)), + createToken(TokenKind.FloatLiteral, '5.0'), token(TokenKind.Mod, 'MOD'), - token(TokenKind.FloatLiteral, '3.0', new Float(3.0)), + createToken(TokenKind.FloatLiteral, '3.0'), EOF ]); @@ -60,11 +60,11 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.FloatLiteral, '32.5', new Float(32.5)), + createToken(TokenKind.FloatLiteral, '32.5'), token(TokenKind.Backslash, '\\'), - token(TokenKind.FloatLiteral, '5.0', new Float(5.0)), + createToken(TokenKind.FloatLiteral, '5.0'), token(TokenKind.Backslash, '\\'), - token(TokenKind.FloatLiteral, '3.0', new Float(3.0)), + createToken(TokenKind.FloatLiteral, '3.0'), EOF ]); diff --git a/src/parser/tests/expression/PrefixUnary.spec.ts b/src/parser/tests/expression/PrefixUnary.spec.ts index 54e037774..6536d5c29 100644 --- a/src/parser/tests/expression/PrefixUnary.spec.ts +++ b/src/parser/tests/expression/PrefixUnary.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsBoolean, Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser prefix unary expressions', () => { @@ -13,7 +13,7 @@ describe('parser prefix unary expressions', () => { identifier('_'), token(TokenKind.Equal, '='), token(TokenKind.Not, 'not'), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), EOF ]); @@ -30,7 +30,7 @@ describe('parser prefix unary expressions', () => { token(TokenKind.Not, 'not'), token(TokenKind.Not, 'not'), token(TokenKind.Not, 'not'), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), EOF ]); @@ -43,7 +43,7 @@ describe('parser prefix unary expressions', () => { identifier('_'), token(TokenKind.Equal, '='), token(TokenKind.Minus, '-'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), EOF ]); @@ -60,7 +60,7 @@ describe('parser prefix unary expressions', () => { token(TokenKind.Minus, '-'), token(TokenKind.Minus, '-'), token(TokenKind.Minus, '-'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), EOF ]); @@ -97,7 +97,6 @@ describe('parser prefix unary expressions', () => { { kind: TokenKind.True, text: 'true', - literal: BrsBoolean.True, isReserved: true, range: Range.create(0, 13, 0, 17) }, diff --git a/src/parser/tests/expression/Primary.spec.ts b/src/parser/tests/expression/Primary.spec.ts index 53126deba..0bdc7dd83 100644 --- a/src/parser/tests/expression/Primary.spec.ts +++ b/src/parser/tests/expression/Primary.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsString, Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser primary expressions', () => { @@ -13,7 +13,7 @@ describe('parser primary expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), equals, - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), EOF ]); expect(diagnostics).to.be.lengthOf(0); @@ -25,7 +25,7 @@ describe('parser primary expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), equals, - token(TokenKind.StringLiteral, 'hello', new BrsString('hello')), + createToken(TokenKind.StringLiteral, 'hello'), EOF ]); @@ -37,12 +37,12 @@ describe('parser primary expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), token(TokenKind.Plus, '+'), token(TokenKind.LeftParen, '('), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), token(TokenKind.Star, '*'), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.RightParen, ')'), EOF ]); @@ -77,7 +77,6 @@ describe('parser primary expressions', () => { { kind: TokenKind.IntegerLiteral, text: '5', - literal: new Int32(5), isReserved: false, range: Range.create(0, 4, 0, 5) }, @@ -102,7 +101,6 @@ describe('parser primary expressions', () => { { kind: TokenKind.StringLiteral, text: `"foo"`, - literal: new BrsString('foo'), isReserved: false, range: Range.create(1, 4, 1, 9) }, @@ -133,7 +131,6 @@ describe('parser primary expressions', () => { { kind: TokenKind.IntegerLiteral, text: '0', - literal: new Int32(0), isReserved: false, range: Range.create(2, 6, 2, 7) }, diff --git a/src/parser/tests/expression/Relational.spec.ts b/src/parser/tests/expression/Relational.spec.ts index 5782ccf06..5c09d8a33 100644 --- a/src/parser/tests/expression/Relational.spec.ts +++ b/src/parser/tests/expression/Relational.spec.ts @@ -1,9 +1,9 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; +import { createToken } from '../../../astUtils/creators'; describe('parser', () => { @@ -12,9 +12,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.Less, '<'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), EOF ]); @@ -26,9 +26,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.LessEqual, '<='), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), EOF ]); @@ -41,9 +41,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.Greater, '>'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), EOF ]); @@ -56,9 +56,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.GreaterEqual, '>='), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), EOF ]); @@ -70,9 +70,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), EOF ]); @@ -85,9 +85,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.LessGreater, '<>'), - token(TokenKind.IntegerLiteral, '2', new Int32(2)), + createToken(TokenKind.IntegerLiteral, '2'), EOF ]); diff --git a/src/parser/tests/statement/AssignmentOperators.spec.ts b/src/parser/tests/statement/AssignmentOperators.spec.ts index b7bb5a8d5..ce3a04c13 100644 --- a/src/parser/tests/statement/AssignmentOperators.spec.ts +++ b/src/parser/tests/statement/AssignmentOperators.spec.ts @@ -1,16 +1,16 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsString, Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; +import { createToken } from '../../../astUtils/creators'; describe('parser assignment operators', () => { it('+=', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.PlusEqual), - token(TokenKind.StringLiteral, `"lorem"`, new BrsString('lorem')), + createToken(TokenKind.StringLiteral, `"lorem"`), EOF ]); @@ -22,7 +22,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.MinusEqual), - token(TokenKind.IntegerLiteral, '1', new Int32(1)), + createToken(TokenKind.IntegerLiteral, '1'), EOF ]); @@ -34,7 +34,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.StarEqual), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), EOF ]); @@ -46,7 +46,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.ForwardslashEqual), - token(TokenKind.IntegerLiteral, '4', new Int32(4)), + createToken(TokenKind.IntegerLiteral, '4'), EOF ]); @@ -58,7 +58,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.BackslashEqual), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), EOF ]); @@ -70,7 +70,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.LeftShiftEqual), - token(TokenKind.IntegerLiteral, '6', new Int32(6)), + createToken(TokenKind.IntegerLiteral, '6'), EOF ]); @@ -82,7 +82,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.RightShiftEqual), - token(TokenKind.IntegerLiteral, '7', new Int32(7)), + createToken(TokenKind.IntegerLiteral, '7'), EOF ]); diff --git a/src/parser/tests/statement/Declaration.spec.ts b/src/parser/tests/statement/Declaration.spec.ts index dd0b98d05..fbacb3266 100644 --- a/src/parser/tests/statement/Declaration.spec.ts +++ b/src/parser/tests/statement/Declaration.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsInvalid, Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser variable declarations', () => { it('allows newlines before assignments', () => { @@ -41,7 +41,7 @@ describe('parser variable declarations', () => { let { statements, diagnostics } = Parser.parse([ identifier('foo'), token(TokenKind.Equal), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), EOF ]); @@ -54,9 +54,9 @@ describe('parser variable declarations', () => { let { statements, diagnostics } = Parser.parse([ identifier('bar'), token(TokenKind.Equal), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.Caret), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), EOF ]); @@ -101,7 +101,6 @@ describe('parser variable declarations', () => { { kind: TokenKind.Invalid, text: 'invalid', - literal: BrsInvalid.Instance, isReserved: true, range: Range.create(0, 6, 0, 13) }, diff --git a/src/parser/tests/statement/Function.spec.ts b/src/parser/tests/statement/Function.spec.ts index fc712a150..805e6a1c4 100644 --- a/src/parser/tests/statement/Function.spec.ts +++ b/src/parser/tests/statement/Function.spec.ts @@ -1,9 +1,9 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsString, Int32 } from '../../../brsTypes'; import { TokenKind, Lexer } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; +import { createToken } from '../../../astUtils/creators'; describe('parser', () => { @@ -48,7 +48,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - token(TokenKind.StringLiteral, 'Lorem ipsum', new BrsString('Lorem ipsum')), + createToken(TokenKind.StringLiteral, 'Lorem ipsum'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndFunction, 'end function'), EOF @@ -109,19 +109,19 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.Comma, ','), identifier('b'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '4', new Int32(4)), + createToken(TokenKind.IntegerLiteral, '4'), token(TokenKind.Comma, ','), identifier('c'), token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), @@ -142,7 +142,7 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.Comma, ','), @@ -151,7 +151,7 @@ describe('parser', () => { token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.RightParen, ')'), @@ -250,7 +250,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - token(TokenKind.StringLiteral, 'Lorem ipsum', new BrsString('Lorem ipsum')), + createToken(TokenKind.StringLiteral, 'Lorem ipsum'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndSub, 'end sub'), EOF @@ -311,19 +311,19 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.Comma, ','), identifier('b'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '4', new Int32(4)), + createToken(TokenKind.IntegerLiteral, '4'), token(TokenKind.Comma, ','), identifier('c'), token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), @@ -343,7 +343,7 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.Comma, ','), @@ -352,7 +352,7 @@ describe('parser', () => { token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.RightParen, ')'), diff --git a/src/parser/tests/statement/PrintStatement.spec.ts b/src/parser/tests/statement/PrintStatement.spec.ts index 991eef7d7..ed6aa1aaf 100644 --- a/src/parser/tests/statement/PrintStatement.spec.ts +++ b/src/parser/tests/statement/PrintStatement.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsString } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser print statements', () => { it('parses singular print statements', () => { @@ -29,9 +29,9 @@ describe('parser print statements', () => { it('parses print lists with no separator', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.Print), - token(TokenKind.StringLiteral, 'Foo', new BrsString('Foo')), - token(TokenKind.StringLiteral, 'bar', new BrsString('bar')), - token(TokenKind.StringLiteral, 'baz', new BrsString('baz')), + createToken(TokenKind.StringLiteral, 'Foo'), + createToken(TokenKind.StringLiteral, 'bar'), + createToken(TokenKind.StringLiteral, 'baz'), EOF ]); @@ -43,11 +43,11 @@ describe('parser print statements', () => { it('parses print lists with separators', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.Print), - token(TokenKind.StringLiteral, 'Foo', new BrsString('Foo')), + createToken(TokenKind.StringLiteral, 'Foo'), token(TokenKind.Semicolon), - token(TokenKind.StringLiteral, 'bar', new BrsString('bar')), + createToken(TokenKind.StringLiteral, 'bar'), token(TokenKind.Semicolon), - token(TokenKind.StringLiteral, 'baz', new BrsString('baz')), + createToken(TokenKind.StringLiteral, 'baz'), EOF ]); @@ -74,7 +74,6 @@ describe('parser print statements', () => { { kind: TokenKind.StringLiteral, text: `"foo"`, - literal: new BrsString('foo'), isReserved: false, range: Range.create(0, 6, 0, 11), leadingWhitespace: '' diff --git a/src/parser/tests/statement/ReturnStatement.spec.ts b/src/parser/tests/statement/ReturnStatement.spec.ts index 9dd08f42a..ff4d66f68 100644 --- a/src/parser/tests/statement/ReturnStatement.spec.ts +++ b/src/parser/tests/statement/ReturnStatement.spec.ts @@ -1,11 +1,11 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { BrsString, Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { FunctionStatement } from '../../Statement'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser return statements', () => { it('parses void returns', () => { @@ -33,7 +33,7 @@ describe('parser return statements', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Return, 'return'), - { kind: TokenKind.StringLiteral, literal: new BrsString('test'), text: '"test"', line: 2 }, + createToken(TokenKind.StringLiteral, '"test"'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndFunction, 'end function'), EOF @@ -87,7 +87,6 @@ describe('parser return statements', () => { { kind: TokenKind.IntegerLiteral, text: '5', - literal: new Int32(5), isReserved: false, range: Range.create(1, 9, 1, 10) }, diff --git a/src/parser/tests/statement/Set.spec.ts b/src/parser/tests/statement/Set.spec.ts index 815a33bf1..b16aeaafd 100644 --- a/src/parser/tests/statement/Set.spec.ts +++ b/src/parser/tests/statement/Set.spec.ts @@ -1,10 +1,10 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; -import { Int32 } from '../../../brsTypes'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { createToken } from '../../../astUtils/creators'; describe('parser indexed assignment', () => { describe('dotted', () => { @@ -51,7 +51,7 @@ describe('parser indexed assignment', () => { token(TokenKind.Dot, '.'), identifier('bar'), token(TokenKind.StarEqual, '*='), - token(TokenKind.IntegerLiteral, '5', new Int32(5)), + createToken(TokenKind.IntegerLiteral, '5'), token(TokenKind.Newline, '\\n'), EOF ]); @@ -67,7 +67,7 @@ describe('parser indexed assignment', () => { let { statements, diagnostics } = Parser.parse([ identifier('someArray'), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '0', new Int32(0)), + createToken(TokenKind.IntegerLiteral, '0'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.Equal, '='), token(TokenKind.Function, 'function'), @@ -87,7 +87,7 @@ describe('parser indexed assignment', () => { let { statements, diagnostics } = Parser.parse([ identifier('someArray'), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '0', new Int32(0)), + createToken(TokenKind.IntegerLiteral, '0'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.Equal, '='), token(TokenKind.True, 'true'), @@ -106,10 +106,10 @@ describe('parser indexed assignment', () => { let { statements, diagnostics } = Parser.parse([ identifier('someArray'), token(TokenKind.LeftSquareBracket, '['), - token(TokenKind.IntegerLiteral, '0', new Int32(0)), + createToken(TokenKind.IntegerLiteral, '0'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.StarEqual, '*='), - token(TokenKind.IntegerLiteral, '3', new Int32(3)), + createToken(TokenKind.IntegerLiteral, '3'), EOF ]); @@ -145,7 +145,6 @@ describe('parser indexed assignment', () => { { kind: TokenKind.IntegerLiteral, text: '0', - literal: new Int32(0), isReserved: false, range: Range.create(0, 4, 0, 5), leadingWhitespace: '' @@ -167,7 +166,6 @@ describe('parser indexed assignment', () => { { kind: TokenKind.IntegerLiteral, text: '1', - literal: new Int32(1), isReserved: false, range: Range.create(0, 9, 0, 10), leadingWhitespace: '' @@ -210,7 +208,6 @@ describe('parser indexed assignment', () => { { kind: TokenKind.IntegerLiteral, text: '5', - literal: new Int32(5), isReserved: false, range: Range.create(1, 8, 1, 9), leadingWhitespace: '' diff --git a/src/preprocessor/Preprocessor.spec.ts b/src/preprocessor/Preprocessor.spec.ts index f641e9a68..ecfa2bed5 100644 --- a/src/preprocessor/Preprocessor.spec.ts +++ b/src/preprocessor/Preprocessor.spec.ts @@ -3,8 +3,8 @@ import { TokenKind } from '../lexer/TokenKind'; import { Preprocessor } from './Preprocessor'; import { BrightScriptChunk, DeclarationChunk, ErrorChunk, HashIfStatement } from './Chunk'; import { expect } from 'chai'; -import { BrsBoolean, BrsString } from '../brsTypes'; import { createSandbox } from 'sinon'; +import { createToken } from '../astUtils/creators'; let sinon = createSandbox(); describe('preprocessor', () => { @@ -29,7 +29,7 @@ describe('preprocessor', () => { let { processedTokens } = new Preprocessor().filter([ new DeclarationChunk( identifier('lorem'), - token(TokenKind.False, 'false', BrsBoolean.False) + createToken(TokenKind.False, 'false') ) ]); expect(processedTokens).to.eql([]); @@ -41,7 +41,7 @@ describe('preprocessor', () => { () => new Preprocessor().filter([ new DeclarationChunk( identifier('lorem'), - token(TokenKind.True, 'true', BrsBoolean.True) + createToken(TokenKind.True, 'true') ) ]) ).not.to.throw; @@ -51,7 +51,7 @@ describe('preprocessor', () => { expect(() => new Preprocessor().filter([ new DeclarationChunk( identifier('ipsum'), - token(TokenKind.False, 'false', BrsBoolean.False) + createToken(TokenKind.False, 'false') ) ]) ).not.to.throw; @@ -62,11 +62,11 @@ describe('preprocessor', () => { // 'ipsum' must be defined before it's referenced new DeclarationChunk( identifier('ipsum'), - token(TokenKind.False, 'false', BrsBoolean.False) + createToken(TokenKind.False, 'false') ), new DeclarationChunk( identifier('dolor'), - token(TokenKind.True, 'true', BrsBoolean.True) + createToken(TokenKind.True, 'true') ) ]) ).not.to.throw; @@ -76,7 +76,7 @@ describe('preprocessor', () => { expect(() => new Preprocessor().filter([ new DeclarationChunk( identifier('sit'), - token(TokenKind.String, 'good boy!', new BrsString('good boy!')) + createToken(TokenKind.String, 'good boy!') ) ]) ).to.throw;//('#const declarations can only have'); @@ -86,11 +86,11 @@ describe('preprocessor', () => { expect(() => new Preprocessor().filter([ new DeclarationChunk( identifier('lorem'), - token(TokenKind.False, 'false', BrsBoolean.False) + createToken(TokenKind.False, 'false') ), new DeclarationChunk( identifier('lorem'), - token(TokenKind.True, 'true', BrsBoolean.True) + createToken(TokenKind.True, 'true') ) ]) ).to.throw; @@ -109,7 +109,7 @@ describe('preprocessor', () => { it('doesn\'t throw when branched around', () => { expect(() => new Preprocessor().filter([ new HashIfStatement( - token(TokenKind.False, 'false', BrsBoolean.False), + createToken(TokenKind.False, 'false'), [ new ErrorChunk( token(TokenKind.HashError, '#error'), @@ -141,11 +141,11 @@ describe('preprocessor', () => { it('enters #if branch', () => { new Preprocessor().filter([ new HashIfStatement( - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), [ifChunk], [ { - condition: token(TokenKind.True, 'true', BrsBoolean.True), + condition: createToken(TokenKind.True, 'true'), thenChunks: [elseIfChunk] } ], @@ -161,11 +161,11 @@ describe('preprocessor', () => { it('enters #else if branch', () => { new Preprocessor().filter([ new HashIfStatement( - token(TokenKind.False, 'false', BrsBoolean.False), + createToken(TokenKind.False, 'false'), [ifChunk], [ { - condition: token(TokenKind.True, 'true', BrsBoolean.True), + condition: createToken(TokenKind.True, 'true'), thenChunks: [elseIfChunk] } ], @@ -181,11 +181,11 @@ describe('preprocessor', () => { it('enters #else branch', () => { new Preprocessor().filter([ new HashIfStatement( - token(TokenKind.False, 'false', BrsBoolean.False), + createToken(TokenKind.False, 'false'), [ifChunk], [ { - condition: token(TokenKind.False, 'false', BrsBoolean.False), + condition: createToken(TokenKind.False, 'false'), thenChunks: [elseIfChunk] } ], @@ -201,7 +201,7 @@ describe('preprocessor', () => { it('enters no branches if none pass', () => { new Preprocessor().filter([ new HashIfStatement( - token(TokenKind.False, 'false', BrsBoolean.False), + createToken(TokenKind.False, 'false'), [ifChunk], [] // no else-if chunks // NOTE: no 'else" chunk! @@ -217,7 +217,7 @@ describe('preprocessor', () => { new Preprocessor().filter([ new DeclarationChunk( identifier('lorem'), - token(TokenKind.True, 'true', BrsBoolean.True) + createToken(TokenKind.True, 'true') ), new HashIfStatement( identifier('lorem'), diff --git a/src/preprocessor/PreprocessorParser.spec.ts b/src/preprocessor/PreprocessorParser.spec.ts index b214438e9..c71a09712 100644 --- a/src/preprocessor/PreprocessorParser.spec.ts +++ b/src/preprocessor/PreprocessorParser.spec.ts @@ -2,8 +2,8 @@ import { PreprocessorParser } from './PreprocessorParser'; import { identifier, token } from '../parser/tests/Parser.spec'; import { TokenKind } from '../lexer/TokenKind'; import { expect } from 'chai'; -import { BrsBoolean } from '../brsTypes'; import { BrightScriptChunk } from './Chunk'; +import { createToken } from '../astUtils/creators'; describe('preprocessor parser', () => { let parser: PreprocessorParser; @@ -35,7 +35,7 @@ describe('preprocessor parser', () => { token(TokenKind.HashConst, '#const'), identifier('foo'), token(TokenKind.Equal, '='), - token(TokenKind.True, 'true', BrsBoolean.True), + createToken(TokenKind.True, 'true'), token(TokenKind.Newline, '\n'), token(TokenKind.Eof, '\0') ]); diff --git a/src/types/ArrayType.ts b/src/types/ArrayType.ts index 3988c6d41..f86c1d3c2 100644 --- a/src/types/ArrayType.ts +++ b/src/types/ArrayType.ts @@ -1,13 +1,13 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; -export class ArrayType implements BrsType { - constructor(...innerTypes: BrsType[]) { +export class ArrayType implements BscType { + constructor(...innerTypes: BscType[]) { this.innerTypes = innerTypes; } - public innerTypes: BrsType[] = []; + public innerTypes: BscType[] = []; - public isAssignableTo(targetType: BrsType) { + public isAssignableTo(targetType: BscType) { if (targetType instanceof DynamicType) { return true; } else if (!(targetType instanceof ArrayType)) { @@ -30,7 +30,7 @@ export class ArrayType implements BrsType { return true; } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { return this.isAssignableTo(targetType); } diff --git a/src/types/BooleanType.ts b/src/types/BooleanType.ts index dc03c1ebd..c1e3bedaa 100644 --- a/src/types/BooleanType.ts +++ b/src/types/BooleanType.ts @@ -1,15 +1,15 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; -export class BooleanType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class BooleanType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof BooleanType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { return this.isAssignableTo(targetType); } diff --git a/src/types/BrsType.ts b/src/types/BrsType.ts deleted file mode 100644 index 0916093a5..000000000 --- a/src/types/BrsType.ts +++ /dev/null @@ -1,5 +0,0 @@ -export interface BrsType { - isAssignableTo(targetType: BrsType): boolean; - isConvertibleTo(targetType: BrsType): boolean; - toString(): string; -} diff --git a/src/types/BscType.ts b/src/types/BscType.ts new file mode 100644 index 000000000..b16b3688d --- /dev/null +++ b/src/types/BscType.ts @@ -0,0 +1,5 @@ +export interface BscType { + isAssignableTo(targetType: BscType): boolean; + isConvertibleTo(targetType: BscType): boolean; + toString(): string; +} diff --git a/src/types/DoubleType.ts b/src/types/DoubleType.ts index abebb6cce..6a96133d6 100644 --- a/src/types/DoubleType.ts +++ b/src/types/DoubleType.ts @@ -1,18 +1,18 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; import { FloatType } from './FloatType'; import { IntegerType } from './IntegerType'; import { LongIntegerType } from './LongIntegerType'; -export class DoubleType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class DoubleType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof DoubleType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { if ( targetType instanceof DynamicType || targetType instanceof IntegerType || diff --git a/src/types/DynamicType.ts b/src/types/DynamicType.ts index 45c085b71..ccb5970e8 100644 --- a/src/types/DynamicType.ts +++ b/src/types/DynamicType.ts @@ -1,7 +1,7 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; -export class DynamicType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class DynamicType implements BscType { + public isAssignableTo(targetType: BscType) { //everything can be dynamic, so as long as a type is provided, this is true return !!targetType; } @@ -10,7 +10,7 @@ export class DynamicType implements BrsType { * The dynamic type is convertible to everything. * @param targetType */ - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { //everything can be dynamic, so as long as a type is provided, this is true return !!targetType; } diff --git a/src/types/FloatType.ts b/src/types/FloatType.ts index 945b5671c..28c5bbf53 100644 --- a/src/types/FloatType.ts +++ b/src/types/FloatType.ts @@ -1,18 +1,18 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DoubleType } from './DoubleType'; import { DynamicType } from './DynamicType'; import { IntegerType } from './IntegerType'; import { LongIntegerType } from './LongIntegerType'; -export class FloatType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class FloatType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof FloatType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { if ( targetType instanceof DynamicType || targetType instanceof IntegerType || diff --git a/src/types/FunctionType.ts b/src/types/FunctionType.ts index 079373086..54e4baddd 100644 --- a/src/types/FunctionType.ts +++ b/src/types/FunctionType.ts @@ -1,9 +1,9 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; -export class FunctionType implements BrsType { +export class FunctionType implements BscType { constructor( - public returnType: BrsType + public returnType: BscType ) { } @@ -18,14 +18,14 @@ export class FunctionType implements BrsType { */ public isSub = false; - public params = [] as Array<{ name: string; type: BrsType; isRequired: boolean }>; + public params = [] as Array<{ name: string; type: BscType; isRequired: boolean }>; public setName(name: string) { this.name = name; return this; } - public addParameter(name: string, type: BrsType, isRequired: boolean) { + public addParameter(name: string, type: BscType, isRequired: boolean) { this.params.push({ name: name, type: type, @@ -34,7 +34,7 @@ export class FunctionType implements BrsType { return this; } - public isAssignableTo(targetType: BrsType) { + public isAssignableTo(targetType: BscType) { if (targetType instanceof DynamicType) { return true; } else if (targetType instanceof FunctionType) { @@ -60,7 +60,7 @@ export class FunctionType implements BrsType { } } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { return this.isAssignableTo(targetType); } diff --git a/src/types/IntegerType.ts b/src/types/IntegerType.ts index de0d1cd29..344cdbda4 100644 --- a/src/types/IntegerType.ts +++ b/src/types/IntegerType.ts @@ -1,18 +1,18 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DoubleType } from './DoubleType'; import { DynamicType } from './DynamicType'; import { FloatType } from './FloatType'; import { LongIntegerType } from './LongIntegerType'; -export class IntegerType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class IntegerType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof IntegerType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { if ( targetType instanceof DynamicType || targetType instanceof IntegerType || diff --git a/src/types/InterfaceType.ts b/src/types/InterfaceType.ts index b4922a506..63f850609 100644 --- a/src/types/InterfaceType.ts +++ b/src/types/InterfaceType.ts @@ -1,15 +1,15 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; -export class InterfaceType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class InterfaceType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof InterfaceType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { return this.isAssignableTo(targetType); } diff --git a/src/types/InvalidType.ts b/src/types/InvalidType.ts index 58cd40d41..2baed5bde 100644 --- a/src/types/InvalidType.ts +++ b/src/types/InvalidType.ts @@ -1,15 +1,15 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; -export class InvalidType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class InvalidType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof InvalidType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { return this.isAssignableTo(targetType); } diff --git a/src/types/LongIntegerType.ts b/src/types/LongIntegerType.ts index 04fe10dd7..3e7cd6c40 100644 --- a/src/types/LongIntegerType.ts +++ b/src/types/LongIntegerType.ts @@ -1,18 +1,18 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DoubleType } from './DoubleType'; import { DynamicType } from './DynamicType'; import { FloatType } from './FloatType'; import { IntegerType } from './IntegerType'; -export class LongIntegerType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class LongIntegerType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof LongIntegerType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { if ( targetType instanceof DynamicType || targetType instanceof IntegerType || diff --git a/src/types/ObjectType.ts b/src/types/ObjectType.ts index 549163331..fcdcff802 100644 --- a/src/types/ObjectType.ts +++ b/src/types/ObjectType.ts @@ -1,15 +1,15 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; -export class ObjectType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class ObjectType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof ObjectType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { return this.isAssignableTo(targetType); } diff --git a/src/types/StringType.ts b/src/types/StringType.ts index a2132d966..c107f44ee 100644 --- a/src/types/StringType.ts +++ b/src/types/StringType.ts @@ -1,15 +1,15 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; -export class StringType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class StringType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof StringType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { return this.isAssignableTo(targetType); } diff --git a/src/types/UninitializedType.ts b/src/types/UninitializedType.ts index b9dd9530f..35139d7d0 100644 --- a/src/types/UninitializedType.ts +++ b/src/types/UninitializedType.ts @@ -1,15 +1,15 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; -export class UninitializedType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class UninitializedType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof UninitializedType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { return this.isAssignableTo(targetType); } diff --git a/src/types/VoidType.ts b/src/types/VoidType.ts index 81a96c912..241d2e423 100644 --- a/src/types/VoidType.ts +++ b/src/types/VoidType.ts @@ -1,15 +1,15 @@ -import { BrsType } from './BrsType'; +import { BscType } from './BscType'; import { DynamicType } from './DynamicType'; -export class VoidType implements BrsType { - public isAssignableTo(targetType: BrsType) { +export class VoidType implements BscType { + public isAssignableTo(targetType: BscType) { return ( targetType instanceof VoidType || targetType instanceof DynamicType ); } - public isConvertibleTo(targetType: BrsType) { + public isConvertibleTo(targetType: BscType) { return this.isAssignableTo(targetType); } diff --git a/src/util.ts b/src/util.ts index 0a7c3c4f8..0f1bcf330 100644 --- a/src/util.ts +++ b/src/util.ts @@ -9,9 +9,8 @@ import * as xml2js from 'xml2js'; import { BsConfig } from './BsConfig'; import { DiagnosticMessages } from './DiagnosticMessages'; -import { CallableContainer, ValueKind, BsDiagnostic, FileReference, CallableContainerMap } from './interfaces'; +import { CallableContainer, BsDiagnostic, FileReference, CallableContainerMap } from './interfaces'; import { BooleanType } from './types/BooleanType'; -import { BrsType } from './types/BrsType'; import { DoubleType } from './types/DoubleType'; import { DynamicType } from './types/DynamicType'; import { FloatType } from './types/FloatType'; @@ -21,7 +20,6 @@ import { InvalidType } from './types/InvalidType'; import { LongIntegerType } from './types/LongIntegerType'; import { ObjectType } from './types/ObjectType'; import { StringType } from './types/StringType'; -import { UninitializedType } from './types/UninitializedType'; import { VoidType } from './types/VoidType'; import { ParseMode } from './parser/Parser'; import { DottedGetExpression, VariableExpression } from './parser/Expression'; @@ -335,38 +333,6 @@ export class Util { }); } - public valueKindToBrsType(kind: ValueKind): BrsType { - switch (kind) { - case ValueKind.Boolean: - return new BooleanType(); - //TODO refine the function type on the outside (I don't think this ValueKind is actually returned) - case ValueKind.Callable: - return new FunctionType(new VoidType()); - case ValueKind.Double: - return new DoubleType(); - case ValueKind.Dynamic: - return new DynamicType(); - case ValueKind.Float: - return new FloatType(); - case ValueKind.Int32: - return new IntegerType(); - case ValueKind.Int64: - return new LongIntegerType(); - case ValueKind.Invalid: - return new InvalidType(); - case ValueKind.Object: - return new ObjectType(); - case ValueKind.String: - return new StringType(); - case ValueKind.Uninitialized: - return new UninitializedType(); - case ValueKind.Void: - return new VoidType(); - default: - return undefined; - } - } - /** * Given a list of callables as a dictionary indexed by their full name (namespace included, transpiled to underscore-separated. * @param callables @@ -999,6 +965,47 @@ export class Util { } return result; } + + /** + * Convert a token into a BscType + */ + public tokenToBscType(token: Token) { + // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check + switch (token.kind) { + case TokenKind.Boolean: + return new BooleanType(); + case TokenKind.Double: + case TokenKind.DoubleLiteral: + return new DoubleType(); + case TokenKind.Dynamic: + return new DynamicType(); + case TokenKind.Float: + case TokenKind.FloatLiteral: + return new FloatType(); + case TokenKind.Function: + //TODO should there be a more generic function type without a signature that's assignable to all other function types? + return new FunctionType(new DynamicType()); + case TokenKind.Integer: + case TokenKind.IntegerLiteral: + return new IntegerType(); + case TokenKind.Invalid: + return new InvalidType(); + case TokenKind.LongInteger: + case TokenKind.LongIntegerLiteral: + return new LongIntegerType(); + case TokenKind.Object: + return new ObjectType(); + case TokenKind.String: + case TokenKind.StringLiteral: + case TokenKind.TemplateStringExpressionBegin: + case TokenKind.TemplateStringExpressionEnd: + case TokenKind.TemplateStringQuasi: + return new StringType(); + case TokenKind.Void: + return new VoidType(); + } + + } } /** From 990ad1810012ebbbf0c9e42eb771f45e1612fb20 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Mon, 5 Oct 2020 22:34:28 -0400 Subject: [PATCH 2/9] Fix FunctionParameterExpression type bug. --- src/parser/Expression.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/parser/Expression.ts b/src/parser/Expression.ts index 50c180c3c..f1c05a563 100644 --- a/src/parser/Expression.ts +++ b/src/parser/Expression.ts @@ -239,7 +239,11 @@ export class FunctionParameterExpression extends Expression { public asToken?: Token ) { super(); - this.type = util.tokenToBscType(typeToken) ?? new DynamicType(); + if (typeToken) { + this.type = util.tokenToBscType(typeToken); + } else { + this.type = new DynamicType(); + } } public type: BscType; From 509ed1a6e4264d915662126d0760b3021c7acfb4 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Mon, 5 Oct 2020 22:48:40 -0400 Subject: [PATCH 3/9] Fix bug with template string --- src/parser/Expression.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/parser/Expression.ts b/src/parser/Expression.ts index f1c05a563..3cec5f803 100644 --- a/src/parser/Expression.ts +++ b/src/parser/Expression.ts @@ -8,7 +8,7 @@ import { TranspileState } from './TranspileState'; import { ParseMode } from './Parser'; import * as fileUrl from 'file-url'; import { walk, InternalWalkMode, WalkOptions, WalkVisitor } from '../astUtils/visitors'; -import { isCommentStatement, isEscapedCharCodeLiteralExpression, isLiteralExpression, isStringType, isVariableExpression } from '../astUtils/reflection'; +import { isCommentStatement, isEscapedCharCodeLiteralExpression, isLiteralExpression, isLiteralString, isStringType, isTemplateStringQuasiExpression, isVariableExpression } from '../astUtils/reflection'; import { BscType } from '../types/BscType'; import { DynamicType } from '../types/DynamicType'; @@ -474,7 +474,11 @@ export class LiteralExpression extends Expression { transpile(state: TranspileState) { let text: string; - if (isStringType(this.type)) { + if (this.token.kind === TokenKind.TemplateStringQuasi) { + //wrap quasis with quotes (and escape inner quotemarks) + text = `"${this.token.text.replace(/"/g, '""')}"`; + + } else if (isStringType(this.type)) { //escape quote marks with another quote mark //TODO do we need to do this anymore? If not, remove the above and below comments //`"${this.value.value.replace(/"/g, '""')}"`; @@ -1005,9 +1009,14 @@ export class TemplateStringQuasiExpression extends Expression { let result = []; let plus = ''; for (let expression of this.expressions) { + //skip empty quasi strings + if (expression.token.kind === TokenKind.TemplateStringQuasi && expression.token.text === '') { + continue; + } //skip empty strings //TODO what does an empty string literal expression look like? - if ((expression as LiteralExpression).token.text === '""' && skipEmptyStrings === true) { + debugger; + if (expression.token.text === '' && skipEmptyStrings === true) { continue; } result.push( From ebe8693eb21f5ca7c576a9402728e190595b4199 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Tue, 6 Oct 2020 15:02:16 -0400 Subject: [PATCH 4/9] Fix remaining bugs in unit tests. --- src/astUtils/creators.ts | 4 +- src/astUtils/reflection.spec.ts | 2 +- src/astUtils/visitors.spec.ts | 1 - src/files/BrsFile.spec.ts | 21 +++++---- src/files/BrsFile.ts | 15 ++++++- src/lexer/Lexer.spec.ts | 44 ++++++++++++------- src/parser/Expression.ts | 17 +++---- src/parser/Parser.ts | 29 ++++++------ src/parser/Statement.ts | 34 +++++++------- src/parser/tests/controlFlow/For.spec.ts | 19 ++++---- .../TemplateStringExpression.spec.ts | 2 +- src/parser/tests/statement/Function.spec.ts | 2 +- .../tests/statement/LibraryStatement.spec.ts | 4 +- src/parser/tests/statement/Misc.spec.ts | 5 ++- src/util.ts | 25 +++++++++++ 15 files changed, 131 insertions(+), 93 deletions(-) diff --git a/src/astUtils/creators.ts b/src/astUtils/creators.ts index cc1fcb71d..6628b50f6 100644 --- a/src/astUtils/creators.ts +++ b/src/astUtils/creators.ts @@ -33,8 +33,8 @@ export function createIntegerLiteral(value: string, range?: Range) { export function createFloatLiteral(value: string, range?: Range) { return new LiteralExpression(createToken(TokenKind.FloatLiteral, value, range)); } -export function createInvalidLiteral(range?: Range) { - return new LiteralExpression(createToken(TokenKind.Invalid, null, range)); +export function createInvalidLiteral(value?: string, range?: Range) { + return new LiteralExpression(createToken(TokenKind.Invalid, value, range)); } export function createBooleanLiteral(value: 'true' | 'false', range?: Range) { return new LiteralExpression(createToken(value === 'true' ? TokenKind.True : TokenKind.False, value, range)); diff --git a/src/astUtils/reflection.spec.ts b/src/astUtils/reflection.spec.ts index f28e3776d..7fbeebde8 100644 --- a/src/astUtils/reflection.spec.ts +++ b/src/astUtils/reflection.spec.ts @@ -40,7 +40,7 @@ describe('reflection', () => { const returns = new ReturnStatement({ return: token }); const ends = new EndStatement({ end: token }); const stop = new StopStatement({ stop: token }); - const fors = new ForStatement({ for: token, to: token, endFor: token }, assignment, expr, expr, block); + const fors = new ForStatement(token, assignment, token, expr, block, token, token, expr); const foreach = new ForEachStatement({ forEach: token, in: token, endFor: token }, token, expr, block); const whiles = new WhileStatement({ while: token, endWhile: token }, expr, block); const dottedSet = new DottedSetStatement(expr, ident, expr); diff --git a/src/astUtils/visitors.spec.ts b/src/astUtils/visitors.spec.ts index 93165f9da..81bcde2ea 100644 --- a/src/astUtils/visitors.spec.ts +++ b/src/astUtils/visitors.spec.ts @@ -289,7 +289,6 @@ describe('astUtils visitors', () => { 'ExpressionStatement:1:CallExpression', // exec("e", ) 'ExpressionStatement:1:VariableExpression', // exec("e", ()) 'ForStatement:1:LiteralExpression', // for i = <1> to 10 - 'ForStatement:1:LiteralExpression', // for i = 1 to 10 'AssignmentStatement:2:LiteralExpression', // for to 10 'ForEachStatement:1:VariableExpression', // for each n in 'WhileStatement:1:BinaryExpression', // while diff --git a/src/files/BrsFile.spec.ts b/src/files/BrsFile.spec.ts index ec8f39c18..7362794cb 100644 --- a/src/files/BrsFile.spec.ts +++ b/src/files/BrsFile.spec.ts @@ -1,8 +1,7 @@ import { assert, expect } from 'chai'; import * as sinonImport from 'sinon'; import { CompletionItemKind, Position, Range } from 'vscode-languageserver'; - -import { Callable, CallableArg, CommentFlag, BsDiagnostic, VariableDeclaration } from '../interfaces'; +import { Callable, CommentFlag, BsDiagnostic, VariableDeclaration } from '../interfaces'; import { Program } from '../Program'; import { BooleanType } from '../types/BooleanType'; import { DynamicType } from '../types/DynamicType'; @@ -14,7 +13,7 @@ import { SourceMapConsumer } from 'source-map'; import { TokenKind, Lexer, Keywords } from '../lexer'; import { DiagnosticMessages } from '../DiagnosticMessages'; import { StandardizedFileEntry } from 'roku-deploy'; -import { standardizePath as s } from '../util'; +import util, { standardizePath as s } from '../util'; import PluginInterface from '../PluginInterface'; import { loadPlugins } from '..'; @@ -1154,20 +1153,20 @@ describe('BrsFile', () => { end function `); expect(file.functionCalls.length).to.equal(1); - let args = file.functionCalls[0].args; - expect(args.length).to.equal(3); - expect(args[0]).deep.include({ + + expect(file.functionCalls[0].args).to.eql([{ type: new StringType(), + range: util.createRange(2, 32, 2, 38), text: '"name"' - }); - expect(args[1]).deep.include({ + }, { type: new IntegerType(), + range: util.createRange(2, 40, 2, 42), text: '12' - }); - expect(args[2]).deep.include({ + }, { type: new BooleanType(), + range: util.createRange(2, 44, 2, 48), text: 'true' - }); + }]); }); it('finds function calls nested inside statements', async () => { diff --git a/src/files/BrsFile.ts b/src/files/BrsFile.ts index 4c7f40f28..89f435303 100644 --- a/src/files/BrsFile.ts +++ b/src/files/BrsFile.ts @@ -621,14 +621,24 @@ export class BrsFile { let args = [] as CallableArg[]; //TODO convert if stmts to use instanceof instead for (let arg of expression.args as any) { - //is variable being passed into argument - if (arg.name) { + + //is a literal parameter value + if (isLiteralExpression(arg)) { + args.push({ + range: arg.range, + type: arg.type, + text: arg.token.text + }); + + //is variable being passed into argument + } else if (arg.name) { args.push({ range: arg.range, //TODO - look up the data type of the actual variable type: new DynamicType(), text: arg.name.text }); + } else if (arg.value) { let text = ''; /* istanbul ignore next: TODO figure out why value is undefined sometimes */ @@ -646,6 +656,7 @@ export class BrsFile { callableArg.text = '"' + callableArg.text + '"'; } args.push(callableArg); + } else { args.push({ range: arg.range, diff --git a/src/lexer/Lexer.spec.ts b/src/lexer/Lexer.spec.ts index ebcab9534..c8148f635 100644 --- a/src/lexer/Lexer.spec.ts +++ b/src/lexer/Lexer.spec.ts @@ -461,11 +461,16 @@ describe('lexer', () => { TokenKind.BackTick, TokenKind.Eof ]); - expect(tokens[1].text).to.eql('"the cat says "'); - expect(tokens[2].text).to.eql('\\`'); - expect(tokens[3].text).to.eql('"meow"'); - expect(tokens[4].text).to.eql('\\`'); - expect(tokens[5].text).to.eql('" a lot"'); + expect(tokens.map(x => x.text)).to.eql([ + '`', + 'the cat says ', + '\\`', + 'meow', + '\\`', + ' a lot', + '`', + '' //EOF + ]); }); it('produces template string literal tokens', () => { @@ -476,7 +481,7 @@ describe('lexer', () => { TokenKind.BackTick, TokenKind.Eof ]); - expect(tokens[1].text).to.deep.equal('"hello world"'); + expect(tokens[1].text).to.deep.equal('hello world'); }); it('collects quasis outside and expressions inside of template strings', () => { @@ -641,9 +646,16 @@ describe('lexer', () => { TokenKind.BackTick, TokenKind.Eof ]); - expect(tokens[1].text).to.eql(`"multi-line"`); - expect(tokens[2].text).to.equal('\n'); - expect(tokens[2].text).to.equal('\n'); + expect(tokens.map(x => x.text)).to.eql([ + '`', + 'multi-line', + '\n', + '', + '\n', + '', + '`', + '' //EOF + ]); }); it('maintains proper line/column locations for multiline strings', () => { @@ -717,31 +729,31 @@ describe('lexer', () => { it('respects \'#\' suffix', () => { let d = Lexer.scan('123#').tokens[0]; expect(d.kind).to.equal(TokenKind.DoubleLiteral); - expect(d.text).to.eql(123); + expect(d.text).to.eql('123#'); }); it('forces literals >= 10 digits into doubles', () => { let d = Lexer.scan('0000000005').tokens[0]; expect(d.kind).to.equal(TokenKind.DoubleLiteral); - expect(d.text).to.eql(5); + expect(d.text).to.eql('0000000005'); }); it('forces literals with \'D\' in exponent into doubles', () => { let d = Lexer.scan('2.5d3').tokens[0]; expect(d.kind).to.equal(TokenKind.DoubleLiteral); - expect(d.text).to.eql(2500); + expect(d.text).to.eql('2.5d3'); }); it('allows digits before `.` to be elided', () => { let f = Lexer.scan('.123#').tokens[0]; expect(f.kind).to.equal(TokenKind.DoubleLiteral); - expect(f.text).to.eql(0.123); + expect(f.text).to.eql('.123#'); }); it('allows digits after `.` to be elided', () => { let f = Lexer.scan('12.#').tokens[0]; expect(f.kind).to.equal(TokenKind.DoubleLiteral); - expect(f.text).to.eql('12'); + expect(f.text).to.eql('12.#'); }); }); @@ -795,7 +807,7 @@ describe('lexer', () => { it('forces literals with \'&\' suffix into Int64s', () => { let li = Lexer.scan('123&').tokens[0]; expect(li.kind).to.equal(TokenKind.LongIntegerLiteral); - expect(li.text).to.deep.equal('123'); + expect(li.text).to.deep.equal('123&'); }); }); @@ -803,7 +815,7 @@ describe('lexer', () => { it('supports hexadecimal literals', () => { let i = Lexer.scan('&hFf').tokens[0]; expect(i.kind).to.equal(TokenKind.IntegerLiteral); - expect(i.text).to.deep.equal('255'); + expect(i.text).to.deep.equal('&hFf'); }); it('falls back to a regular integer', () => { diff --git a/src/parser/Expression.ts b/src/parser/Expression.ts index 3cec5f803..ddf834560 100644 --- a/src/parser/Expression.ts +++ b/src/parser/Expression.ts @@ -11,6 +11,7 @@ import { walk, InternalWalkMode, WalkOptions, WalkVisitor } from '../astUtils/vi import { isCommentStatement, isEscapedCharCodeLiteralExpression, isLiteralExpression, isLiteralString, isStringType, isTemplateStringQuasiExpression, isVariableExpression } from '../astUtils/reflection'; import { BscType } from '../types/BscType'; import { DynamicType } from '../types/DynamicType'; +import { VoidType } from '../types/VoidType'; export type ExpressionVisitor = (expression: Expression, parent: Expression) => void; @@ -127,6 +128,10 @@ export class FunctionExpression extends Expression { super(); if (this.returnTypeToken) { this.returnType = util.tokenToBscType(this.returnTypeToken); + } else if (this.functionType.text.toLowerCase() === 'sub') { + this.returnType = new VoidType(); + } else { + this.returnType = new DynamicType(); } } @@ -479,10 +484,11 @@ export class LiteralExpression extends Expression { text = `"${this.token.text.replace(/"/g, '""')}"`; } else if (isStringType(this.type)) { - //escape quote marks with another quote mark - //TODO do we need to do this anymore? If not, remove the above and below comments - //`"${this.value.value.replace(/"/g, '""')}"`; text = this.token.text; + //add trailing quotemark if it's missing. We will have already generated a diagnostic for this. + if (text.endsWith('"') === false) { + text += '"'; + } } else { text = this.token.text; } @@ -1009,13 +1015,8 @@ export class TemplateStringQuasiExpression extends Expression { let result = []; let plus = ''; for (let expression of this.expressions) { - //skip empty quasi strings - if (expression.token.kind === TokenKind.TemplateStringQuasi && expression.token.text === '') { - continue; - } //skip empty strings //TODO what does an empty string literal expression look like? - debugger; if (expression.token.text === '' && skipEmptyStrings === true) { continue; } diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts index dd0ef005a..8e6fe0056 100644 --- a/src/parser/Parser.ts +++ b/src/parser/Parser.ts @@ -914,19 +914,18 @@ export class Parser { } private forStatement(): ForStatement { - const forKeyword = this.advance(); + const forToken = this.advance(); const initializer = this.assignment(TokenKind.To); - const to = this.advance(); + const toToken = this.advance(); const finalValue = this.expression(); - let increment: Expression | undefined; - let step: Token | undefined; + let incrementExpression: Expression | undefined; + let stepToken: Token | undefined; if (this.check(TokenKind.Step)) { - step = this.advance(); - increment = this.expression(); + stepToken = this.advance(); + incrementExpression = this.expression(); } else { // BrightScript for/to/step loops default to a step of 1 if no `step` is provided - increment = new LiteralExpression(this.peek()); } while (this.match(TokenKind.Newline)) { @@ -940,22 +939,20 @@ export class Parser { }); throw this.lastDiagnosticAsError(); } - let endFor = this.advance(); + let endForToken = this.advance(); while (this.match(TokenKind.Newline)) { } // WARNING: BrightScript doesn't delete the loop initial value after a for/to loop! It just // stays around in scope with whatever value it was when the loop exited. return new ForStatement( - { - for: forKeyword, - to: to, - step: step, - endFor: endFor - }, + forToken, initializer, + toToken, finalValue, - increment, - body + body, + endForToken, + stepToken, + incrementExpression ); } diff --git a/src/parser/Statement.ts b/src/parser/Statement.ts index 1bde080e0..de4135a3c 100644 --- a/src/parser/Statement.ts +++ b/src/parser/Statement.ts @@ -719,19 +719,17 @@ export class StopStatement extends Statement { export class ForStatement extends Statement { constructor( - readonly tokens: { - for: Token; - to: Token; - step?: Token; - endFor: Token; - }, - readonly counterDeclaration: AssignmentStatement, - readonly finalValue: Expression, - readonly increment: Expression, - readonly body: Block + public forToken: Token, + public counterDeclaration: AssignmentStatement, + public toToken: Token, + public finalValue: Expression, + public body: Block, + public endForToken: Token, + public stepToken?: Token, + public increment?: Expression ) { super(); - this.range = util.createRangeFromPositions(this.tokens.for.range.start, this.tokens.endFor.range.end); + this.range = util.createRangeFromPositions(this.forToken.range.start, this.endForToken.range.end); } public readonly range: Range; @@ -740,7 +738,7 @@ export class ForStatement extends Statement { let result = []; //for result.push( - new SourceNode(this.tokens.for.range.start.line + 1, this.tokens.for.range.start.character, state.pathAbsolute, 'for'), + new SourceNode(this.forToken.range.start.line + 1, this.forToken.range.start.character, state.pathAbsolute, 'for'), ' ' ); //i=1 @@ -750,16 +748,16 @@ export class ForStatement extends Statement { ); //to result.push( - new SourceNode(this.tokens.to.range.start.line + 1, this.tokens.to.range.start.character, state.pathAbsolute, 'to'), + new SourceNode(this.toToken.range.start.line + 1, this.toToken.range.start.character, state.pathAbsolute, 'to'), ' ' ); //final value result.push(this.finalValue.transpile(state)); //step - if (this.tokens.step) { + if (this.stepToken) { result.push( ' ', - new SourceNode(this.tokens.step.range.start.line + 1, this.tokens.step.range.start.character, state.pathAbsolute, 'step'), + new SourceNode(this.stepToken.range.start.line + 1, this.stepToken.range.start.character, state.pathAbsolute, 'step'), ' ', this.increment.transpile(state) ); @@ -774,7 +772,7 @@ export class ForStatement extends Statement { //end for result.push( state.indent(), - new SourceNode(this.tokens.endFor.range.start.line + 1, this.tokens.endFor.range.start.character, state.pathAbsolute, 'end for') + new SourceNode(this.endForToken.range.start.line + 1, this.endForToken.range.start.character, state.pathAbsolute, 'end for') ); return result; @@ -1566,9 +1564,9 @@ export class ClassMethodStatement extends FunctionStatement { //if there is no initial value, set the initial value to `invalid` newStatements.push( new AssignmentStatement( - createToken(TokenKind.Equal, '='), + createToken(TokenKind.Equal, '=', field.name.range), thisQualifiedName, - createInvalidLiteral(), + createInvalidLiteral('invalid', field.name.range), this.func ) ); diff --git a/src/parser/tests/controlFlow/For.spec.ts b/src/parser/tests/controlFlow/For.spec.ts index 132c0e850..df747c4cf 100644 --- a/src/parser/tests/controlFlow/For.spec.ts +++ b/src/parser/tests/controlFlow/For.spec.ts @@ -5,6 +5,7 @@ import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; import { createToken } from '../../../astUtils/creators'; +import { ForStatement, LiteralExpression } from '../..'; describe('parser for loops', () => { it('accepts a \'step\' clause', () => { @@ -24,14 +25,13 @@ describe('parser for loops', () => { EOF ]) as any; - expect(diagnostics).to.be.lengthOf(0); - expect(statements).to.be.length.greaterThan(0); - expect(statements[0]).to.exist; - expect(statements[0].increment).to.exist; - expect(statements[0].increment.value).to.include(new Int32(2)); + const statement = statements[0] as ForStatement; + expect(diagnostics[0]?.message).not.to.exist; + expect(statement.increment).to.be.instanceof(LiteralExpression); + expect((statement.increment as LiteralExpression).token.text).to.equal('2'); }); - it('defaults a missing \'step\' clause to \'1\'', () => { + it('supports omitted \'step\' clause', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.For, 'for'), identifier('i'), @@ -46,11 +46,8 @@ describe('parser for loops', () => { EOF ]) as any; - expect(diagnostics).to.be.lengthOf(0); - expect(statements).to.be.length.greaterThan(0); - expect(statements[0]).to.exist; - expect(statements[0].increment).to.exist; - expect(statements[0].increment.value).to.include(new Int32(1)); + expect(diagnostics[0]?.message).not.to.exist; + expect((statements[0] as ForStatement).increment).not.to.exist; }); it('allows \'next\' to terminate loop', () => { diff --git a/src/parser/tests/expression/TemplateStringExpression.spec.ts b/src/parser/tests/expression/TemplateStringExpression.spec.ts index ba3f5e278..ade84332a 100644 --- a/src/parser/tests/expression/TemplateStringExpression.spec.ts +++ b/src/parser/tests/expression/TemplateStringExpression.spec.ts @@ -185,7 +185,7 @@ describe('TemplateStringExpression', () => { }); describe('tagged template strings', () => { - it('properly transpiles', async () => { + it('properly transpiles with escaped characters and quasis', async () => { await testTranspile(` function zombify(strings, values) end function diff --git a/src/parser/tests/statement/Function.spec.ts b/src/parser/tests/statement/Function.spec.ts index 805e6a1c4..78cd7d8b0 100644 --- a/src/parser/tests/statement/Function.spec.ts +++ b/src/parser/tests/statement/Function.spec.ts @@ -298,7 +298,7 @@ describe('parser', () => { EOF ]); - expect(diagnostics).to.be.lengthOf(0); + expect(diagnostics[0]?.message).not.to.exist; expect(statements).to.length.greaterThan(0); }); diff --git a/src/parser/tests/statement/LibraryStatement.spec.ts b/src/parser/tests/statement/LibraryStatement.spec.ts index 2c8b90b89..e1fff4143 100644 --- a/src/parser/tests/statement/LibraryStatement.spec.ts +++ b/src/parser/tests/statement/LibraryStatement.spec.ts @@ -59,9 +59,7 @@ describe('parser library statements', () => { `); const { statements, diagnostics } = Parser.parse(tokens) as any; //make sure the assignment is present in the function body - expect(statements[0].func.body.statements[0].value.elements[0].key.value).to.equal( - 'library' - ); + expect(statements[0].func.body.statements[0].value.elements[0].keyToken.text).to.equal('library'); expect(diagnostics).to.be.lengthOf(0); }); diff --git a/src/parser/tests/statement/Misc.spec.ts b/src/parser/tests/statement/Misc.spec.ts index eef6df469..e23864ca3 100644 --- a/src/parser/tests/statement/Misc.spec.ts +++ b/src/parser/tests/statement/Misc.spec.ts @@ -3,6 +3,7 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; import { Lexer, DisallowedLocalIdentifiersText, TokenKind } from '../../../lexer'; import { Range } from 'vscode-languageserver'; +import { AAMemberExpression } from '../../Expression'; describe('parser', () => { describe('`end` keyword', () => { @@ -274,8 +275,8 @@ describe('parser', () => { end function `); let { statements, diagnostics } = Parser.parse(tokens); + let element = ((statements as any)[0].func.body.statements[0].value.elements[0] as AAMemberExpression); expect(diagnostics[0]?.message).not.to.exist; - expect((statements[0] as any).func.body.statements[0].value.elements[0].keyToken.text).to.equal('"has-second-layer"'); - expect((statements[0] as any).func.body.statements[0].value.elements[0].key.value).to.equal('has-second-layer'); + expect(element.keyToken.text).to.equal('"has-second-layer"'); }); }); diff --git a/src/util.ts b/src/util.ts index 0f1bcf330..000328792 100644 --- a/src/util.ts +++ b/src/util.ts @@ -973,6 +973,8 @@ export class Util { // eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check switch (token.kind) { case TokenKind.Boolean: + case TokenKind.True: + case TokenKind.False: return new BooleanType(); case TokenKind.Double: case TokenKind.DoubleLiteral: @@ -1003,6 +1005,29 @@ export class Util { return new StringType(); case TokenKind.Void: return new VoidType(); + case TokenKind.Identifier: + switch (token.text.toLowerCase()) { + case 'boolean': + return new BooleanType(); + case 'double': + return new DoubleType(); + case 'float': + return new FloatType(); + case 'function': + return new FunctionType(new DynamicType()); + case 'integer': + return new IntegerType(); + case 'invalid': + return new InvalidType(); + case 'longinteger': + return new LongIntegerType(); + case 'object': + return new ObjectType(); + case 'string': + return new StringType(); + case 'void': + return new VoidType(); + } } } From dd61fcfcbdb6508a64cb20f9c1eab326ddeef2af Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Tue, 6 Oct 2020 15:04:04 -0400 Subject: [PATCH 5/9] Fix tsc "unused variable" errors. --- src/parser/Expression.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parser/Expression.ts b/src/parser/Expression.ts index ddf834560..6fbfa6848 100644 --- a/src/parser/Expression.ts +++ b/src/parser/Expression.ts @@ -8,7 +8,7 @@ import { TranspileState } from './TranspileState'; import { ParseMode } from './Parser'; import * as fileUrl from 'file-url'; import { walk, InternalWalkMode, WalkOptions, WalkVisitor } from '../astUtils/visitors'; -import { isCommentStatement, isEscapedCharCodeLiteralExpression, isLiteralExpression, isLiteralString, isStringType, isTemplateStringQuasiExpression, isVariableExpression } from '../astUtils/reflection'; +import { isCommentStatement, isEscapedCharCodeLiteralExpression, isLiteralExpression, isStringType, isVariableExpression } from '../astUtils/reflection'; import { BscType } from '../types/BscType'; import { DynamicType } from '../types/DynamicType'; import { VoidType } from '../types/VoidType'; From 2e2b09375ee8177fb03d9e115021ac200fe6d595 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Tue, 6 Oct 2020 22:10:49 -0400 Subject: [PATCH 6/9] don't use `InterfaceType` in global callables --- src/globalCallables.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/globalCallables.ts b/src/globalCallables.ts index 0838f680c..6a257ba3d 100644 --- a/src/globalCallables.ts +++ b/src/globalCallables.ts @@ -6,7 +6,6 @@ import { DynamicType } from './types/DynamicType'; import { FloatType } from './types/FloatType'; import { FunctionType } from './types/FunctionType'; import { IntegerType } from './types/IntegerType'; -import { InterfaceType } from './types/InterfaceType'; import { ObjectType } from './types/ObjectType'; import { StringType } from './types/StringType'; import { VoidType } from './types/VoidType'; @@ -293,7 +292,7 @@ let globalUtilityFunctions = [ }, { name: 'GetInterface', shortDescription: 'Each BrightScript Component has one or more interfaces. This function returns a value of type "Interface". \nNote that generally BrightScript Components allow you to skip the interface specification. In which case, the appropriate interface within the object is used. This works as long as the function names within the interfaces are unique.', - type: new FunctionType(new InterfaceType()), + type: new FunctionType(new ObjectType()), file: globalFile, params: [{ name: 'object', @@ -305,7 +304,7 @@ let globalUtilityFunctions = [ }, { name: 'FindMemberFunction', shortDescription: 'Returns the interface from the object that provides the specified function, or invalid if not found.', - type: new FunctionType(new InterfaceType()), + type: new FunctionType(new ObjectType()), file: globalFile, params: [{ name: 'object', From aaca871ed3a3a9934229d18984cdca2180e5f8f0 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Wed, 7 Oct 2020 15:18:34 -0400 Subject: [PATCH 7/9] Optimize `isNumberType` --- src/astUtils/reflection.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/astUtils/reflection.ts b/src/astUtils/reflection.ts index 04f94c59a..e6e016ddf 100644 --- a/src/astUtils/reflection.ts +++ b/src/astUtils/reflection.ts @@ -217,13 +217,14 @@ export function isFloatType(e: any): e is FloatType { export function isDoubleType(e: any): e is DoubleType { return e?.constructor.name === DoubleType.name; } +const numberConstructorNames = [ + IntegerType.name, + LongIntegerType.name, + FloatType.name, + DoubleType.name +]; export function isNumberType(e: any): e is IntegerType | LongIntegerType | FloatType | DoubleType { - return [ - IntegerType.name, - LongIntegerType.name, - FloatType.name, - DoubleType.name - ].includes(e?.constructor.name); + return numberConstructorNames.includes(e?.constructor.name); } // Literal reflection From 1ad618bc7d073b068b049e27310754c19dea67e5 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Wed, 7 Oct 2020 15:22:10 -0400 Subject: [PATCH 8/9] Replace `createToken` with `token` for most tests --- src/parser/tests/controlFlow/For.spec.ts | 14 +++---- src/parser/tests/controlFlow/If.spec.ts | 42 +++++++++---------- src/parser/tests/controlFlow/While.spec.ts | 10 ++--- src/parser/tests/expression/Additive.spec.ts | 12 +++--- .../tests/expression/ArrayLiterals.spec.ts | 42 +++++++++---------- .../AssociativeArrayLiterals.spec.ts | 32 +++++++------- src/parser/tests/expression/Boolean.spec.ts | 8 ++-- src/parser/tests/expression/Call.spec.ts | 4 +- .../tests/expression/Exponential.spec.ts | 10 ++--- src/parser/tests/expression/Function.spec.ts | 30 ++++++------- src/parser/tests/expression/Indexing.spec.ts | 14 +++---- .../tests/expression/Multiplicative.spec.ts | 24 +++++------ .../tests/expression/PrefixUnary.spec.ts | 8 ++-- src/parser/tests/expression/Primary.spec.ts | 10 ++--- .../tests/expression/Relational.spec.ts | 24 +++++------ .../statement/AssignmentOperators.spec.ts | 14 +++---- .../tests/statement/Declaration.spec.ts | 6 +-- src/parser/tests/statement/Function.spec.ts | 24 +++++------ .../tests/statement/PrintStatement.spec.ts | 12 +++--- .../tests/statement/ReturnStatement.spec.ts | 2 +- src/parser/tests/statement/Set.spec.ts | 10 ++--- src/preprocessor/Preprocessor.spec.ts | 34 +++++++-------- src/preprocessor/PreprocessorParser.spec.ts | 2 +- 23 files changed, 194 insertions(+), 194 deletions(-) diff --git a/src/parser/tests/controlFlow/For.spec.ts b/src/parser/tests/controlFlow/For.spec.ts index df747c4cf..00617e80f 100644 --- a/src/parser/tests/controlFlow/For.spec.ts +++ b/src/parser/tests/controlFlow/For.spec.ts @@ -13,11 +13,11 @@ describe('parser for loops', () => { token(TokenKind.For, 'for'), identifier('i'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '0'), + token(TokenKind.IntegerLiteral, '0'), token(TokenKind.To, 'to'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.Step, 'step'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Newline, '\n'), // body would go here, but it's not necessary for this test token(TokenKind.EndFor, 'end for'), @@ -36,9 +36,9 @@ describe('parser for loops', () => { token(TokenKind.For, 'for'), identifier('i'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '0'), + token(TokenKind.IntegerLiteral, '0'), token(TokenKind.To, 'to'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.Newline, '\n'), // body would go here, but it's not necessary for this test token(TokenKind.EndFor, 'end for'), @@ -55,9 +55,9 @@ describe('parser for loops', () => { token(TokenKind.For, 'for'), identifier('i'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '0'), + token(TokenKind.IntegerLiteral, '0'), token(TokenKind.To, 'to'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.Newline, '\n'), // body would go here, but it's not necessary for this test token(TokenKind.Next, 'next'), diff --git a/src/parser/tests/controlFlow/If.spec.ts b/src/parser/tests/controlFlow/If.spec.ts index 0758e3793..f70ea4e80 100644 --- a/src/parser/tests/controlFlow/If.spec.ts +++ b/src/parser/tests/controlFlow/If.spec.ts @@ -104,13 +104,13 @@ describe('parser if statements', () => { it('parses if only', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.If, 'if'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Less, '<'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Then, 'then'), identifier('foo'), token(TokenKind.Equal, '='), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.Newline, '\n'), EOF ]); @@ -122,17 +122,17 @@ describe('parser if statements', () => { it('parses if-else', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.If, 'if'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Less, '<'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Then, 'then'), identifier('foo'), token(TokenKind.Equal, '='), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.Else, 'else'), identifier('foo'), token(TokenKind.Equal, '='), - createToken(TokenKind.False, 'true'), + token(TokenKind.False, 'true'), token(TokenKind.Newline, '\n'), EOF ]); @@ -144,25 +144,25 @@ describe('parser if statements', () => { it('parses if-elseif-else', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.If, 'if'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Less, '<'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Then, 'then'), identifier('foo'), token(TokenKind.Equal, '='), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.ElseIf, 'else if'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Then, 'then'), identifier('same'), token(TokenKind.Equal, '='), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.Else, 'else'), identifier('foo'), token(TokenKind.Equal, '='), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.Newline, '\n'), EOF ]); @@ -174,23 +174,23 @@ describe('parser if statements', () => { it('allows \'then\' to be skipped', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.If, 'if'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Less, '<'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), identifier('foo'), token(TokenKind.Equal, '='), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.ElseIf, 'else if'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), identifier('same'), token(TokenKind.Equal, '='), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.Else, 'else'), identifier('foo'), token(TokenKind.Equal, '='), - createToken(TokenKind.False, 'false'), + token(TokenKind.False, 'false'), token(TokenKind.Newline, '\n'), EOF ]); diff --git a/src/parser/tests/controlFlow/While.spec.ts b/src/parser/tests/controlFlow/While.spec.ts index 499afa0b8..8c08768d0 100644 --- a/src/parser/tests/controlFlow/While.spec.ts +++ b/src/parser/tests/controlFlow/While.spec.ts @@ -11,10 +11,10 @@ describe('parser while statements', () => { it('while without exit', () => { const { statements, diagnostics } = Parser.parse([ token(TokenKind.While, 'while'), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.Newline, '\n'), token(TokenKind.Print, 'print'), - createToken(TokenKind.StringLiteral, 'looping'), + token(TokenKind.StringLiteral, 'looping'), token(TokenKind.Newline, '\n'), token(TokenKind.EndWhile, 'end while'), EOF @@ -27,10 +27,10 @@ describe('parser while statements', () => { it('while with exit', () => { const { statements, diagnostics } = Parser.parse([ token(TokenKind.While, 'while'), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.Newline, '\n'), token(TokenKind.Print, 'print'), - createToken(TokenKind.StringLiteral, 'looping'), + token(TokenKind.StringLiteral, 'looping'), token(TokenKind.Newline, '\n'), token(TokenKind.ExitWhile, 'exit while'), token(TokenKind.Newline, '\n'), @@ -73,7 +73,7 @@ describe('parser while statements', () => { // loop body isn't significant for location tracking, so helper functions are safe identifier('Rnd'), token(TokenKind.LeftParen, '('), - createToken(TokenKind.IntegerLiteral), + token(TokenKind.IntegerLiteral), token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\n'), { diff --git a/src/parser/tests/expression/Additive.spec.ts b/src/parser/tests/expression/Additive.spec.ts index e4ad340f7..e5b0d172c 100644 --- a/src/parser/tests/expression/Additive.spec.ts +++ b/src/parser/tests/expression/Additive.spec.ts @@ -11,11 +11,11 @@ describe('parser additive expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), EOF ]); @@ -27,11 +27,11 @@ describe('parser additive expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Minus, '-'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Minus, '-'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), EOF ]); diff --git a/src/parser/tests/expression/ArrayLiterals.spec.ts b/src/parser/tests/expression/ArrayLiterals.spec.ts index 48c38b16f..230495a88 100644 --- a/src/parser/tests/expression/ArrayLiterals.spec.ts +++ b/src/parser/tests/expression/ArrayLiterals.spec.ts @@ -47,11 +47,11 @@ describe('parser array literals', () => { identifier('_'), token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -66,13 +66,13 @@ describe('parser array literals', () => { token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), token(TokenKind.Newline, '\n'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.Newline, '\n'), token(TokenKind.RightSquareBracket, ']'), EOF @@ -88,11 +88,11 @@ describe('parser array literals', () => { token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), token(TokenKind.Newline, '\n'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Newline, '\n'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Newline, '\n'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.Newline, '\n'), token(TokenKind.RightSquareBracket, ']'), EOF @@ -109,11 +109,11 @@ describe('parser array literals', () => { identifier('_'), token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -128,19 +128,19 @@ describe('parser array literals', () => { token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.Comma, ','), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '4'), + token(TokenKind.IntegerLiteral, '4'), token(TokenKind.Comma, ','), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.Comma, ','), - createToken(TokenKind.IntegerLiteral, '6'), + token(TokenKind.IntegerLiteral, '6'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.RightSquareBracket, ']'), EOF @@ -155,12 +155,12 @@ describe('parser array literals', () => { identifier('_'), token(TokenKind.Equal, '='), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), token(TokenKind.Not, 'not'), - createToken(TokenKind.False, 'false'), + token(TokenKind.False, 'false'), token(TokenKind.RightSquareBracket, ']'), EOF ]); diff --git a/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts b/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts index 659f89785..cec470ecb 100644 --- a/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts +++ b/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts @@ -49,15 +49,15 @@ describe('parser associative array literals', () => { token(TokenKind.LeftCurlyBrace, '{'), identifier('foo'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), identifier('bar'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), identifier('baz'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.RightCurlyBrace, '}'), EOF ]); @@ -74,17 +74,17 @@ describe('parser associative array literals', () => { token(TokenKind.Newline, '\n'), identifier('foo'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), identifier('bar'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), identifier('baz'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.Newline, '\n'), token(TokenKind.RightCurlyBrace, '}'), EOF @@ -102,15 +102,15 @@ describe('parser associative array literals', () => { token(TokenKind.Newline, '\n'), identifier('foo'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Newline, '\n'), identifier('bar'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Newline, '\n'), identifier('baz'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.Newline, '\n'), token(TokenKind.RightCurlyBrace, '}'), EOF @@ -133,7 +133,7 @@ describe('parser associative array literals', () => { token(TokenKind.LeftCurlyBrace, '{'), identifier('name'), token(TokenKind.Colon, ':'), - createToken(TokenKind.StringLiteral, 'Bob'), + token(TokenKind.StringLiteral, 'Bob'), token(TokenKind.Colon, ':'), token(TokenKind.Colon, ':'), token(TokenKind.Colon, ':'), @@ -141,7 +141,7 @@ describe('parser associative array literals', () => { token(TokenKind.Colon, ':'), identifier('age'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '50'), + token(TokenKind.IntegerLiteral, '50'), token(TokenKind.RightCurlyBrace, '}'), token(TokenKind.Newline, '\n'), token(TokenKind.EndSub, 'end sub'), @@ -157,19 +157,19 @@ describe('parser associative array literals', () => { token(TokenKind.Equal, '='), token(TokenKind.LeftCurlyBrace, '{'), token(TokenKind.Newline, '\n'), - createToken(TokenKind.StringLiteral, 'foo'), + token(TokenKind.StringLiteral, 'foo'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), identifier('bar'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Comma, ','), token(TokenKind.Newline, '\n'), - createToken(TokenKind.StringLiteral, 'requires-hyphens'), + token(TokenKind.StringLiteral, 'requires-hyphens'), token(TokenKind.Colon, ':'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.Newline, '\n'), token(TokenKind.RightCurlyBrace, '}'), EOF diff --git a/src/parser/tests/expression/Boolean.spec.ts b/src/parser/tests/expression/Boolean.spec.ts index aad89b7b8..b49520981 100644 --- a/src/parser/tests/expression/Boolean.spec.ts +++ b/src/parser/tests/expression/Boolean.spec.ts @@ -12,9 +12,9 @@ describe('parser boolean expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.And, 'and'), - createToken(TokenKind.False, 'false'), + token(TokenKind.False, 'false'), EOF ]); @@ -26,9 +26,9 @@ describe('parser boolean expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.Or, 'or'), - createToken(TokenKind.False, 'false'), + token(TokenKind.False, 'false'), EOF ]); diff --git a/src/parser/tests/expression/Call.spec.ts b/src/parser/tests/expression/Call.spec.ts index d7fd21b22..ec2223801 100644 --- a/src/parser/tests/expression/Call.spec.ts +++ b/src/parser/tests/expression/Call.spec.ts @@ -73,9 +73,9 @@ describe('parser call expressions', () => { const { statements, diagnostics } = Parser.parse([ identifier('add'), { kind: TokenKind.LeftParen, text: '(', line: 1 }, - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), { kind: TokenKind.Comma, text: ',', line: 1 }, - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.RightParen, ')'), EOF ]) as any; diff --git a/src/parser/tests/expression/Exponential.spec.ts b/src/parser/tests/expression/Exponential.spec.ts index 3ec2803ab..5247985e0 100644 --- a/src/parser/tests/expression/Exponential.spec.ts +++ b/src/parser/tests/expression/Exponential.spec.ts @@ -11,9 +11,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Caret, '^'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), EOF ]); @@ -25,11 +25,11 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Caret, '^'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.Caret, '^'), - createToken(TokenKind.IntegerLiteral, '4'), + token(TokenKind.IntegerLiteral, '4'), EOF ]); diff --git a/src/parser/tests/expression/Function.spec.ts b/src/parser/tests/expression/Function.spec.ts index f1c609229..ddac7eadd 100644 --- a/src/parser/tests/expression/Function.spec.ts +++ b/src/parser/tests/expression/Function.spec.ts @@ -34,7 +34,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Colon, ':'), token(TokenKind.Print, 'print'), - createToken(TokenKind.StringLiteral, 'Lorem ipsum'), + token(TokenKind.StringLiteral, 'Lorem ipsum'), token(TokenKind.Colon, ':'), token(TokenKind.EndFunction, 'end function'), EOF @@ -53,7 +53,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - createToken(TokenKind.StringLiteral, 'Lorem ipsum'), + token(TokenKind.StringLiteral, 'Lorem ipsum'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndFunction, 'end function'), EOF @@ -118,19 +118,19 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.Comma, ','), identifier('b'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '4'), + token(TokenKind.IntegerLiteral, '4'), token(TokenKind.Comma, ','), identifier('c'), token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), @@ -151,7 +151,7 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.Comma, ','), @@ -160,7 +160,7 @@ describe('parser', () => { token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.RightParen, ')'), @@ -219,7 +219,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - createToken(TokenKind.StringLiteral, 'Lorem ipsum'), + token(TokenKind.StringLiteral, 'Lorem ipsum'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndSub, 'end sub'), EOF @@ -284,19 +284,19 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.Comma, ','), identifier('b'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '4'), + token(TokenKind.IntegerLiteral, '4'), token(TokenKind.Comma, ','), identifier('c'), token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), @@ -317,7 +317,7 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.Comma, ','), @@ -326,7 +326,7 @@ describe('parser', () => { token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.RightParen, ')'), @@ -353,7 +353,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - createToken(TokenKind.StringLiteral, 'I\'m a callback'), + token(TokenKind.StringLiteral, 'I\'m a callback'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndFunction, 'end function'), token(TokenKind.Newline, '\\n'), @@ -376,7 +376,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - createToken(TokenKind.StringLiteral, 'I\'m anonymous'), + token(TokenKind.StringLiteral, 'I\'m anonymous'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndFunction, 'end function'), diff --git a/src/parser/tests/expression/Indexing.spec.ts b/src/parser/tests/expression/Indexing.spec.ts index 32b61acda..2674c1816 100644 --- a/src/parser/tests/expression/Indexing.spec.ts +++ b/src/parser/tests/expression/Indexing.spec.ts @@ -31,7 +31,7 @@ describe('parser indexing', () => { token(TokenKind.Equal, '='), identifier('foo'), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -49,7 +49,7 @@ describe('parser indexing', () => { identifier('foo'), token(TokenKind.Dot, '.'), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.Integer, '2'), + token(TokenKind.Integer, '2'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -67,7 +67,7 @@ describe('parser indexing', () => { token(TokenKind.Dot, '.'), token(TokenKind.Dot, '.'), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.Integer, '2'), + token(TokenKind.Integer, '2'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -200,13 +200,13 @@ describe('parser indexing', () => { token(TokenKind.Equal, '='), identifier('foo'), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '0'), + token(TokenKind.IntegerLiteral, '0'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '6'), + token(TokenKind.IntegerLiteral, '6'), token(TokenKind.RightSquareBracket, ']'), EOF ]); @@ -223,7 +223,7 @@ describe('parser indexing', () => { token(TokenKind.Dot, '.'), identifier('bar'), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '0'), + token(TokenKind.IntegerLiteral, '0'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.Dot, '.'), identifier('baz'), diff --git a/src/parser/tests/expression/Multiplicative.spec.ts b/src/parser/tests/expression/Multiplicative.spec.ts index 3e7785d44..b704c9a9f 100644 --- a/src/parser/tests/expression/Multiplicative.spec.ts +++ b/src/parser/tests/expression/Multiplicative.spec.ts @@ -12,11 +12,11 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.FloatLiteral, '3.0'), + token(TokenKind.FloatLiteral, '3.0'), token(TokenKind.Star, '*'), - createToken(TokenKind.FloatLiteral, '5.0'), + token(TokenKind.FloatLiteral, '5.0'), token(TokenKind.Star, '*'), - createToken(TokenKind.FloatLiteral, '7.0'), + token(TokenKind.FloatLiteral, '7.0'), EOF ]); @@ -28,11 +28,11 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.FloatLiteral, '7.0'), + token(TokenKind.FloatLiteral, '7.0'), token(TokenKind.Forwardslash, '/'), - createToken(TokenKind.FloatLiteral, '5.0'), + token(TokenKind.FloatLiteral, '5.0'), token(TokenKind.Forwardslash, '/'), - createToken(TokenKind.FloatLiteral, '3.0'), + token(TokenKind.FloatLiteral, '3.0'), EOF ]); @@ -44,11 +44,11 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.FloatLiteral, '7.0'), + token(TokenKind.FloatLiteral, '7.0'), token(TokenKind.Mod, 'MOD'), - createToken(TokenKind.FloatLiteral, '5.0'), + token(TokenKind.FloatLiteral, '5.0'), token(TokenKind.Mod, 'MOD'), - createToken(TokenKind.FloatLiteral, '3.0'), + token(TokenKind.FloatLiteral, '3.0'), EOF ]); @@ -60,11 +60,11 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.FloatLiteral, '32.5'), + token(TokenKind.FloatLiteral, '32.5'), token(TokenKind.Backslash, '\\'), - createToken(TokenKind.FloatLiteral, '5.0'), + token(TokenKind.FloatLiteral, '5.0'), token(TokenKind.Backslash, '\\'), - createToken(TokenKind.FloatLiteral, '3.0'), + token(TokenKind.FloatLiteral, '3.0'), EOF ]); diff --git a/src/parser/tests/expression/PrefixUnary.spec.ts b/src/parser/tests/expression/PrefixUnary.spec.ts index 6536d5c29..d9212794f 100644 --- a/src/parser/tests/expression/PrefixUnary.spec.ts +++ b/src/parser/tests/expression/PrefixUnary.spec.ts @@ -13,7 +13,7 @@ describe('parser prefix unary expressions', () => { identifier('_'), token(TokenKind.Equal, '='), token(TokenKind.Not, 'not'), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), EOF ]); @@ -30,7 +30,7 @@ describe('parser prefix unary expressions', () => { token(TokenKind.Not, 'not'), token(TokenKind.Not, 'not'), token(TokenKind.Not, 'not'), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), EOF ]); @@ -43,7 +43,7 @@ describe('parser prefix unary expressions', () => { identifier('_'), token(TokenKind.Equal, '='), token(TokenKind.Minus, '-'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), EOF ]); @@ -60,7 +60,7 @@ describe('parser prefix unary expressions', () => { token(TokenKind.Minus, '-'), token(TokenKind.Minus, '-'), token(TokenKind.Minus, '-'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), EOF ]); diff --git a/src/parser/tests/expression/Primary.spec.ts b/src/parser/tests/expression/Primary.spec.ts index 0bdc7dd83..43dec2507 100644 --- a/src/parser/tests/expression/Primary.spec.ts +++ b/src/parser/tests/expression/Primary.spec.ts @@ -13,7 +13,7 @@ describe('parser primary expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), equals, - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), EOF ]); expect(diagnostics).to.be.lengthOf(0); @@ -25,7 +25,7 @@ describe('parser primary expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), equals, - createToken(TokenKind.StringLiteral, 'hello'), + token(TokenKind.StringLiteral, 'hello'), EOF ]); @@ -37,12 +37,12 @@ describe('parser primary expressions', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), token(TokenKind.Plus, '+'), token(TokenKind.LeftParen, '('), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), token(TokenKind.Star, '*'), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.RightParen, ')'), EOF ]); diff --git a/src/parser/tests/expression/Relational.spec.ts b/src/parser/tests/expression/Relational.spec.ts index 5c09d8a33..8d0a437ea 100644 --- a/src/parser/tests/expression/Relational.spec.ts +++ b/src/parser/tests/expression/Relational.spec.ts @@ -12,9 +12,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.Less, '<'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), EOF ]); @@ -26,9 +26,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.LessEqual, '<='), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), EOF ]); @@ -41,9 +41,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.Greater, '>'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), EOF ]); @@ -56,9 +56,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.GreaterEqual, '>='), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), EOF ]); @@ -70,9 +70,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), EOF ]); @@ -85,9 +85,9 @@ describe('parser', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.LessGreater, '<>'), - createToken(TokenKind.IntegerLiteral, '2'), + token(TokenKind.IntegerLiteral, '2'), EOF ]); diff --git a/src/parser/tests/statement/AssignmentOperators.spec.ts b/src/parser/tests/statement/AssignmentOperators.spec.ts index ce3a04c13..d51de111b 100644 --- a/src/parser/tests/statement/AssignmentOperators.spec.ts +++ b/src/parser/tests/statement/AssignmentOperators.spec.ts @@ -10,7 +10,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.PlusEqual), - createToken(TokenKind.StringLiteral, `"lorem"`), + token(TokenKind.StringLiteral, `"lorem"`), EOF ]); @@ -22,7 +22,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.MinusEqual), - createToken(TokenKind.IntegerLiteral, '1'), + token(TokenKind.IntegerLiteral, '1'), EOF ]); @@ -34,7 +34,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.StarEqual), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), EOF ]); @@ -46,7 +46,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.ForwardslashEqual), - createToken(TokenKind.IntegerLiteral, '4'), + token(TokenKind.IntegerLiteral, '4'), EOF ]); @@ -58,7 +58,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.BackslashEqual), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), EOF ]); @@ -70,7 +70,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.LeftShiftEqual), - createToken(TokenKind.IntegerLiteral, '6'), + token(TokenKind.IntegerLiteral, '6'), EOF ]); @@ -82,7 +82,7 @@ describe('parser assignment operators', () => { let { statements, diagnostics } = Parser.parse([ identifier('_'), token(TokenKind.RightShiftEqual), - createToken(TokenKind.IntegerLiteral, '7'), + token(TokenKind.IntegerLiteral, '7'), EOF ]); diff --git a/src/parser/tests/statement/Declaration.spec.ts b/src/parser/tests/statement/Declaration.spec.ts index fbacb3266..893fac031 100644 --- a/src/parser/tests/statement/Declaration.spec.ts +++ b/src/parser/tests/statement/Declaration.spec.ts @@ -41,7 +41,7 @@ describe('parser variable declarations', () => { let { statements, diagnostics } = Parser.parse([ identifier('foo'), token(TokenKind.Equal), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), EOF ]); @@ -54,9 +54,9 @@ describe('parser variable declarations', () => { let { statements, diagnostics } = Parser.parse([ identifier('bar'), token(TokenKind.Equal), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.Caret), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), EOF ]); diff --git a/src/parser/tests/statement/Function.spec.ts b/src/parser/tests/statement/Function.spec.ts index 78cd7d8b0..63428ba0f 100644 --- a/src/parser/tests/statement/Function.spec.ts +++ b/src/parser/tests/statement/Function.spec.ts @@ -48,7 +48,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - createToken(TokenKind.StringLiteral, 'Lorem ipsum'), + token(TokenKind.StringLiteral, 'Lorem ipsum'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndFunction, 'end function'), EOF @@ -109,19 +109,19 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.Comma, ','), identifier('b'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '4'), + token(TokenKind.IntegerLiteral, '4'), token(TokenKind.Comma, ','), identifier('c'), token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), @@ -142,7 +142,7 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.Comma, ','), @@ -151,7 +151,7 @@ describe('parser', () => { token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.RightParen, ')'), @@ -250,7 +250,7 @@ describe('parser', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Print, 'print'), - createToken(TokenKind.StringLiteral, 'Lorem ipsum'), + token(TokenKind.StringLiteral, 'Lorem ipsum'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndSub, 'end sub'), EOF @@ -311,19 +311,19 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.Comma, ','), identifier('b'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '4'), + token(TokenKind.IntegerLiteral, '4'), token(TokenKind.Comma, ','), identifier('c'), token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), @@ -343,7 +343,7 @@ describe('parser', () => { identifier('a'), token(TokenKind.Equal, '='), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.Comma, ','), @@ -352,7 +352,7 @@ describe('parser', () => { token(TokenKind.Equal, '='), identifier('a'), token(TokenKind.Plus, '+'), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.As, 'as'), identifier('integer'), token(TokenKind.RightParen, ')'), diff --git a/src/parser/tests/statement/PrintStatement.spec.ts b/src/parser/tests/statement/PrintStatement.spec.ts index ed6aa1aaf..434ef539e 100644 --- a/src/parser/tests/statement/PrintStatement.spec.ts +++ b/src/parser/tests/statement/PrintStatement.spec.ts @@ -29,9 +29,9 @@ describe('parser print statements', () => { it('parses print lists with no separator', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.Print), - createToken(TokenKind.StringLiteral, 'Foo'), - createToken(TokenKind.StringLiteral, 'bar'), - createToken(TokenKind.StringLiteral, 'baz'), + token(TokenKind.StringLiteral, 'Foo'), + token(TokenKind.StringLiteral, 'bar'), + token(TokenKind.StringLiteral, 'baz'), EOF ]); @@ -43,11 +43,11 @@ describe('parser print statements', () => { it('parses print lists with separators', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.Print), - createToken(TokenKind.StringLiteral, 'Foo'), + token(TokenKind.StringLiteral, 'Foo'), token(TokenKind.Semicolon), - createToken(TokenKind.StringLiteral, 'bar'), + token(TokenKind.StringLiteral, 'bar'), token(TokenKind.Semicolon), - createToken(TokenKind.StringLiteral, 'baz'), + token(TokenKind.StringLiteral, 'baz'), EOF ]); diff --git a/src/parser/tests/statement/ReturnStatement.spec.ts b/src/parser/tests/statement/ReturnStatement.spec.ts index ff4d66f68..4da4271c4 100644 --- a/src/parser/tests/statement/ReturnStatement.spec.ts +++ b/src/parser/tests/statement/ReturnStatement.spec.ts @@ -33,7 +33,7 @@ describe('parser return statements', () => { token(TokenKind.RightParen, ')'), token(TokenKind.Newline, '\\n'), token(TokenKind.Return, 'return'), - createToken(TokenKind.StringLiteral, '"test"'), + token(TokenKind.StringLiteral, '"test"'), token(TokenKind.Newline, '\\n'), token(TokenKind.EndFunction, 'end function'), EOF diff --git a/src/parser/tests/statement/Set.spec.ts b/src/parser/tests/statement/Set.spec.ts index b16aeaafd..ad768a9d4 100644 --- a/src/parser/tests/statement/Set.spec.ts +++ b/src/parser/tests/statement/Set.spec.ts @@ -51,7 +51,7 @@ describe('parser indexed assignment', () => { token(TokenKind.Dot, '.'), identifier('bar'), token(TokenKind.StarEqual, '*='), - createToken(TokenKind.IntegerLiteral, '5'), + token(TokenKind.IntegerLiteral, '5'), token(TokenKind.Newline, '\\n'), EOF ]); @@ -67,7 +67,7 @@ describe('parser indexed assignment', () => { let { statements, diagnostics } = Parser.parse([ identifier('someArray'), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '0'), + token(TokenKind.IntegerLiteral, '0'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.Equal, '='), token(TokenKind.Function, 'function'), @@ -87,7 +87,7 @@ describe('parser indexed assignment', () => { let { statements, diagnostics } = Parser.parse([ identifier('someArray'), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '0'), + token(TokenKind.IntegerLiteral, '0'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.Equal, '='), token(TokenKind.True, 'true'), @@ -106,10 +106,10 @@ describe('parser indexed assignment', () => { let { statements, diagnostics } = Parser.parse([ identifier('someArray'), token(TokenKind.LeftSquareBracket, '['), - createToken(TokenKind.IntegerLiteral, '0'), + token(TokenKind.IntegerLiteral, '0'), token(TokenKind.RightSquareBracket, ']'), token(TokenKind.StarEqual, '*='), - createToken(TokenKind.IntegerLiteral, '3'), + token(TokenKind.IntegerLiteral, '3'), EOF ]); diff --git a/src/preprocessor/Preprocessor.spec.ts b/src/preprocessor/Preprocessor.spec.ts index ecfa2bed5..c8449799e 100644 --- a/src/preprocessor/Preprocessor.spec.ts +++ b/src/preprocessor/Preprocessor.spec.ts @@ -29,7 +29,7 @@ describe('preprocessor', () => { let { processedTokens } = new Preprocessor().filter([ new DeclarationChunk( identifier('lorem'), - createToken(TokenKind.False, 'false') + token(TokenKind.False, 'false') ) ]); expect(processedTokens).to.eql([]); @@ -41,7 +41,7 @@ describe('preprocessor', () => { () => new Preprocessor().filter([ new DeclarationChunk( identifier('lorem'), - createToken(TokenKind.True, 'true') + token(TokenKind.True, 'true') ) ]) ).not.to.throw; @@ -51,7 +51,7 @@ describe('preprocessor', () => { expect(() => new Preprocessor().filter([ new DeclarationChunk( identifier('ipsum'), - createToken(TokenKind.False, 'false') + token(TokenKind.False, 'false') ) ]) ).not.to.throw; @@ -62,11 +62,11 @@ describe('preprocessor', () => { // 'ipsum' must be defined before it's referenced new DeclarationChunk( identifier('ipsum'), - createToken(TokenKind.False, 'false') + token(TokenKind.False, 'false') ), new DeclarationChunk( identifier('dolor'), - createToken(TokenKind.True, 'true') + token(TokenKind.True, 'true') ) ]) ).not.to.throw; @@ -76,7 +76,7 @@ describe('preprocessor', () => { expect(() => new Preprocessor().filter([ new DeclarationChunk( identifier('sit'), - createToken(TokenKind.String, 'good boy!') + token(TokenKind.String, 'good boy!') ) ]) ).to.throw;//('#const declarations can only have'); @@ -86,11 +86,11 @@ describe('preprocessor', () => { expect(() => new Preprocessor().filter([ new DeclarationChunk( identifier('lorem'), - createToken(TokenKind.False, 'false') + token(TokenKind.False, 'false') ), new DeclarationChunk( identifier('lorem'), - createToken(TokenKind.True, 'true') + token(TokenKind.True, 'true') ) ]) ).to.throw; @@ -109,7 +109,7 @@ describe('preprocessor', () => { it('doesn\'t throw when branched around', () => { expect(() => new Preprocessor().filter([ new HashIfStatement( - createToken(TokenKind.False, 'false'), + token(TokenKind.False, 'false'), [ new ErrorChunk( token(TokenKind.HashError, '#error'), @@ -141,11 +141,11 @@ describe('preprocessor', () => { it('enters #if branch', () => { new Preprocessor().filter([ new HashIfStatement( - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), [ifChunk], [ { - condition: createToken(TokenKind.True, 'true'), + condition: token(TokenKind.True, 'true'), thenChunks: [elseIfChunk] } ], @@ -161,11 +161,11 @@ describe('preprocessor', () => { it('enters #else if branch', () => { new Preprocessor().filter([ new HashIfStatement( - createToken(TokenKind.False, 'false'), + token(TokenKind.False, 'false'), [ifChunk], [ { - condition: createToken(TokenKind.True, 'true'), + condition: token(TokenKind.True, 'true'), thenChunks: [elseIfChunk] } ], @@ -181,11 +181,11 @@ describe('preprocessor', () => { it('enters #else branch', () => { new Preprocessor().filter([ new HashIfStatement( - createToken(TokenKind.False, 'false'), + token(TokenKind.False, 'false'), [ifChunk], [ { - condition: createToken(TokenKind.False, 'false'), + condition: token(TokenKind.False, 'false'), thenChunks: [elseIfChunk] } ], @@ -201,7 +201,7 @@ describe('preprocessor', () => { it('enters no branches if none pass', () => { new Preprocessor().filter([ new HashIfStatement( - createToken(TokenKind.False, 'false'), + token(TokenKind.False, 'false'), [ifChunk], [] // no else-if chunks // NOTE: no 'else" chunk! @@ -217,7 +217,7 @@ describe('preprocessor', () => { new Preprocessor().filter([ new DeclarationChunk( identifier('lorem'), - createToken(TokenKind.True, 'true') + token(TokenKind.True, 'true') ), new HashIfStatement( identifier('lorem'), diff --git a/src/preprocessor/PreprocessorParser.spec.ts b/src/preprocessor/PreprocessorParser.spec.ts index c71a09712..05c3351ef 100644 --- a/src/preprocessor/PreprocessorParser.spec.ts +++ b/src/preprocessor/PreprocessorParser.spec.ts @@ -35,7 +35,7 @@ describe('preprocessor parser', () => { token(TokenKind.HashConst, '#const'), identifier('foo'), token(TokenKind.Equal, '='), - createToken(TokenKind.True, 'true'), + token(TokenKind.True, 'true'), token(TokenKind.Newline, '\n'), token(TokenKind.Eof, '\0') ]); From a3a1343babdd4a0918c3e54dcb0237cfa3117229 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Wed, 7 Oct 2020 15:54:27 -0400 Subject: [PATCH 9/9] remove unused imports from tests. --- src/parser/tests/controlFlow/For.spec.ts | 1 - src/parser/tests/controlFlow/If.spec.ts | 1 - src/parser/tests/controlFlow/While.spec.ts | 1 - src/parser/tests/expression/Additive.spec.ts | 1 - src/parser/tests/expression/ArrayLiterals.spec.ts | 1 - src/parser/tests/expression/AssociativeArrayLiterals.spec.ts | 1 - src/parser/tests/expression/Boolean.spec.ts | 1 - src/parser/tests/expression/Call.spec.ts | 1 - src/parser/tests/expression/Exponential.spec.ts | 1 - src/parser/tests/expression/Function.spec.ts | 1 - src/parser/tests/expression/Indexing.spec.ts | 1 - src/parser/tests/expression/Multiplicative.spec.ts | 1 - src/parser/tests/expression/PrefixUnary.spec.ts | 1 - src/parser/tests/expression/Primary.spec.ts | 1 - src/parser/tests/expression/Relational.spec.ts | 1 - src/parser/tests/statement/AssignmentOperators.spec.ts | 1 - src/parser/tests/statement/Declaration.spec.ts | 1 - src/parser/tests/statement/Function.spec.ts | 1 - src/parser/tests/statement/PrintStatement.spec.ts | 1 - src/parser/tests/statement/ReturnStatement.spec.ts | 1 - src/parser/tests/statement/Set.spec.ts | 1 - src/preprocessor/Preprocessor.spec.ts | 1 - src/preprocessor/PreprocessorParser.spec.ts | 1 - 23 files changed, 23 deletions(-) diff --git a/src/parser/tests/controlFlow/For.spec.ts b/src/parser/tests/controlFlow/For.spec.ts index 00617e80f..7d7e5cfe4 100644 --- a/src/parser/tests/controlFlow/For.spec.ts +++ b/src/parser/tests/controlFlow/For.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; import { ForStatement, LiteralExpression } from '../..'; describe('parser for loops', () => { diff --git a/src/parser/tests/controlFlow/If.spec.ts b/src/parser/tests/controlFlow/If.spec.ts index f70ea4e80..6275df053 100644 --- a/src/parser/tests/controlFlow/If.spec.ts +++ b/src/parser/tests/controlFlow/If.spec.ts @@ -3,7 +3,6 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; import { TokenKind, Lexer } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; -import { createToken } from '../../../astUtils/creators'; describe('parser if statements', () => { it('allows empty if blocks', () => { diff --git a/src/parser/tests/controlFlow/While.spec.ts b/src/parser/tests/controlFlow/While.spec.ts index 8c08768d0..4ee3ab13c 100644 --- a/src/parser/tests/controlFlow/While.spec.ts +++ b/src/parser/tests/controlFlow/While.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser while statements', () => { diff --git a/src/parser/tests/expression/Additive.spec.ts b/src/parser/tests/expression/Additive.spec.ts index e5b0d172c..90730454c 100644 --- a/src/parser/tests/expression/Additive.spec.ts +++ b/src/parser/tests/expression/Additive.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser additive expressions', () => { it('parses left-associative addition chains', () => { diff --git a/src/parser/tests/expression/ArrayLiterals.spec.ts b/src/parser/tests/expression/ArrayLiterals.spec.ts index 230495a88..77de98fc3 100644 --- a/src/parser/tests/expression/ArrayLiterals.spec.ts +++ b/src/parser/tests/expression/ArrayLiterals.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser array literals', () => { describe('empty arrays', () => { diff --git a/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts b/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts index cec470ecb..b427b5896 100644 --- a/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts +++ b/src/parser/tests/expression/AssociativeArrayLiterals.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser associative array literals', () => { describe('empty associative arrays', () => { diff --git a/src/parser/tests/expression/Boolean.spec.ts b/src/parser/tests/expression/Boolean.spec.ts index b49520981..170703a20 100644 --- a/src/parser/tests/expression/Boolean.spec.ts +++ b/src/parser/tests/expression/Boolean.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser boolean expressions', () => { diff --git a/src/parser/tests/expression/Call.spec.ts b/src/parser/tests/expression/Call.spec.ts index ec2223801..770a06ab1 100644 --- a/src/parser/tests/expression/Call.spec.ts +++ b/src/parser/tests/expression/Call.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind, Lexer } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser call expressions', () => { it('parses named function calls', () => { diff --git a/src/parser/tests/expression/Exponential.spec.ts b/src/parser/tests/expression/Exponential.spec.ts index 5247985e0..b7f4afedb 100644 --- a/src/parser/tests/expression/Exponential.spec.ts +++ b/src/parser/tests/expression/Exponential.spec.ts @@ -3,7 +3,6 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; -import { createToken } from '../../../astUtils/creators'; describe('parser', () => { describe('exponential expressions', () => { diff --git a/src/parser/tests/expression/Function.spec.ts b/src/parser/tests/expression/Function.spec.ts index ddac7eadd..f4cd2d0f8 100644 --- a/src/parser/tests/expression/Function.spec.ts +++ b/src/parser/tests/expression/Function.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser', () => { diff --git a/src/parser/tests/expression/Indexing.spec.ts b/src/parser/tests/expression/Indexing.spec.ts index 2674c1816..debec599b 100644 --- a/src/parser/tests/expression/Indexing.spec.ts +++ b/src/parser/tests/expression/Indexing.spec.ts @@ -6,7 +6,6 @@ import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; import { DiagnosticMessages } from '../../../DiagnosticMessages'; import { AssignmentStatement } from '../../Statement'; -import { createToken } from '../../../astUtils/creators'; describe('parser indexing', () => { describe('one level', () => { diff --git a/src/parser/tests/expression/Multiplicative.spec.ts b/src/parser/tests/expression/Multiplicative.spec.ts index b704c9a9f..96b38c3db 100644 --- a/src/parser/tests/expression/Multiplicative.spec.ts +++ b/src/parser/tests/expression/Multiplicative.spec.ts @@ -3,7 +3,6 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; -import { createToken } from '../../../astUtils/creators'; describe('parser', () => { diff --git a/src/parser/tests/expression/PrefixUnary.spec.ts b/src/parser/tests/expression/PrefixUnary.spec.ts index d9212794f..e475ecf2c 100644 --- a/src/parser/tests/expression/PrefixUnary.spec.ts +++ b/src/parser/tests/expression/PrefixUnary.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser prefix unary expressions', () => { diff --git a/src/parser/tests/expression/Primary.spec.ts b/src/parser/tests/expression/Primary.spec.ts index 43dec2507..0e696ae30 100644 --- a/src/parser/tests/expression/Primary.spec.ts +++ b/src/parser/tests/expression/Primary.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser primary expressions', () => { diff --git a/src/parser/tests/expression/Relational.spec.ts b/src/parser/tests/expression/Relational.spec.ts index 8d0a437ea..6cf2cbe9d 100644 --- a/src/parser/tests/expression/Relational.spec.ts +++ b/src/parser/tests/expression/Relational.spec.ts @@ -3,7 +3,6 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; -import { createToken } from '../../../astUtils/creators'; describe('parser', () => { diff --git a/src/parser/tests/statement/AssignmentOperators.spec.ts b/src/parser/tests/statement/AssignmentOperators.spec.ts index d51de111b..754a1ceef 100644 --- a/src/parser/tests/statement/AssignmentOperators.spec.ts +++ b/src/parser/tests/statement/AssignmentOperators.spec.ts @@ -3,7 +3,6 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; -import { createToken } from '../../../astUtils/creators'; describe('parser assignment operators', () => { it('+=', () => { diff --git a/src/parser/tests/statement/Declaration.spec.ts b/src/parser/tests/statement/Declaration.spec.ts index 893fac031..5a4881e13 100644 --- a/src/parser/tests/statement/Declaration.spec.ts +++ b/src/parser/tests/statement/Declaration.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser variable declarations', () => { it('allows newlines before assignments', () => { diff --git a/src/parser/tests/statement/Function.spec.ts b/src/parser/tests/statement/Function.spec.ts index 63428ba0f..74b1ff72e 100644 --- a/src/parser/tests/statement/Function.spec.ts +++ b/src/parser/tests/statement/Function.spec.ts @@ -3,7 +3,6 @@ import { expect } from 'chai'; import { Parser } from '../../Parser'; import { TokenKind, Lexer } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; -import { createToken } from '../../../astUtils/creators'; describe('parser', () => { diff --git a/src/parser/tests/statement/PrintStatement.spec.ts b/src/parser/tests/statement/PrintStatement.spec.ts index 434ef539e..64d47e49b 100644 --- a/src/parser/tests/statement/PrintStatement.spec.ts +++ b/src/parser/tests/statement/PrintStatement.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser print statements', () => { it('parses singular print statements', () => { diff --git a/src/parser/tests/statement/ReturnStatement.spec.ts b/src/parser/tests/statement/ReturnStatement.spec.ts index 4da4271c4..c940d4e13 100644 --- a/src/parser/tests/statement/ReturnStatement.spec.ts +++ b/src/parser/tests/statement/ReturnStatement.spec.ts @@ -5,7 +5,6 @@ import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { FunctionStatement } from '../../Statement'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser return statements', () => { it('parses void returns', () => { diff --git a/src/parser/tests/statement/Set.spec.ts b/src/parser/tests/statement/Set.spec.ts index ad768a9d4..976d4a0e1 100644 --- a/src/parser/tests/statement/Set.spec.ts +++ b/src/parser/tests/statement/Set.spec.ts @@ -4,7 +4,6 @@ import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, identifier, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; -import { createToken } from '../../../astUtils/creators'; describe('parser indexed assignment', () => { describe('dotted', () => { diff --git a/src/preprocessor/Preprocessor.spec.ts b/src/preprocessor/Preprocessor.spec.ts index c8449799e..b31d6b9f8 100644 --- a/src/preprocessor/Preprocessor.spec.ts +++ b/src/preprocessor/Preprocessor.spec.ts @@ -4,7 +4,6 @@ import { Preprocessor } from './Preprocessor'; import { BrightScriptChunk, DeclarationChunk, ErrorChunk, HashIfStatement } from './Chunk'; import { expect } from 'chai'; import { createSandbox } from 'sinon'; -import { createToken } from '../astUtils/creators'; let sinon = createSandbox(); describe('preprocessor', () => { diff --git a/src/preprocessor/PreprocessorParser.spec.ts b/src/preprocessor/PreprocessorParser.spec.ts index 05c3351ef..924d20766 100644 --- a/src/preprocessor/PreprocessorParser.spec.ts +++ b/src/preprocessor/PreprocessorParser.spec.ts @@ -3,7 +3,6 @@ import { identifier, token } from '../parser/tests/Parser.spec'; import { TokenKind } from '../lexer/TokenKind'; import { expect } from 'chai'; import { BrightScriptChunk } from './Chunk'; -import { createToken } from '../astUtils/creators'; describe('preprocessor parser', () => { let parser: PreprocessorParser;