From a691019abdbcc43781d6a9649a8c5f88c0690055 Mon Sep 17 00:00:00 2001 From: Bronley Plumb Date: Tue, 14 Jun 2022 14:15:13 -0400 Subject: [PATCH] fix bug with class transpile in watch mode --- src/files/BrsFile.Class.spec.ts | 53 +++++++++++++++++++++++++++++++-- src/parser/Statement.ts | 12 ++++---- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/src/files/BrsFile.Class.spec.ts b/src/files/BrsFile.Class.spec.ts index 45f767e20..20d6932f0 100644 --- a/src/files/BrsFile.Class.spec.ts +++ b/src/files/BrsFile.Class.spec.ts @@ -6,7 +6,7 @@ import { expect } from 'chai'; import { DiagnosticMessages } from '../DiagnosticMessages'; import { Range } from 'vscode-languageserver'; import { ParseMode } from '../parser/Parser'; -import { expectDiagnostics, expectZeroDiagnostics, getTestTranspile } from '../testHelpers.spec'; +import { expectDiagnostics, expectZeroDiagnostics, getTestTranspile, trim } from '../testHelpers.spec'; import { standardizePath as s } from '../util'; import * as fsExtra from 'fs-extra'; import { BrsTranspileState } from '../parser/BrsTranspileState'; @@ -861,8 +861,57 @@ describe('BrsFile BrighterScript classes', () => { ]); }); - it('does not cause infinite loop', () => { + it('transpiles super method calls twice', async () => { + program.setFile('source/lib.bs', ` + class Being + function think() + print "thinking..." + end function + end class + class Human extends Being + function think() + super.think() + end function + end class + `); + await program.transpile([], stagingDir); + fsExtra.emptyDirSync(stagingDir); + await program.transpile([], stagingDir); + expect( + fsExtra.readFileSync(s`${stagingDir}/source/lib.brs`).toString().trimEnd() + ).to.eql(trim` + function __Being_builder() + instance = {} + instance.new = sub() + end sub + instance.think = function() + print "thinking..." + end function + return instance + end function + function Being() + instance = __Being_builder() + instance.new() + return instance + end function + function __Human_builder() + instance = __Being_builder() + instance.super0_new = instance.new + instance.new = sub() + m.super0_new() + end sub + instance.think = function() + m.super0_think() + end function + return instance + end function + function Human() + instance = __Human_builder() + instance.new() + return instance + end function + `); }); it('detects duplicate member names', () => { diff --git a/src/parser/Statement.ts b/src/parser/Statement.ts index ff09f7144..3ca1aee2e 100644 --- a/src/parser/Statement.ts +++ b/src/parser/Statement.ts @@ -10,7 +10,7 @@ import type { BrsTranspileState } from './BrsTranspileState'; import { ParseMode } from './Parser'; import type { WalkVisitor, WalkOptions } from '../astUtils/visitors'; import { InternalWalkMode, walk, createVisitor, WalkMode, walkArray } from '../astUtils/visitors'; -import { isCallExpression, isClassFieldStatement, isClassMethodStatement, isCommentStatement, isEnumMemberStatement, isExpression, isExpressionStatement, isFunctionStatement, isIfStatement, isInterfaceFieldStatement, isInterfaceMethodStatement, isInvalidType, isLiteralExpression, isTypedefProvider, isVoidType } from '../astUtils/reflection'; +import { isCallExpression, isCommentStatement, isEnumMemberStatement, isExpression, isExpressionStatement, isFieldStatement, isFunctionStatement, isIfStatement, isInterfaceFieldStatement, isInterfaceMethodStatement, isInvalidType, isLiteralExpression, isMethodStatement, isTypedefProvider, isVoidType } from '../astUtils/reflection'; import type { TranspileResult, TypedefProvider } from '../interfaces'; import { createInvalidLiteral, createMethodStatement, createToken, interpolatedRange } from '../astUtils/creators'; import { DynamicType } from '../types/DynamicType'; @@ -1524,10 +1524,10 @@ export class ClassStatement extends Statement implements TypedefProvider { super(); this.body = this.body ?? []; for (let statement of this.body) { - if (isClassMethodStatement(statement)) { + if (isMethodStatement(statement)) { this.methods.push(statement); this.memberMap[statement?.name?.text.toLowerCase()] = statement; - } else if (isClassFieldStatement(statement)) { + } else if (isFieldStatement(statement)) { this.fields.push(statement); this.memberMap[statement?.name?.text.toLowerCase()] = statement; } @@ -1751,12 +1751,12 @@ export class ClassStatement extends Statement implements TypedefProvider { for (let statement of body) { //is field statement - if (isClassFieldStatement(statement)) { + if (isFieldStatement(statement)) { //do nothing with class fields in this situation, they are handled elsewhere continue; //methods - } else if (isClassMethodStatement(statement)) { + } else if (isMethodStatement(statement)) { //store overridden parent methods as super{parentIndex}_{methodName} if ( @@ -1922,7 +1922,7 @@ export class MethodStatement extends FunctionStatement { const beginningVariable = util.findBeginningVariableExpression(e); const lowerName = beginningVariable?.getName(ParseMode.BrighterScript).toLowerCase(); if (lowerName === 'super') { - beginningVariable.name.text = 'm'; + state.editor.setProperty(beginningVariable.name, 'text', 'm'); state.editor.setProperty(e.name, 'text', `super${parentClassIndex}_${e.name.text}`); } }