Processing pipeline
Installation
npm install kopytko-brightscript-parserBasic usage
The three main entry points: tokenize, parse, and buildScopes.
import { tokenize, parse, buildScopes } from 'kopytko-brightscript-parser';
const source = `
function add(a as Integer, b as Integer) as Integer
return a + b
end function
`;
// 1. Tokenize — get the raw token stream
const tokens = tokenize(source);
console.log(tokens.length); // 20 tokens
console.log(tokens[0].kind); // 'Function'
console.log(tokens[0].text); // 'function'
// 2. Parse — get the full CST + diagnostics
const { root, diagnostics } = parse(source);
console.log(diagnostics.length); // 0 (no errors)
// 3. Scope analysis
const scope = buildScopes(root);
const addDecl = scope.declarations.get('add');
console.log(addDecl?.kind); // 'function'Live token visualizer
Edit the BrightScript source below to see how the lexer splits it into tokens in real time. Each token kind is color-coded by category.
' BrightScript sample — edit to explore function greet(name as String) as String if name = "" or name = invalid then return "Hello, World!" end if return "Hello, " + name + "!" end function sub main() colors = ["red", "green", "blue"] for i = 0 to colors.Count() - 1 print colors[i] ' current color end for m.count = 0 m.count++ result = greet("Roku") end sub
Token kind reference
Literals
IntegerLiteralLongIntegerLiteralFloatLiteralDoubleLiteralStringLiteral Identifiers
Identifier Type names
TypeName — parser-produced; any token after as
The only parser-produced token kind. The lexer emits type names
as Identifier tokens;
the parser re-classifies whichever token follows as to
TypeName in the CST.
Use isTypeKeyword(kind) to detect them.
Keywords
AndAsBoxCatchContinueCreateObjectDimEachElseElseIfEndEndForEndFunctionEndIfEndSubEndTryEndWhileEvalExitExitWhileFalseForFunctionGetGlobalAAGetLastRunCompileErrorGetLastRunRunTimeErrorGotoIfInInvalidLetLineNumModNextNotObjFunOrPosPrintReturnRunStepStopSubTabThenThrowToTrueTryTypeWhile Operators
PlusMinusStarSlashBackslashCaretEqualLessGreaterLessGreaterLessEqualGreaterEqualLeftShiftRightShiftPlusEqualMinusEqualStarEqualSlashEqualBackslashEqualLeftShiftEqualRightShiftEqualPlusPlusMinusMinusQuestionDotQuestionBracketQuestionParenQuestionAt Punctuation
LeftParenRightParenLeftBracketRightBracketLeftBraceRightBraceDotCommaColonAt Preprocessor
HashIfHashElseIfHashElseHashEndIfHashConstHashError Typed AST & visitor
wrapNode() converts a raw CST node into a typed wrapper.
walk() traverses the tree calling your visitor methods.
import { parse, wrapNode, SourceFile, FunctionDeclaration, walk } from 'kopytko-brightscript-parser';
const { root } = parse(`
function greet(name as String) as String
return "Hello, " + name
end function
`);
const file = wrapNode(root) as SourceFile;
// Walk the AST with a visitor
walk(file, {
visitFunctionDeclaration(node: FunctionDeclaration) {
console.log('Function:', node.name?.text);
console.log('Params:', node.parameterList?.parameters.map(p => p.name?.text));
console.log('ReturnType:', node.returnTypeClause?.typeName?.text);
}
});
// Function: greet
// Params: ['name']
// ReturnType: StringScope analysis
buildScopes(root) walks the AST and builds a hierarchical scope tree.
resolve(name, scope) does case-insensitive lookup up the scope chain.
import { parse, buildScopes, resolve, findScopeAtLine } from 'kopytko-brightscript-parser';
const source = `
function outer() as Void
x = 10
inner = function(y as Integer) as Integer
return x + y
end function
end function
`;
const { root } = parse(source);
const fileScope = buildScopes(root);
// outer() scope
const outerScope = fileScope.children[0];
console.log(outerScope.ownerName); // 'outer'
console.log([...outerScope.declarations.keys()]);
// ['x', 'inner']
// Resolve a name from the inner scope
const innerScope = outerScope.children[0];
const xDecl = resolve('x', innerScope);
console.log(xDecl?.kind); // 'variable' (found in parent scope)
// Find innermost scope at a given line (0-based)
const scope = findScopeAtLine(fileScope, 4);
console.log(scope.ownerName); // '<anonymous>'Built-in catalogs
BRIGHTSCRIPT_BUILTINS Complete BrightScript standard library with signatures, return types, and descriptions.
BRIGHTSCRIPT_COMPONENTS All ro* component interfaces with method signatures, firmware since, and deprecation flags.
SG_NODES Full SceneGraph node catalog including interfaces, fields, and parent hierarchy.
findBuiltin(name) → BuiltinFunction | undefined Look up a BrightScript built-in function by name (case-insensitive). Returns signature, return type, and documentation.
findComponent(name) → Component | undefined Look up a ro* component (roArray, roSGNode, roUrlTransfer, …) by name.
getComponentMethods(name) → Method[] Get all interface methods of a ro* component, including firmware version and deprecation flags.
findMethodInterface(component, method) → MethodInterface | undefined Find a specific method's full interface definition including parameter types and return type.
applyCasing(text, option) → string Apply a casing option (lower-case, pascal-case, camel-case, …) to an identifier string.
applyCasingWithOverrides(text, config, kind) → string Apply casing according to a CasingConfig, checking per-identifier exact overrides first.
resolveKeywordCasing(text, config) → string Resolve the correct casing for a keyword (if, function, …) from a CasingConfig.
CasingConfig → interface Configuration interface for all identifier casing dimensions (keyword, builtin, type, literal, logicOperator, …).
inferTypesFromAst(root) → TypeMap Walk the AST and build a variable→type map. Used by the extension for member completion after CreateObject().
buildCallGraph(root) → CallGraph Build a function call graph from the AST: who calls whom, with argument counts.
getSymbolInfo(name, root) → SymbolInfo | undefined Get rich hover/definition data for a symbol — works for both built-ins and user functions.
inferNumericLiteralType(text) → 'Integer' | 'LongInteger' | 'Float' | 'Double' Infer the precise BrightScript numeric type from a literal's text (e.g. "42" → Integer, "3.14" → Float, "1%" → Integer).
isNumericLiteral(kind) → boolean Returns true if the TokenKind is any numeric literal variant (Integer, LongInteger, Float, Double).
findNodeAtPosition(root, line, col) → SyntaxNode | undefined Find the deepest CST node that contains the given 0-based line and column. Used by hover, completion, and go-to-definition providers.
findTokenAtPosition(root, line, col) → Token | undefined Find the token at the given 0-based line and column, including tokens with trivia.
matchesGlob(str, pattern) → boolean Test a path string against a glob pattern (supports ** wildcards).
findMatchingGlob(globs, str) → string | undefined Return the first glob pattern from an array that matches the given string.
parseXmlScriptUris(xml) → string[] Extract all <script uri="…"> URIs from a SceneGraph component XML string.
parseXmlInterface(xml) → { fields, functions } Parse the <interface> block from component XML, returning field and function definitions.
parseXmlExtends(xml) → string | undefined Get the extends attribute value from a <component> XML string.
KEYWORD_MAP → Map<string, TokenKind> Map from lowercase keyword text to TokenKind (e.g. "if" → TokenKind.If, "endwhile" → TokenKind.EndWhile).
isKeyword(kind) → boolean Returns true if the TokenKind is a reserved BrightScript keyword (produced by the lexer).
isTypeKeyword(kind) → boolean Returns true if the TokenKind is TypeName — the parser-produced kind for any token that follows an as keyword in a type annotation position.