nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: rokucommunity/brighterscript
Pull request #493 (2022-01-25 17:55:45)

Fix parser bug after interface statement.
Fixes an issue in the parser that would show errors for all data that shows up after the first interface statement. 


Patch:
diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts
index 1cf32079..da761005 100644
--- a/src/parser/Parser.ts
+++ b/src/parser/Parser.ts
@@ -474,8 +474,6 @@ export class Parser {
         //consume the final `end interface` token
         const endInterfaceToken = this.consumeToken(TokenKind.EndInterface);
 
-        this.consumeStatementSeparators();
-
         const statement = new InterfaceStatement(
             interfaceToken,
             nameToken,


Test patch:
diff --git a/src/parser/tests/statement/InterfaceStatement.spec.ts b/src/parser/tests/statement/InterfaceStatement.spec.ts
index aeca6749..9cc43849 100644
--- a/src/parser/tests/statement/InterfaceStatement.spec.ts
+++ b/src/parser/tests/statement/InterfaceStatement.spec.ts
@@ -1,4 +1,4 @@
-import { getTestGetTypedef } from '../../../testHelpers.spec';
+import { expectZeroDiagnostics, getTestGetTypedef } from '../../../testHelpers.spec';
 import { standardizePath as s } from '../../../util';
 import { Program } from '../../../Program';
 
@@ -61,4 +61,17 @@ describe('InterfaceStatement', () => {
             end interface
         `, undefined, undefined, undefined, true);
     });
+
+    it('allows declaring multiple interfaces in a file', () => {
+        program.addOrReplaceFile('source/interfaces.bs', `
+            interface Iface1
+                name as dynamic
+            end interface
+            interface IFace2
+                prop as dynamic
+            end interface
+        `);
+        program.validate();
+        expectZeroDiagnostics(program);
+    });
 });
Repository: rokucommunity/brighterscript
Pull request #670 (2022-08-18 12:42:51)

Allow const as variable name
- Fixes a bug that was preventing the use of `const` as a variable name.
- warn about using `const` statements in non-brighterscript mode


Patch:
diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts
index 9596aa64..a93c90e9 100644
--- a/src/parser/Parser.ts
+++ b/src/parser/Parser.ts
@@ -340,7 +340,7 @@ export class Parser {
                 return this.libraryStatement();
             }
 
-            if (this.check(TokenKind.Const)) {
+            if (this.check(TokenKind.Const) && this.checkAnyNext(TokenKind.Identifier, ...this.allowedLocalIdentifiers)) {
                 return this.constDeclaration();
             }
 
@@ -1471,8 +1471,9 @@ export class Parser {
     }
 
     private constDeclaration(): ConstStatement | undefined {
+        this.warnIfNotBrighterScriptMode('const declaration');
         const constToken = this.advance();
-        const nameToken = this.identifier();
+        const nameToken = this.identifier(...this.allowedLocalIdentifiers);
         const equalToken = this.consumeToken(TokenKind.Equal);
         const expression = this.expression();
         const statement = new ConstStatement({


Test patch:
diff --git a/src/parser/tests/statement/ConstStatement.spec.ts b/src/parser/tests/statement/ConstStatement.spec.ts
index 17d73b1b..cbfe1379 100644
--- a/src/parser/tests/statement/ConstStatement.spec.ts
+++ b/src/parser/tests/statement/ConstStatement.spec.ts
@@ -2,7 +2,7 @@ import { expectCompletionsIncludes, expectZeroDiagnostics, getTestGetTypedef, ge
 import util, { standardizePath as s } from '../../../util';
 import { Program } from '../../../Program';
 import { createSandbox } from 'sinon';
-import { Parser } from '../../Parser';
+import { ParseMode, Parser } from '../../Parser';
 import { expect } from 'chai';
 import type { ConstStatement } from '../../Statement';
 import { TokenKind } from '../../../lexer/TokenKind';
@@ -27,8 +27,21 @@ describe('ConstStatement', () => {
         program.dispose();
     });
 
+    it('does not prevent using `const` as a variable name in .brs files', () => {
+        program.setFile('source/main.brs', `
+            sub main()
+                const = {
+                    name: "Bob"
+                }
+                print const.name = {}
+            end sub
+        `);
+        program.validate();
+        expectZeroDiagnostics(program);
+    });
+
     it('supports basic structure', () => {
-        parser.parse('const API_KEY = "abc"');
+        parser.parse('const API_KEY = "abc"', { mode: ParseMode.BrighterScript });
         expectZeroDiagnostics(parser);
         const statement = parser.ast.statements[0] as ConstStatement;
         expect(statement.tokens.const?.kind).to.eql(TokenKind.Const);
Repository: rokucommunity/brighterscript
Pull request #730 (2022-10-27 18:26:25)

Allow `continue` as local var
Allow `continue` to be used as local variable. 


Patch:
diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts
index 3f619d5e..3282b7c9 100644
--- a/src/parser/Parser.ts
+++ b/src/parser/Parser.ts
@@ -1112,7 +1112,8 @@ export class Parser {
             return this.gotoStatement();
         }
 
-        if (this.check(TokenKind.Continue)) {
+        //the continue keyword (followed by `for`, `while`, or a statement separator)
+        if (this.check(TokenKind.Continue) && this.checkAnyNext(TokenKind.While, TokenKind.For, TokenKind.Newline, TokenKind.Colon, TokenKind.Comment)) {
             return this.continueStatement();
         }
 


Test patch:
diff --git a/src/parser/tests/statement/Continue.spec.ts b/src/parser/tests/statement/Continue.spec.ts
index 099b8aa6..70d2d558 100644
--- a/src/parser/tests/statement/Continue.spec.ts
+++ b/src/parser/tests/statement/Continue.spec.ts
@@ -82,6 +82,20 @@ describe('parser continue statements', () => {
         ]);
     });
 
+    it('allows `continue` to be used as a local variable', () => {
+        program.setFile<BrsFile>('source/main.bs', `
+            sub main()
+                continue = true
+                print continue
+                if not continue then
+                    print continue
+                end if
+            end sub
+        `);
+        program.validate();
+        expectZeroDiagnostics(program);
+    });
+
     it('transpiles properly', () => {
         testTranspile(`
             sub main()
Repository: rokucommunity/brighterscript
Pull request #774 (2023-02-21 16:36:57)

Fix crash when func has no block
Fixes a crash in the parser when a function body fails to parse. Allows the diagnostics to happen, but still adds an empty `Block` entry to `function.body` so ast walkers have a better time. 


Patch:
diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts
index c44d0fd2..aba00415 100644
--- a/src/parser/Parser.ts
+++ b/src/parser/Parser.ts
@@ -887,12 +887,13 @@ export class Parser {
 
             this._references.functionExpressions.push(func);
 
-            //make sure to restore the currentFunctionExpression even if the body block fails to parse
-            try {
-                //support ending the function with `end sub` OR `end function`
-                func.body = this.block();
-                func.body.symbolTable = new SymbolTable(`Block: Function '${name?.text ?? ''}'`, () => func.getSymbolTable());
-            } finally { }
+            //support ending the function with `end sub` OR `end function`
+            func.body = this.block();
+            //if the parser was unable to produce a block, make an empty one so the AST makes some sense...
+            if (!func.body) {
+                func.body = new Block([], util.createRangeFromPositions(func.range.start, func.range.start));
+            }
+            func.body.symbolTable = new SymbolTable(`Block: Function '${name?.text ?? ''}'`, () => func.getSymbolTable());
 
             if (!func.body) {
                 this.diagnostics.push({


Test patch:
diff --git a/src/parser/tests/statement/Function.spec.ts b/src/parser/tests/statement/Function.spec.ts
index 1208229b..d2fd5c12 100644
--- a/src/parser/tests/statement/Function.spec.ts
+++ b/src/parser/tests/statement/Function.spec.ts
@@ -1,13 +1,23 @@
 import { expect } from '../../../chai-config.spec';
-
 import { Parser } from '../../Parser';
 import { Lexer } from '../../../lexer/Lexer';
 import { TokenKind } from '../../../lexer/TokenKind';
 import { EOF, identifier, token } from '../Parser.spec';
+import { isFunctionStatement } from '../../../astUtils/reflection';
+import type { FunctionStatement } from '../../Statement';
 
 describe('parser', () => {
 
     describe('function declarations', () => {
+        it('still provides a body when end keyword is mangled/missing', () => {
+            const parser = Parser.parse(`
+                sub test()
+                end su
+            `);
+            const func = parser.ast.findChild<FunctionStatement>(isFunctionStatement);
+            expect(func.func.body).to.exist;
+        });
+
         it('recovers when using `end sub` instead of `end function`', () => {
             const { tokens } = Lexer.scan(`
                 function Main()
Repository: rokucommunity/brighterscript
Pull request #793 (2023-04-17 16:33:25)

Fix namespace-relative enum value
Fixes a bug that was incorrectly flagging namespace-relative enum values. 


Patch:
diff --git a/src/Scope.ts b/src/Scope.ts
index 58d92333..2f1e3cc6 100644
--- a/src/Scope.ts
+++ b/src/Scope.ts
@@ -165,7 +165,7 @@ export class Scope {
      * @param containingNamespace - The namespace used to resolve relative enum names. (i.e. the namespace around the current statement trying to find a enum)
      */
     public getEnumMemberFileLink(enumMemberName: string, containingNamespace?: string): FileLink<EnumMemberStatement> {
-        let lowerNameParts = enumMemberName?.split('.');
+        let lowerNameParts = enumMemberName?.toLowerCase()?.split('.');
         let memberName = lowerNameParts?.splice(lowerNameParts.length - 1, 1)?.[0];
         let lowerName = lowerNameParts?.join('.').toLowerCase();
         const enumMap = this.getEnumMap();
diff --git a/src/bscPlugin/validation/ScopeValidator.ts b/src/bscPlugin/validation/ScopeValidator.ts
index 49e658b7..0b7b9a10 100644
--- a/src/bscPlugin/validation/ScopeValidator.ts
+++ b/src/bscPlugin/validation/ScopeValidator.ts
@@ -125,7 +125,7 @@ export class ScopeValidator {
                 entityNameLower += '.' + part.name.text.toLowerCase();
 
                 //if this is an enum member, stop validating here to prevent errors further down the chain
-                if (scope.getEnumMemberMap().has(entityNameLower)) {
+                if (scope.getEnumMemberFileLink(entityName, info.enclosingNamespaceNameLower)) {
                     break;
                 }
 


Test patch:
diff --git a/src/parser/tests/statement/Enum.spec.ts b/src/parser/tests/statement/Enum.spec.ts
index 682f1f1b..80299ae7 100644
--- a/src/parser/tests/statement/Enum.spec.ts
+++ b/src/parser/tests/statement/Enum.spec.ts
@@ -602,6 +602,23 @@ describe('EnumStatement', () => {
             `);
         });
 
+        it('recognizes namespace-relative enums', () => {
+            program.setFile('source/main.bs', `
+                namespace MyNamespace
+                    enum MyEnum
+                        val1
+                        val2
+                    end enum
+
+                    function foo() as integer
+                        return MyEnum.val1
+                    end function
+                end namespace
+            `);
+            program.validate();
+            expectZeroDiagnostics(program);
+        });
+
         it('replaces enum values from separate file with literals', () => {
             program.setFile('source/enum.bs', `
                 enum CharacterType
Repository: rokucommunity/brighterscript
Pull request #921 (2023-09-25 19:24:22)

Fix incorrect quasi location in template string
Fixes a token location bug in the template string lexer logic where the closing `}` had incorrect end char position. 


Patch:
diff --git a/src/lexer/Lexer.ts b/src/lexer/Lexer.ts
index 0493d8b9..3df83d29 100644
--- a/src/lexer/Lexer.ts
+++ b/src/lexer/Lexer.ts
@@ -616,7 +616,7 @@ export class Lexer {
                     this.scanToken();
                 }
                 if (this.check('}')) {
-                    this.current++;
+                    this.advance();
                     this.addToken(TokenKind.TemplateStringExpressionEnd);
                 } else {
 


Test patch:
diff --git a/src/parser/tests/expression/TemplateStringExpression.spec.ts b/src/parser/tests/expression/TemplateStringExpression.spec.ts
index 1b1a6884..9dc48ab7 100644
--- a/src/parser/tests/expression/TemplateStringExpression.spec.ts
+++ b/src/parser/tests/expression/TemplateStringExpression.spec.ts
@@ -8,6 +8,7 @@ import { Parser, ParseMode } from '../../Parser';
 import { AssignmentStatement } from '../../Statement';
 import { Program } from '../../../Program';
 import { expectZeroDiagnostics, getTestTranspile } from '../../../testHelpers.spec';
+import { util } from '../../../util';
 
 describe('TemplateStringExpression', () => {
     describe('parser template String', () => {
@@ -18,6 +19,41 @@ describe('TemplateStringExpression', () => {
         });
 
         describe('in assignment', () => {
+            it('generates correct locations for quasis', () => {
+                let { tokens } = Lexer.scan('print `0xAAAAAA${"0xBBBBBB"}0xCCCCCC`');
+                expect(
+                    tokens.filter(x => /"?0x/.test(x.text)).map(x => x.range)
+                ).to.eql([
+                    util.createRange(0, 7, 0, 15), // 0xAAAAAA
+                    util.createRange(0, 17, 0, 27), // "0xBBBBBB"
+                    util.createRange(0, 28, 0, 36) // 0xCCCCCC
+                ]);
+            });
+
+            it('generates correct locations for items', () => {
+                let { tokens } = Lexer.scan('print `${111}${222}${333}`');
+                //throw out the `print` token
+                tokens.shift();
+                expect(
+                    //compute the length of the token char spread
+                    tokens.filter(x => x.text !== '').map(x => [x.range.end.character - x.range.start.character, x.text])
+                ).to.eql([
+                    '`',
+                    '${',
+                    '111',
+                    '}',
+                    '${',
+                    '222',
+                    '}',
+                    '${',
+                    '333',
+                    '}',
+                    '`'
+                ].map(x => [x.length, x])
+                );
+            });
+
+
             it(`simple case`, () => {
                 let { tokens } = Lexer.scan(`a = \`hello      world\``);
                 let { statements, diagnostics } = Parser.parse(tokens, { mode: ParseMode.BrighterScript });
Repository: rokucommunity/brighterscript
Pull request #924 (2023-10-02 12:20:26)

Add function parameter support in interfaces
Adds support for function parameters in interface declarations. I had added this to v0.66, but it really should be in mainline since it's such a simple change. 


Patch:
diff --git a/docs/interfaces.md b/docs/interfaces.md
index 7465a305..d8905969 100644
--- a/docs/interfaces.md
+++ b/docs/interfaces.md
@@ -91,4 +91,21 @@ end interface
 ```BrightScript
 
 ```
-</details>
\ No newline at end of file
+</details>
+
+</details>
+
+## Methods
+Interfaces can describe complex methods as well
+```brighterscript
+interface Dog
+    sub barkAt(nemesis as Cat)
+end interface
+```
+
+<details>
+  <summary>View the transpiled BrightScript code</summary>
+
+```BrightScript
+```
+</details>
diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts
index 4d9fca70..04095df5 100644
--- a/src/parser/Parser.ts
+++ b/src/parser/Parser.ts
@@ -417,7 +417,19 @@ export class Parser {
         const name = this.identifier(...AllowedProperties);
         const leftParen = this.consumeToken(TokenKind.LeftParen);
 
-        const params = [];
+        let params = [] as FunctionParameterExpression[];
+        if (!this.check(TokenKind.RightParen)) {
+            do {
+                if (params.length >= CallExpression.MaximumArguments) {
+                    this.diagnostics.push({
+                        ...DiagnosticMessages.tooManyCallableParameters(params.length, CallExpression.MaximumArguments),
+                        range: this.peek().range
+                    });
+                }
+
+                params.push(this.functionParameter());
+            } while (this.match(TokenKind.Comma));
+        }
         const rightParen = this.consumeToken(TokenKind.RightParen);
         let asToken = null as Token;
         let returnTypeToken = null as Token;


Test patch:
diff --git a/src/parser/tests/statement/InterfaceStatement.spec.ts b/src/parser/tests/statement/InterfaceStatement.spec.ts
index b39caea5..7d952d10 100644
--- a/src/parser/tests/statement/InterfaceStatement.spec.ts
+++ b/src/parser/tests/statement/InterfaceStatement.spec.ts
@@ -87,4 +87,13 @@ describe('InterfaceStatement', () => {
             'this comment was throwing exception during transpile
         `);
     });
+
+    it('allows parameters in interface method signatures', () => {
+        testGetTypedef(`
+            interface Person
+                sub someFunc(name as string, age as integer) as string
+                someField as string
+            end interface
+        `, undefined, undefined, undefined, true);
+    });
 });
Repository: rokucommunity/brighterscript
Pull request #1082 (2024-02-28 20:05:21)

Empty interfaces break the parser
Fixes a bug where empty interfaces would break the parser

![image](https://github.com/rokucommunity/brighterscript/assets/2544493/c288363d-6cdd-48f5-aa98-15a4e7928ce5)



Patch:
diff --git a/src/parser/Parser.ts b/src/parser/Parser.ts
index b3f95672..75bff4cf 100644
--- a/src/parser/Parser.ts
+++ b/src/parser/Parser.ts
@@ -489,6 +489,11 @@ export class Parser {
         let body = [] as Statement[];
         while (this.checkAny(TokenKind.Comment, TokenKind.Identifier, TokenKind.At, ...AllowedProperties)) {
             try {
+                //break out of this loop if we encountered the `EndInterface` token not followed by `as`
+                if (this.check(TokenKind.EndInterface) && !this.checkNext(TokenKind.As)) {
+                    break;
+                }
+
                 let decl: Statement;
 
                 //collect leading annotations
@@ -528,10 +533,6 @@ export class Parser {
 
             //ensure statement separator
             this.consumeStatementSeparators();
-            //break out of this loop if we encountered the `EndInterface` token not followed by `as`
-            if (this.check(TokenKind.EndInterface) && !this.checkNext(TokenKind.As)) {
-                break;
-            }
         }
 
         //consume the final `end interface` token


Test patch:
diff --git a/src/parser/tests/statement/InterfaceStatement.spec.ts b/src/parser/tests/statement/InterfaceStatement.spec.ts
index 7d952d10..7aae48e9 100644
--- a/src/parser/tests/statement/InterfaceStatement.spec.ts
+++ b/src/parser/tests/statement/InterfaceStatement.spec.ts
@@ -96,4 +96,13 @@ describe('InterfaceStatement', () => {
             end interface
         `, undefined, undefined, undefined, true);
     });
+
+    it('supports empty interfaces', () => {
+        const file = program.setFile('source/main.bs', `
+           interface SomeInterface
+           end interface
+        `);
+        program.validate();
+        expectZeroDiagnostics(file);
+    });
 });