Diagnose reserved BrightScript builtins used as values#1697
Open
Diagnose reserved BrightScript builtins used as values#1697
Conversation
Adds a new diagnostic (`reservedBuiltinUsedAsValue`, code 1147) that
fires when a reserved call-only BrightScript builtin appears in any
non-call position. These builtins compile cleanly today in the
brighterscript parser but produce a device compile error
(typically `Syntax Error. Builtin function call expected`, hex &h9d,
or `Syntax Error` &h02 depending on the builtin).
Builtins covered (all device-verified):
- box, createobject, getglobalaa
- getlastruncompileerror, getlastrunruntimeerror
- objfun, pos, run, tab, type
The check fires from `primary()` after an identifier match, gated on
`peek().kind !== LeftParen` so canonical call sites (e.g. `type(x)`,
`Box(1)`, `CreateObject("roSGNode", "Node")`) remain clean. Property
access (`m.type = 1`) and AA-literal keys (`{ type: 1 }`) are not
affected because they use different parse paths. BrighterScript's
`type Name = ...` statement is also unaffected.
Adds 38 tests:
- per-builtin RHS-read flag + canonical-call no-flag pairs (16)
- per-builtin parameter-name 1045 regression tests (10)
- ObjFun/type-specific edge cases: passed-as-arg, property access,
AA-keys, type-statement, case-insensitivity (12)
`Eval` is intentionally excluded from this set. Its compile error
(&h90 RSG 1.2 deprecation) is a different concern and merits a
separate, more pointed diagnostic.
eval is a call-only builtin like the others here — referencing it as a value (`x = eval`, etc.) is a device compile error.
TwitchBronBron
requested changes
May 4, 2026
Rename CallOnlyBuiltins to UnreferencableBuiltins and move the value-read check from the parser into BrsFileValidator so plugin-injected AST nodes are also caught. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new diagnostic (
reservedBuiltinUsedAsValue, code 1147) that fires when a reserved call-only BrightScript builtin appears in any non-call position. These builtins parse cleanly today but produce a device compile error (Syntax Error. Builtin function call expected, &h9d, or genericSyntax Error&h02 for some).Builtins covered:
box,createobject,eval,getglobalaagetlastruncompileerror,getlastrunruntimeerrorobjfun,pos,run,tab,typeBefore / after
x = ObjFun'ObjFun' is a reserved builtin and can only be used as a function call (e.g. 'ObjFun(...)')x = typex = evalprint foo(Box, 2)ObjFun(),type(123),Box(1),eval(...)etc.m.type = 1,{ type: 1 }type Name = ...(BrighterScript type alias)Implementation
CallOnlyBuiltinsset in src/lexer/TokenKind.ts, keyed by lowercased text.reservedBuiltinUsedAsValue(code 1147) in src/DiagnosticMessages.ts.primary()at src/parser/Parser.ts that fires whentext.toLowerCase()is inCallOnlyBuiltinsandpeek().kind !== LeftParen.Why these specific builtins
Each was tested on a Roku device by writing the various forms (
x = Foo,Foo(...),m.Foo = 1,{ Foo: 1 },function f(Foo)) and observing whether each form was a device compile error, runtime error, or successful execution. The 11 names above are the set where non-call usage is a hard compile error on device.evalis included because referencing it as a value has always been a compile error across firmware versions; its separate deprecation/removal lifecycle for call sites is handled in #1698.Test plan
npm test— 2806 passing, 0 failingnpm run lint— cleantype statementregression test updated to expect the new diagnostic forreturn type🤖 Generated with Claude Code