diff --git a/src/files/BrsFile.spec.ts b/src/files/BrsFile.spec.ts index 8a6a35172..032a05a8a 100644 --- a/src/files/BrsFile.spec.ts +++ b/src/files/BrsFile.spec.ts @@ -2149,7 +2149,7 @@ describe('BrsFile', () => { returnValue = 12 'comment return returnValue 'comment end function 'comment - print "a" ; "b" ; 3 'comment + print "a"; "b"; 3 'comment a(1, 2, 3) 'comment person.functionCall(1, 2, 3) 'comment if true then 'comment diff --git a/src/parser/Statement.ts b/src/parser/Statement.ts index be31ea742..c5e77c3e6 100644 --- a/src/parser/Statement.ts +++ b/src/parser/Statement.ts @@ -578,19 +578,22 @@ export class PrintStatement extends Statement { ' ' ]; for (let i = 0; i < this.expressions.length; i++) { - let expression: any = this.expressions[i]; - if (expression.transpile) { - //separate print statements with a semi-colon - if (i > 0) { - result.push(' ; '); - } - result.push(...(expression as ExpressionStatement).transpile(state)); + const expressionOrSeparator: any = this.expressions[i]; + if (expressionOrSeparator.transpile) { + result.push(...(expressionOrSeparator as ExpressionStatement).transpile(state)); } else { - //skip these because I think they are bogus items only added for use in the runtime + result.push( + state.tokenToSourceNode(expressionOrSeparator) + ); + } + //if there's an expression after us, add a space + if ((this.expressions[i + 1] as any)?.transpile) { + result.push(' '); } } return result; } + walk(visitor: WalkVisitor, options: WalkOptions) { if (options.walkMode & InternalWalkMode.walkExpressions) { for (let i = 0; i < this.expressions.length; i++) { diff --git a/src/parser/tests/statement/PrintStatement.spec.ts b/src/parser/tests/statement/PrintStatement.spec.ts index 64d47e49b..73d043585 100644 --- a/src/parser/tests/statement/PrintStatement.spec.ts +++ b/src/parser/tests/statement/PrintStatement.spec.ts @@ -1,11 +1,25 @@ import { expect } from 'chai'; - import { Parser } from '../../Parser'; import { TokenKind } from '../../../lexer'; import { EOF, token } from '../Parser.spec'; import { Range } from 'vscode-languageserver'; +import { Program } from '../../../Program'; +import { standardizePath as s } from '../../../util'; +import { getTestTranspile } from '../../../testHelpers.spec'; + +const rootDir = s`${process.cwd()}/.tmp/rootDir`; describe('parser print statements', () => { + + let program: Program; + const testTranspile = getTestTranspile(() => [program, rootDir]); + + beforeEach(() => { + program = new Program({ + rootDir: rootDir + }); + }); + it('parses singular print statements', () => { let { statements, diagnostics } = Parser.parse([ token(TokenKind.Print), @@ -90,4 +104,93 @@ describe('parser print statements', () => { expect(statements).to.be.lengthOf(1); expect(statements[0].range).to.deep.include(Range.create(0, 0, 0, 11)); }); + + describe('transpile', () => { + it('retains comma separators', () => { + testTranspile(` + a$ = "string" + print a$, a$, a$ + `); + }); + + it('retains semicolon separators', () => { + testTranspile(` + a$ = "string" + print a$; a$; a$ + `); + }); + + it('supports no space between function calls', () => { + testTranspile(` + function getText() + return "text" + end function + print getText() getText() getText() + `); + }); + + it('supports print in loop', () => { + testTranspile(` + paramArr = ["This", "is", true, "and", "this", "is", 1] + print "This is one line of stuff:"; + for each item in paramArr + print item; " "; + end for + print "" + `, ` + paramArr = [ + "This", + "is", + true, + "and", + "this", + "is", + 1 + ] + print "This is one line of stuff:"; + for each item in paramArr + print item; " "; + end for + print "" + `); + }); + + it('handles roku documentation examples', () => { + testTranspile(` + x=5:print 25; " is equal to"; x^2 + a$="string":print a$;a$,a$;" ";a$ + print "zone 1","zone 2","zone 3","zone 4" + print "print statement #1 ":print "print statement #2" + print "this is a five " 5 "!!" + print {} + print {a:1} + print [] + print [5] + print tab(5)"tabbed 5";tab(25)"tabbed 25" + print tab(40) pos(0) 'prints 40 at position 40 + print "these" tab(pos(0)+5)"words" tab(pos(0)+5)"are":print tab(pos(0)+5)"evenly" tab(pos(0)+5)"spaced" + `, ` + x = 5 + print 25; " is equal to"; x ^ 2 + a$ = "string" + print a$; a$, a$; " "; a$ + print "zone 1", "zone 2", "zone 3", "zone 4" + print "print statement #1 " + print "print statement #2" + print "this is a five " 5 "!!" + print {} + print { + a: 1 + } + print [] + print [ + 5 + ] + print tab(5) "tabbed 5"; tab(25) "tabbed 25" + print tab(40) pos(0) 'prints 40 at position 40 + print "these" tab(pos(0) + 5) "words" tab(pos(0) + 5) "are" + print tab(pos(0) + 5) "evenly" tab(pos(0) + 5) "spaced" + `); + }); + }); });