Repository: sjbarag/brs
Pull request #600 (2020-12-23 23:57:50)

Implement RoLongInteger, cast int to LongInt, float to Double
This implements the [RoLongInteger](https://developer.roku.com/en-ca/docs/references/brightscript/components/rolonginteger.md), also adds support of auto casting `roInt` to `roLongInt`, `roFloat` to `roDouble`.

fixes #364 


Patch:
diff --git a/README.md b/README.md
index 69e0da9..4a2315e 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@
       - [Testing](#testing)
       - [Cleaning](#cleaning)
       - [All Together](#all-together)
+  - [Gaps](#gaps)
   - [Extensions](#extensions)
     - [`_brs_.getStackTrace(numEntries = 10, excludePatterns = [])`](#_brs_getstacktracenumentries--10-excludepatterns--)
     - [`_brs_.global`](#_brs_global)
@@ -86,7 +87,7 @@ Dennis Ritchie said "Hello, World!"
 The [Roku](https://roku.com) series of media streaming devices are wildly popular amongst consumers, and several [very](https://netflix.com) [popular](https://hulu.com) [streaming](https://amazon.com/primevideo) [services](https://crackle.com) offer Channels for the Roku platform.  Unfortunately, Roku chanels *must* be written in a language called BrightScript, which is only executable directly on a Roku device.  BRS hopes to change that by allowing Roku developers to test their code on their own machines, thus improving the quality of their channels and the end-user's experience as a whole.
 
 ## So can I use this to watch TV without a Roku?
-Nope!  The BRS project currently has no intention of emulating the Roku user interface, integrating with the Roku store, or emulating content playback.  In addition to likely getting this project in legal trouble, that sort of emulation is a ton of work.  BRS isn't mature enough to be able to sustain that yet.
+Nope!  The BRS project currently has no intention of emulating the Roku user interface, integrating with the Roku store, or emulating content playback.  In addition to likely getting this project in legal trouble, that sort of emulation is a ton of work.
 
 ## Building from source
 The BRS project follows pretty standard `node` development patterns, with the caveat that it uses `yarn` for dependency management.
@@ -165,6 +166,9 @@ Thanks to the [npm-run-all](https://www.npmjs.com/package/npm-run-all) package,
 $ yarn run-s clean build test
 ```
 
+## Gaps
+The API provided to BrightScript developers is quite large, and implementing it in its entirety is a daunting task.  Parts in the standard library included with the Reference BrightScript Implementation (RBI) are [listed in NotImplemented.md](./docs/NotImplemented.md).
+
 ## Extensions
 
 For the most part, `brs` attempts to emulate BrightScript as closely as possible. However, in the spirit of unit testing, it also has a few extensions that will help with testing.
diff --git a/docs/NotImplemented.md b/docs/NotImplemented.md
new file mode 100644
index 0000000..b5c6df8
--- /dev/null
+++ b/docs/NotImplemented.md
@@ -0,0 +1,159 @@
+# Statements
+* [try/catch/throw](https://developer.roku.com/docs/references/brightscript/language/error-handling.md)
+* [goto](https://developer.roku.com/docs/references/brightscript/language/program-statements.md#goto-label)
+* [end](https://developer.roku.com/docs/references/brightscript/language/program-statements.md#end)
+* [stop](https://developer.roku.com/docs/references/brightscript/language/program-statements.md#stop) and the associated interactive debugger
+
+# Global Functions
+* [Eval](https://developer.roku.com/docs/references/brightscript/language/runtime-functions.md#evalcode-as-string-as-dynamic) - deprecated in RBI and will not be implemented in `brs`
+* [GetLastRunCompileError](https://developer.roku.com/docs/references/brightscript/language/runtime-functions.md#getlastruncompileerror-as-object) - compile errors are reported immediately
+* [GetLastRunRuntimeError](https://developer.roku.com/docs/references/brightscript/language/runtime-functions.md#getlastrunruntimeerror-as-integer) - runtime errors are reported immediately
+* [RunGarbageCollector](https://developer.roku.com/docs/references/brightscript/language/global-utility-functions.md#rungarbagecollector-as-object)
+* [Sleep](https://developer.roku.com/docs/references/brightscript/language/global-utility-functions.md#sleepmilliseconds-as-integer-as-void)
+* [Wait](https://developer.roku.com/docs/references/brightscript/language/global-utility-functions.md#waittimeout-as-integer-port-as-object-as-object) - requires `roMessagePort` to be implemented (see below)
+* [UpTime](https://developer.roku.com/docs/references/brightscript/language/global-utility-functions.md#uptimedummy-as-integer-as-float)
+
+# BrightScript Components
+The following components are not currently implemented in `brs`, meaning that they can't be instantiated via `createObject`.  They may be implemented in the future
+
+* [roAppInfo](https://developer.roku.com/docs/references/brightscript/components/roappinfo.md)
+* [roAppManager](https://developer.roku.com/docs/references/brightscript/components/roappmanager.md)
+* [roAudioGuide](https://developer.roku.com/docs/references/brightscript/components/roaudioguide.md)
+* [roAudioMetadata](https://developer.roku.com/docs/references/brightscript/components/roaudioguide.md)
+* [roAudioPlayer](https://developer.roku.com/docs/references/brightscript/components/roaudioplayer.md)
+* [roAudioResource](https://developer.roku.com/docs/references/brightscript/components/roaudioresource.md)
+* [roBitmap](https://developer.roku.com/docs/references/brightscript/components/robitmap.md)
+* [roByteArray](https://developer.roku.com/docs/references/brightscript/components/robytearray.md)
+* [roChannelStore](https://developer.roku.com/docs/references/brightscript/components/rochannelstore.md)
+* [roCompositor](https://developer.roku.com/docs/references/brightscript/components/rocompositor.md)
+* [roDataGramSocket](https://developer.roku.com/docs/references/brightscript/components/rodatagramsocket.md)
+* [roDeviceCrypto](https://developer.roku.com/docs/references/brightscript/components/rodevicecrypto.md)
+* [roEVPCipher](https://developer.roku.com/docs/references/brightscript/components/roevpcipher.md)
+* [roEVPDigest](https://developer.roku.com/docs/references/brightscript/components/roevpdigest.md)
+* [roEVPDigest](https://developer.roku.com/docs/references/brightscript/components/roevpdigest.md)
+* [roFileSystem](https://developer.roku.com/docs/references/brightscript/components/rofilesystem.md)
+* [roFileSystem](https://developer.roku.com/docs/references/brightscript/components/rofilesystem.md)
+* [roFont](https://developer.roku.com/docs/references/brightscript/components/rofont.md)
+* [roFontRegistry](https://developer.roku.com/docs/references/brightscript/components/rofontregistry.md)
+* [roFunction](https://developer.roku.com/docs/references/brightscript/components/rofunction.md)
+* [roHdmiStatus](https://developer.roku.com/docs/references/brightscript/components/rohdmistatus.md)
+* [roHMAC](https://developer.roku.com/docs/references/brightscript/components/rohmac.md)
+* [roHttpAgent](https://developer.roku.com/docs/references/brightscript/components/rohttpagent.md)
+* [roHttpAgent](https://developer.roku.com/docs/references/brightscript/components/rohttpagent.md)
+* [roImageMetadata](https://developer.roku.com/docs/references/brightscript/components/roimagemetadata.md)
+* [roInput](https://developer.roku.com/docs/references/brightscript/components/roinput.md)
+* [roList](https://developer.roku.com/docs/references/brightscript/components/rolist.md)
+* [roLocalization](https://developer.roku.com/docs/references/brightscript/components/rolocalization.md)
+* [roLongInteger](https://developer.roku.com/docs/references/brightscript/components/rolonginteger.md)
+* [roMessagePort](https://developer.roku.com/docs/references/brightscript/components/romessageport.md)
+* [roMicrophone](https://developer.roku.com/docs/references/brightscript/components/romicrophone.md)
+* [roPath](https://developer.roku.com/docs/references/brightscript/components/ropath.md)
+* [roProgramGuide](https://developer.roku.com/docs/references/brightscript/components/roprogramguide.md)
+* [roRegion](https://developer.roku.com/docs/references/brightscript/components/roregion.md)
+* [roRegistry](https://developer.roku.com/docs/references/brightscript/components/roregistry.md)
+* [roRegistrySection](https://developer.roku.com/docs/references/brightscript/components/roregistrysection.md)
+* [roRSA](https://developer.roku.com/docs/references/brightscript/components/rorsa.md)
+* [roScreen](https://developer.roku.com/docs/references/brightscript/components/roscreen.md)
+* [roSGScreen](https://developer.roku.com/docs/references/brightscript/components/rosgscreen.md)
+* [roSocketAddress](https://developer.roku.com/docs/references/brightscript/components/rosocketaddress.md)
+* [roSpringboardScreen](https://developer.roku.com/docs/references/brightscript/components/rospringboardscreen.md)
+* [roSprite](https://developer.roku.com/docs/references/brightscript/components/rosprite.md)
+* [roStreamSocket](https://developer.roku.com/docs/references/brightscript/components/rostreamsocket.md)
+* [roSystemLog](https://developer.roku.com/docs/references/brightscript/components/rosystemlog.md)
+* [roTextToSpeech](https://developer.roku.com/docs/references/brightscript/components/rotexttospeech.md)
+* [roTextureManager](https://developer.roku.com/docs/references/brightscript/components/rotexturemanager.md)
+* [roTextureRequest](https://developer.roku.com/docs/references/brightscript/components/rotexturerequest.md)
+* [roUrlTransfer](https://developer.roku.com/docs/references/brightscript/components/rourltransfer.md)
+* [roVideoPlayer](https://developer.roku.com/docs/references/brightscript/components/rovideoplayer.md)
+* [roXMLElement](https://developer.roku.com/docs/references/brightscript/components/roxmlelement.md)
+* [roXMLList](https://developer.roku.com/docs/references/brightscript/components/roxmllist.md)
+
+## Deprecated in RBI
+The following components are deprecated in the Reference BrightScript Interpreter (RBI), and thus will not be implemented in this project.
+
+* [roCaptionRenderer](https://developer.roku.com/docs/references/brightscript/components/robytearray.md)
+* [roCodeRegistrationScreen](https://developer.roku.com/docs/references/brightscript/components/rocoderegistrationscreen.md)
+* [roFontMetrics](https://developer.roku.com/docs/references/brightscript/components/rofontmetrics.md)
+* [roGridScreen](https://developer.roku.com/docs/references/brightscript/components/rogridscreen.md)
+* [roImageCanvas](https://developer.roku.com/docs/references/brightscript/components/roimagecanvas.md)
+* [roKeyboardScreen](https://developer.roku.com/docs/references/brightscript/components/rokeyboardscreen.md)
+* [roListScreen](https://developer.roku.com/docs/references/brightscript/components/rolistscreen.md)
+* [roMessageDialog](https://developer.roku.com/docs/references/brightscript/components/romessagedialog.md)
+* [roOneLineDialog](https://developer.roku.com/docs/references/brightscript/components/roonelinedialog.md)
+* [roParagraphScreen](https://developer.roku.com/docs/references/brightscript/components/roparagraphscreen.md)
+* [roPinEntryDialog](https://developer.roku.com/docs/references/brightscript/components/ropinentrydialog.md)
+* [roPosterScreen](https://developer.roku.com/docs/references/brightscript/components/roposterscreen.md)
+* [roSearchHistory](https://developer.roku.com/docs/references/brightscript/components/rosearchhistory.md)
+* [roSearchHistory](https://developer.roku.com/docs/references/brightscript/components/rosearchhistory.md)
+* [roSlideShow](https://developer.roku.com/docs/references/brightscript/components/roslideshow.md)
+* [roTextScreen](https://developer.roku.com/docs/references/brightscript/components/rotextscreen.md)
+* [roVideoScreen](https://developer.roku.com/docs/references/brightscript/components/rovideoscreen.md)
+
+# SceneGraph
+Custom SceneGraph components (defined in XML files) are supported, but with a few caveats:
+
+1. The entire chain of `extends="..."` components must be implemented by `brs` or custom nodes.  A missing standard-library node will result in a partially-created component that likely won't function properly.
+2. BrightScript included in a [CDATA](https://en.wikipedia.org/wiki/CDATA) tag is ignored.
+
+Additionally, many components are implemented as "stubs" - their fields exist and are of the correct type, but assigning values to them doesn't trigger any effects (e.g. assigning a string to a `Label`'s `.text` field doesn't change the resulting `.boundingRect()`).  This is intentional for now, as some components are either very complex (e.g. `MarkupGrid`) or would be prohibitively expensive to make accurate (e.g. font rendering nuances that affect layout, wrapping, etc.).  Given that `brs` doesn't intend to implement any sort of graphical rendering, implementing some SceneGraph components as non-stubs would lead to near-meaningless components (what's it mean for an `Video` component to exist if it doesn't play video, advance progress, buffer, etc.?).
+
+| Name | Status | Notes |
+| ---- | ------ | ----- |
+| [AnimationBase](https://developer.roku.com/docs/references/scenegraph/abstract-nodes/animationbase.md) | ⛔ None | Includes all subclasses |
+| [Animation](https://developer.roku.com/docs/references/scenegraph/animation-nodes/animation.md) | ⛔ None | Extends `AnimationBase` |
+| [ArrayGrid](https://developer.roku.com/docs/references/scenegraph/abstract-nodes/arraygrid.md) | ⚠ Stub | |
+| [Audio](https://developer.roku.com/docs/references/scenegraph/media-playback-nodes/audio.md) | ⛔ None | |
+| [BusySpinner](https://developer.roku.com/docs/references/scenegraph/widget-nodes/busyspinner.md) | ⛔ None | |
+| [ButtonGroup](https://developer.roku.com/docs/references/scenegraph/layout-group-nodes/buttongroup.md) | ⛔ None | |
+| [Button](https://developer.roku.com/docs/references/scenegraph/widget-nodes/button.md) | ⛔ None | |
+| [ChannelStore](https://developer.roku.com/docs/references/scenegraph/control-nodes/channelstore.md) | ⛔ None | |
+| [CheckList](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/checklist.md) | ⛔ None | |
+| [ColorFieldInterpolator](https://developer.roku.com/docs/references/scenegraph/animation-nodes/colorfieldinterpolator.md) | ⛔ None | Extends `AnimationBase` |
+| [ComponentLibrary](https://developer.roku.com/docs/references/scenegraph/control-nodes/componentlibrary.md) | ⚠ Partial | `pkg:/`-local libraries only (as `.zip` files) |
+| [ContentNode](https://developer.roku.com/docs/references/scenegraph/control-nodes/contentnode.md) | ✅ Complete | |
+| [Dialog](https://developer.roku.com/docs/references/scenegraph/dialog-nodes/dialog.md) | ⛔ None | |
+| [FloatFieldInterpolator](https://developer.roku.com/docs/references/scenegraph/animation-nodes/floatfieldinterpolator.md) | ⛔ None | Extends `AnimationBase` |
+| [Font](https://developer.roku.com/docs/references/scenegraph/typographic-nodes/font.md) | ⚠ Stub | |
+| [GridPanel](https://developer.roku.com/docs/references/scenegraph/sliding-panels-nodes/gridpanel.md) | ⛔ None | |
+| [Group](https://developer.roku.com/docs/references/scenegraph/layout-group-nodes/group.md) | ⚠ Partial | Fields can be set, but `renderTracking` never gets updated (because nothing renders) |
+| [KeyboardDialog](https://developer.roku.com/docs/references/scenegraph/dialog-nodes/keyboarddialog.md) | ⛔ None | Extends `Dialog` |
+| [Keyboard](https://developer.roku.com/docs/references/scenegraph/widget-nodes/keyboard.md) | ⛔ None | |
+| [LabelList](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/labellist.md) | ⛔ None | |
+| [Label](https://developer.roku.com/docs/references/scenegraph/renderable-nodes/label.md) | ⚠ Stub | |
+| [LayoutGroup](https://developer.roku.com/docs/references/scenegraph/layout-group-nodes/layoutgroup.md) | ⚠ Stub | |
+| [ListPanel](https://developer.roku.com/docs/references/scenegraph/sliding-panels-nodes/listpanel.md) | ⛔ None | |
+| [MarkupGrid](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/markupgrid.md) | ⚠ Stub | Assigning `ContentNode` to `.content` field doesn't create items |
+| [MarkupList](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/markuplist.md) | ⛔ None | |
+| [MaskGroup](https://developer.roku.com/docs/references/scenegraph/control-nodes/maskgroup.md) | ⛔ None | |
+| [MiniKeyboard](https://developer.roku.com/docs/references/scenegraph/widget-nodes/minikeyboard.md) | ⚠ Stub | |
+| [Node](https://developer.roku.com/docs/references/scenegraph/abstract-nodes/node.md) | ✅ Mostly complete | Some interfaces may not be accurate (e.g. `ifSGNodeBoundingRect`) |
+| [OverhangPanelSetScene](https://developer.roku.com/docs/references/scenegraph/sliding-panels-nodes/overhangpanelsetscene.md) | ⛔ None | |
+| [Overhang](https://developer.roku.com/docs/references/scenegraph/sliding-panels-nodes/overhang.md) | ⛔ None | |
+| [PanelSet](https://developer.roku.com/docs/references/scenegraph/sliding-panels-nodes/panelset.md) | ⛔ None | |
+| [Panel](https://developer.roku.com/docs/references/scenegraph/sliding-panels-nodes/panel.md) | ⛔ None | |
+| [ParallelAnimation](https://developer.roku.com/docs/references/scenegraph/animation-nodes/parallelanimation.md) | ⛔ None | Extends `AnimationBase` |
+| [ParentalControlPinpad](https://developer.roku.com/docs/references/scenegraph/widget-nodes/parentalcontrolpinpad.md) | ⛔ None | |
+| [PinDialog](https://developer.roku.com/docs/references/scenegraph/dialog-nodes/pindialog.md) | ⛔ None | Extends `Dialog` |
+| [Pinpad](https://developer.roku.com/docs/references/scenegraph/widget-nodes/pinpad.md) | ⛔ None | |
+| [PosterGrid](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/postergrid.md) | ⛔ None | |
+| [Poster](https://developer.roku.com/docs/references/scenegraph/renderable-nodes/poster.md) ⚠ Stub | Does not fetch images |
+| [ProgressDialog](https://developer.roku.com/docs/references/scenegraph/dialog-nodes/progressdialog.md) | ⛔ None | Extends `Dialog` |
+| [RadioButtonList](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/radiobuttonlist.md) | ⛔ None | |
+| [Rectangle](https://developer.roku.com/docs/references/scenegraph/renderable-nodes/rectangle.md) | ⚠ Stub | |
+| [RowList](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/rowlist.md) | ⛔ None | |
+| [Scene](https://developer.roku.com/docs/references/scenegraph/abstract-nodes/scene.md) | ⚠ Stub | |
+| [ScrollableText](https://developer.roku.com/docs/references/scenegraph/typographic-nodes/scrollabletext.md) | ⛔ None | |
+| [ScrollingLabel](https://developer.roku.com/docs/references/scenegraph/typographic-nodes/scrollinglabel.md) | ⛔ None | |
+| [SequentialAnimation](https://developer.roku.com/docs/references/scenegraph/animation-nodes/sequentialanimation.md) | ⛔ None | Extends `AnimationBase` |
+| [SimpleLabel](https://developer.roku.com/docs/references/scenegraph/renderable-nodes/simplelabel.md) | ⛔ None | |
+| [SoundEffect](https://developer.roku.com/docs/references/scenegraph/media-playback-nodes/soundeffect.md) | ⛔ None | |
+| [TargetGroup](https://developer.roku.com/docs/references/scenegraph/layout-group-nodes/targetgroup.md) | ⚠ Stub | |
+| [TargetList](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/targetlist.md) | ⛔ None | |
+| [TargetSet](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/targetset.md) | ⛔ None | |
+| [Task](https://developer.roku.com/docs/references/scenegraph/control-nodes/task.md) | ⛔ None | |
+| [TextEditBox](https://developer.roku.com/docs/references/scenegraph/widget-nodes/texteditbox.md) | ⚠ Stub | |
+| [TimeGrid](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/timegrid.md) | ⛔ None | |
+| [Timer](https://developer.roku.com/docs/references/scenegraph/control-nodes/timer.md) | ⚠ Stub | |
+| [Vector2DFieldInterpolator](https://developer.roku.com/docs/references/scenegraph/animation-nodes/vector2dfieldinterpolator.md) | ⛔ None | Extends `AnimationBase` |
+| [Video](https://developer.roku.com/docs/references/scenegraph/media-playback-nodes/video.md) | ⛔ None | |
+| [ZoomRowList](https://developer.roku.com/docs/references/scenegraph/list-and-grid-nodes/zoomrowlist.md) | ⛔ None | |
diff --git a/package.json b/package.json
index 57edb6a..95955de 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "brs",
-  "version": "0.40.1",
+  "version": "0.41.0",
   "description": "An interpreter for the BrightScript language that runs on non-Roku platforms.",
   "author": "Sean Barag <sean@barag.org>",
   "license": "MIT",
diff --git a/src/brsTypes/Callable.ts b/src/brsTypes/Callable.ts
index 72e488f..7d7a419 100644
--- a/src/brsTypes/Callable.ts
+++ b/src/brsTypes/Callable.ts
@@ -6,6 +6,7 @@ import { Location } from "../lexer";
 import { Int32 } from "./Int32";
 import { Float } from "./Float";
 import { Double } from "./Double";
+import { Int64 } from "./Int64";
 
 /** An argument to a BrightScript `function` or `sub`. */
 export interface Argument {
@@ -282,6 +283,14 @@ export class Callable implements Brs.BrsValue {
                 return;
             }
 
+            if (
+                expected.type.kind === Brs.ValueKind.Int64 &&
+                received.kind === Brs.ValueKind.Int32
+            ) {
+                args[index] = new Int64(received.getValue());
+                return;
+            }
+
             if (expected.type.kind !== received.kind) {
                 reasons.push({
                     reason: MismatchReason.ArgumentTypeMismatch,
diff --git a/src/brsTypes/Int64.ts b/src/brsTypes/Int64.ts
index 954e0dc..bae2d5f 100644
--- a/src/brsTypes/Int64.ts
+++ b/src/brsTypes/Int64.ts
@@ -4,8 +4,10 @@ import { BrsNumber, Numeric } from "./BrsNumber";
 import { ValueKind, Comparable } from "./BrsType";
 import { Float } from "./Float";
 import { Double } from "./Double";
+import { Boxable } from "./Boxing";
+import { roLongInteger } from "./components/RoLongInteger";
 
-export class Int64 implements Numeric, Comparable {
+export class Int64 implements Numeric, Comparable, Boxable {
     readonly kind = ValueKind.Int64;
     private readonly value: Long;
 
@@ -217,4 +219,8 @@ export class Int64 implements Numeric, Comparable {
     toString(parent?: BrsType): string {
         return this.value.toString();
     }
+
+    box() {
+        return new roLongInteger(this);
+    }
 }
diff --git a/src/brsTypes/components/BrsObjects.ts b/src/brsTypes/components/BrsObjects.ts
index 495f5d2..98269f6 100644
--- a/src/brsTypes/components/BrsObjects.ts
+++ b/src/brsTypes/components/BrsObjects.ts
@@ -5,15 +5,18 @@ import { RoDateTime } from "./RoDateTime";
 import { Timespan } from "./Timespan";
 import { createNodeByType } from "./RoSGNode";
 import { RoRegex } from "./RoRegex";
+import { RoXMLElement } from "./RoXMLElement";
 import { BrsString, BrsBoolean } from "../BrsType";
 import { RoString } from "./RoString";
 import { roBoolean } from "./RoBoolean";
 import { roDouble } from "./RoDouble";
 import { roFloat } from "./RoFloat";
 import { roInt } from "./RoInt";
+import { roLongInteger } from "./RoLongInteger";
 import { Double } from "../Double";
 import { Float } from "../Float";
 import { Int32 } from "../Int32";
+import { Int64 } from "../Int64";
 import { Interpreter } from "../../interpreter";
 import { roInvalid } from "./RoInvalid";
 
@@ -32,10 +35,12 @@ export const BrsObjects = new Map<string, Function>([
         "roregex",
         (_: Interpreter, expression: BrsString, flags: BrsString) => new RoRegex(expression, flags),
     ],
+    ["roxmlelement", (_: Interpreter) => new RoXMLElement()],
     ["rostring", (_: Interpreter) => new RoString()],
     ["roboolean", (_: Interpreter, literal: BrsBoolean) => new roBoolean(literal)],
     ["rodouble", (_: Interpreter, literal: Double) => new roDouble(literal)],
     ["rofloat", (_: Interpreter, literal: Float) => new roFloat(literal)],
     ["roint", (_: Interpreter, literal: Int32) => new roInt(literal)],
+    ["rolonginteger", (_: Interpreter, literal: Int64) => new roLongInteger(literal)],
     ["roinvalid", (_: Interpreter) => new roInvalid()],
 ]);
diff --git a/src/brsTypes/components/RoLongInteger.ts b/src/brsTypes/components/RoLongInteger.ts
new file mode 100644
index 0000000..ff55e5f
--- /dev/null
+++ b/src/brsTypes/components/RoLongInteger.ts
@@ -0,0 +1,79 @@
+import { BrsComponent } from "./BrsComponent";
+import { BrsValue, ValueKind, BrsString, BrsBoolean, BrsInvalid, Comparable } from "../BrsType";
+import { Callable, StdlibArgument } from "../Callable";
+import { Interpreter } from "../../interpreter";
+import { BrsType } from "..";
+import { Unboxable } from "../Boxing";
+import { Int64 } from "../Int64";
+
+export class roLongInteger extends BrsComponent implements BrsValue, Unboxable {
+    readonly kind = ValueKind.Object;
+    private intrinsic: Int64;
+
+    public getValue(): Int64 {
+        return this.intrinsic;
+    }
+
+    constructor(initialValue: Int64) {
+        super("roLongInteger");
+
+        this.intrinsic = initialValue;
+        this.registerMethods({
+            ifLongInt: [this.getLongInt, this.setLongInt],
+            ifToStr: [this.toStr],
+        });
+    }
+
+    unbox() {
+        return this.intrinsic;
+    }
+
+    equalTo(other: BrsType): BrsBoolean {
+        if (other instanceof roLongInteger) {
+            return BrsBoolean.from(
+                other.intrinsic.getValue().low === this.intrinsic.getValue().low
+            );
+        }
+
+        return BrsBoolean.False;
+    }
+
+    toString(_parent?: BrsType): string {
+        return this.intrinsic.toString();
+    }
+
+    // ---------- ifLongInt ----------
+
+    private getLongInt = new Callable("getLongInt", {
+        signature: {
+            args: [],
+            returns: ValueKind.Int64,
+        },
+        impl: (interpreter: Interpreter) => {
+            return this.intrinsic;
+        },
+    });
+
+    private setLongInt = new Callable("setLongInt", {
+        signature: {
+            args: [new StdlibArgument("value", ValueKind.Int64)],
+            returns: ValueKind.Void,
+        },
+        impl: (_interpreter, value: Int64) => {
+            this.intrinsic = value;
+            return BrsInvalid.Instance;
+        },
+    });
+
+    // ---------- ifToStr ----------
+
+    private toStr = new Callable("toStr", {
+        signature: {
+            args: [],
+            returns: ValueKind.String,
+        },
+        impl: (interpreter: Interpreter) => {
+            return new BrsString(this.intrinsic.toString());
+        },
+    });
+}
diff --git a/src/brsTypes/components/RoSGNode.ts b/src/brsTypes/components/RoSGNode.ts
index 6d9c9da..8b2b252 100644
--- a/src/brsTypes/components/RoSGNode.ts
+++ b/src/brsTypes/components/RoSGNode.ts
@@ -26,6 +26,7 @@ import { Environment } from "../../interpreter/Environment";
 import { roInvalid } from "./RoInvalid";
 import type * as MockNodeModule from "../../extensions/MockNode";
 import { BlockEnd } from "../../parser/Statement";
+import { Stmt } from "../../parser";
 
 interface BrsCallback {
     interpreter: Interpreter;
@@ -268,11 +269,35 @@ export class Field {
     }
 }
 
+/* Hierarchy of all node Types. Used to discover is a current node is a subtype of another node */
+const subtypeHierarchy = new Map<string, string>();
+
+/**
+ *  Checks the node sub type hierarchy to see if the current node is a sub component of the given node type
+ *
+ * @param {string} currentNodeType
+ * @param {string} checkType
+ * @returns {boolean}
+ */
+function isSubtypeCheck(currentNodeType: string, checkType: string): boolean {
+    checkType = checkType.toLowerCase();
+    currentNodeType = currentNodeType.toLowerCase();
+    if (currentNodeType === checkType) {
+        return true;
+    }
+    let nextNodeType = subtypeHierarchy.get(currentNodeType);
+    if (nextNodeType == null) {
+        return false;
+    }
+    return isSubtypeCheck(nextNodeType, checkType);
+}
+
 export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable {
     readonly kind = ValueKind.Object;
     private fields = new Map<string, Field>();
     private children: RoSGNode[] = [];
     private parent: RoSGNode | BrsInvalid = BrsInvalid.Instance;
+
     readonly defaultFields: FieldModel[] = [
         { name: "change", type: "roAssociativeArray" },
         { name: "focusable", type: "boolean" },
@@ -283,6 +308,7 @@ export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable {
 
     constructor(initializedFields: AAMember[], readonly nodeSubtype: string = "Node") {
         super("Node");
+        this.setExtendsType();
 
         // All nodes start have some built-in fields when created.
         this.registerDefaultFields(this.defaultFields);
@@ -337,7 +363,14 @@ export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable {
                 this.insertchildren,
             ],
             ifSGNodeFocus: [this.hasfocus, this.setfocus, this.isinfocuschain],
-            ifSGNodeDict: [this.findnode, this.issamenode, this.subtype, this.callfunc],
+            ifSGNodeDict: [
+                this.findnode,
+                this.issamenode,
+                this.subtype,
+                this.callfunc,
+                this.issubtype,
+                this.parentsubtype,
+            ],
         });
     }
 
@@ -533,6 +566,35 @@ export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable {
         return false;
     }
 
+    /* used for isSubtype */
+    protected setExtendsType() {
+        let baseClass = this.constructor;
+        let currentNodeType: string, parentType: string;
+        while (baseClass) {
+            currentNodeType = baseClass.name.toLowerCase();
+
+            const parentClass = Object.getPrototypeOf(baseClass);
+
+            if (parentClass && parentClass !== Object && parentClass.name) {
+                baseClass = parentClass;
+                parentType = parentClass.name;
+                if (parentType === "BrsComponent") {
+                    // Only care about RoSgNode and above
+                    break;
+                }
+                if (parentType === "RoSGNode") {
+                    // RoSGNode is referenced as "Node"
+                    parentType = "Node";
+                }
+                if (!subtypeHierarchy.has(currentNodeType)) {
+                    subtypeHierarchy.set(currentNodeType, parentType);
+                }
+            } else {
+                break;
+            }
+        }
+    }
+
     /**
      * Calls the function specified on this node.
      */
@@ -575,11 +637,19 @@ export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable {
                         subInterpreter.environment.setM(this.m);
                         subInterpreter.environment.setRootM(this.m);
 
-                        // Determine whether the function should get arguments or not.
-                        if (functionToCall.getFirstSatisfiedSignature(functionargs)) {
-                            return functionToCall.call(subInterpreter, ...functionargs);
-                        } else {
-                            return functionToCall.call(subInterpreter);
+                        try {
+                            // Determine whether the function should get arguments or not.
+                            if (functionToCall.getFirstSatisfiedSignature(functionargs)) {
+                                return functionToCall.call(subInterpreter, ...functionargs);
+                            } else {
+                                return functionToCall.call(subInterpreter);
+                            }
+                        } catch (reason) {
+                            if (!(reason instanceof Stmt.ReturnValue)) {
+                                // re-throw interpreter errors
+                                throw reason;
+                            }
+                            return reason.value || BrsInvalid.Instance;
                         }
                     }, componentDef.environment);
                 }
@@ -1550,6 +1620,38 @@ export class RoSGNode extends BrsComponent implements BrsValue, BrsIterable {
         },
     });
 
+    /* Checks whether the subtype of the subject node is a descendant of the subtype nodeType
+     * in the SceneGraph node class hierarchy.
+     *
+     *
+     */
+    private issubtype = new Callable("issubtype", {
+        signature: {
+            args: [new StdlibArgument("nodeType", ValueKind.String)],
+            returns: ValueKind.Boolean,
+        },
+        impl: (interpreter: Interpreter, nodeType: BrsString) => {
+            return BrsBoolean.from(isSubtypeCheck(this.nodeSubtype, nodeType.value));
+        },
+    });
+
+    /* Checks whether the subtype of the subject node is a descendant of the subtype nodeType
+     * in the SceneGraph node class hierarchy.
+     */
+    private parentsubtype = new Callable("parentsubtype", {
+        signature: {
+            args: [new StdlibArgument("nodeType", ValueKind.String)],
+            returns: ValueKind.Object,
+        },
+        impl: (interpreter: Interpreter, nodeType: BrsString) => {
+            const parentType = subtypeHierarchy.get(nodeType.value.toLowerCase());
+            if (parentType) {
+                return new BrsString(parentType);
+            }
+            return BrsInvalid.Instance;
+        },
+    });
+
     /* Returns a Boolean value indicating whether the roSGNode parameter
             refers to the same node object as this node */
     private issamenode = new Callable("issamenode", {
@@ -1633,6 +1735,9 @@ export function createNodeByType(interpreter: Interpreter, type: BrsString): RoS
         // in the correct order.
         typeDefStack.push(typeDef);
         while (typeDef) {
+            // Add the current typedef to the subtypeHierarchy
+            subtypeHierarchy.set(typeDef.name!.toLowerCase(), typeDef.extends || "Node");
+
             typeDef = interpreter.environment.nodeDefMap.get(typeDef.extends?.toLowerCase());
             if (typeDef) typeDefStack.push(typeDef);
         }
diff --git a/src/brsTypes/components/RoXMLElement.ts b/src/brsTypes/components/RoXMLElement.ts
new file mode 100644
index 0000000..a7e8f47
--- /dev/null
+++ b/src/brsTypes/components/RoXMLElement.ts
@@ -0,0 +1,90 @@
+import { RoAssociativeArray } from "./RoAssociativeArray";
+import { RoArray } from "./RoArray";
+import { BrsComponent } from "./BrsComponent";
+import { BrsBoolean, BrsString, BrsValue, ValueKind } from "../BrsType";
+import { BrsType } from "..";
+import { Callable, StdlibArgument } from "../Callable";
+import { Interpreter } from "../../interpreter";
+import { XmlDocument, XmlElement } from "xmldoc";
+
+export class RoXMLElement extends BrsComponent implements BrsValue {
+    readonly kind = ValueKind.Object;
+    private xmlNode?: XmlElement;
+
+    constructor() {
+        super("roXMLElement");
+
+        this.registerMethods({
+            ifXMLElement: [this.parse, this.getName, this.getNamedElementsCi, this.getAttributes],
+        });
+    }
+
+    toString(parent?: BrsType) {
+        return "<Component: roXMLElement>";
+    }
+
+    equalTo(other: BrsType) {
+        return BrsBoolean.False;
+    }
+
+    private parse = new Callable("parse", {
+        signature: {
+            args: [new StdlibArgument("str", ValueKind.String)],
+            returns: ValueKind.Boolean,
+        },
+        impl: (interpreter: Interpreter, str: BrsString) => {
+            try {
+                this.xmlNode = new XmlDocument(str.value);
+                return BrsBoolean.True;
+            } catch (err) {
+                this.xmlNode = undefined;
+                return BrsBoolean.False;
+            }
+        },
+    });
+
+    private getName = new Callable("getName", {
+        signature: {
+            args: [],
+            returns: ValueKind.String,
+        },
+        impl: (interpreter: Interpreter) => {
+            return new BrsString(this.xmlNode?.name ?? "");
+        },
+    });
+
+    private getNamedElementsCi = new Callable("getNamedElementsCi", {
+        signature: {
+            args: [new StdlibArgument("str", ValueKind.String)],
+            returns: ValueKind.Object,
+        },
+        impl: (interpreter: Interpreter, str: BrsString) => {
+            let neededKey = str.value.toLowerCase();
+            let arr = [];
+            for (let item of this.xmlNode?.children ?? []) {
+                if (item.type === "element" && item.name?.toLowerCase() === neededKey) {
+                    let childXmlElement = new RoXMLElement();
+                    childXmlElement.xmlNode = item;
+                    arr.push(childXmlElement);
+                }
+            }
+            return new RoArray(arr);
+        },
+    });
+
+    private getAttributes = new Callable("getAttributes", {
+        signature: {
+            args: [],
+            returns: ValueKind.Object,
+        },
+        impl: (interpreter: Interpreter) => {
+            let attrs = this.xmlNode?.attr ?? {};
+            return new RoAssociativeArray(
+                Object.entries(attrs).map(([name, value]) => ({
+                    name: new BrsString(name),
+                    value: new BrsString(value),
+                }))
+            );
+        },
+    });
+}
diff --git a/src/brsTypes/index.ts b/src/brsTypes/index.ts
index 5bdcf56..a8310ae 100644
--- a/src/brsTypes/index.ts
+++ b/src/brsTypes/index.ts
@@ -40,11 +40,13 @@ export * from "./components/RoAssociativeArray";
 export * from "./components/Timespan";
 export * from "./components/BrsObjects";
 export * from "./components/RoRegex";
+export * from "./components/RoXMLElement";
 export * from "./components/RoString";
 export * from "./components/RoBoolean";
 export * from "./components/RoDouble";
 export * from "./components/RoFloat";
 export * from "./components/RoInt";
+export * from "./components/RoLongInteger";
 export * from "./components/RoInvalid";
 export * from "./components/RoSGNodeEvent";
 export * from "./components/RoSGNode";
diff --git a/src/index.ts b/src/index.ts
index e05efa6..8836b16 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -210,6 +210,45 @@ export function lexParseSync(filenames: string[], options: Partial<ExecutionOpti
         .reduce((allStatements, statements) => [...allStatements, ...statements], []);
 }
 
+export type ExecuteWithScope = (filenames: string[], args: BrsTypes.BrsType[]) => BrsTypes.BrsType;
+/**
+ * Runs a set of files to create an execution scope, and generates an execution function that runs in that scope.
+ *
+ * @param filenamesForScope List of filenames to put into the execution scope
+ * @param options Execution options
+ *
+ * @returns A function to execute files using the created scope.
+ */
+export async function createExecuteWithScope(
+    filenamesForScope: string[],
+    options: Partial<ExecutionOptions>
+): Promise<ExecuteWithScope> {
+    let { lexerParserFn, interpreter } = await loadFiles(options);
+    let mainStatements = await lexerParserFn(filenamesForScope);
+    interpreter.exec(mainStatements);
+    // Clear any errors that accumulated, so that we can isolate errors from future calls to the execute function.
+    interpreter.errors = [];
+
+    return (filenames: string[], args: BrsTypes.BrsType[]) => {
+        let ast = lexParseSync(filenames, interpreter.options);
+        let execErrors: BrsError.BrsError[] = [];
+        let returnValue = interpreter.inSubEnv((subInterpreter) => {
+            let value = subInterpreter.exec(ast, ...args)[0] || BrsTypes.BrsInvalid.Instance;
+            execErrors = subInterpreter.errors;
+            subInterpreter.errors = [];
+            return value;
+        });
+
+        // Re-throw any errors the interpreter encounters. We can't throw them directly from the `inSubEnv` call,
+        // because they get caught by upstream handlers.
+        if (execErrors.length) {
+            throw execErrors;
+        }
+
+        return returnValue;
+    };
+}
+
 /**
  * Launches an interactive read-execute-print loop, which reads input from
  * `stdin` and executes it.
diff --git a/src/interpreter/index.ts b/src/interpreter/index.ts
index 3499851..48beb14 100644
--- a/src/interpreter/index.ts
+++ b/src/interpreter/index.ts
@@ -10,6 +10,7 @@ import {
     BrsString,
     isBrsBoolean,
     Int32,
+    Int64,
     isBrsCallable,
     Uninitialized,
     RoArray,
@@ -19,6 +20,7 @@ import {
     Callable,
     BrsNumber,
     Float,
+    Double,
 } from "../brsTypes";
 
 import { Lexeme, Location } from "../lexer";
@@ -446,19 +448,25 @@ export class Interpreter implements Expr.Visitor<BrsType>, Stmt.Visitor<BrsType>
         let requiredType = typeDesignators[name.charAt(name.length - 1)];
 
         if (requiredType && requiredType !== value.kind) {
-            return this.addError(
-                new TypeMismatch({
-                    message: `Attempting to assign incorrect value to statically-typed variable '${name}'`,
-                    left: {
-                        type: requiredType,
-                        location: statement.name.location,
-                    },
-                    right: {
-                        type: value,
-                        location: statement.value.location,
-                    },
-                })
-            );
+            if (requiredType === ValueKind.Int64 && value.kind === ValueKind.Int32) {
+                value = new Int64(value.getValue());
+            } else if (requiredType === ValueKind.Double && value.kind === ValueKind.Float) {
+                value = new Double(value.getValue());
+            } else {
+                return this.addError(
+                    new TypeMismatch({
+                        message: `Attempting to assign incorrect value to statically-typed variable '${name}'`,
+                        left: {
+                            type: requiredType,
+                            location: statement.name.location,
+                        },
+                        right: {
+                            type: value,
+                            location: statement.value.location,
+                        },
+                    })
+                );
+            }
         }
 
         this.environment.define(Scope.Function, statement.name.text, value);


Test patch:
diff --git a/test/brsTypes/components/RoLongInteger.test.js b/test/brsTypes/components/RoLongInteger.test.js
new file mode 100644
index 0000000..0c099c8
--- /dev/null
+++ b/test/brsTypes/components/RoLongInteger.test.js
@@ -0,0 +1,84 @@
+const brs = require("brs");
+const { roLongInteger, Int64, BrsBoolean, BrsString, Callable } = brs.types;
+const { Interpreter } = require("../../../lib/interpreter");
+
+describe("roLongInteger", () => {
+    describe("equality", () => {
+        it("compares to intrinsic Int64", () => {
+            let a = new roLongInteger(new Int64(40000111222));
+            let b = new roLongInteger(new Int64(0));
+            let c = new roLongInteger(new Int64(-40000111222));
+            let d = new roLongInteger(new Int64(40000111222));
+            let e = new roLongInteger(new Int64(-5));
+
+            expect(a.equalTo(b)).toBe(BrsBoolean.False);
+            expect(a.equalTo(c)).toBe(BrsBoolean.False);
+            expect(b.equalTo(c)).toBe(BrsBoolean.False);
+            expect(a.equalTo(d)).toBe(BrsBoolean.True);
+            expect(d.equalTo(a)).toBe(BrsBoolean.True);
+            expect(a.equalTo(e)).toBe(BrsBoolean.False);
+            expect(b.equalTo(e)).toBe(BrsBoolean.False);
+        });
+    });
+
+    test("toString", () => {
+        expect(new roLongInteger(new Int64(22)).toString()).toBe("22");
+    });
+
+    describe("ifLongInt, ifToStr", () => {
+        var a = new roLongInteger(new Int64(0));
+        var b = new roLongInteger(new Int64(0));
+        let interpreter;
+        let someNumberA = 305;
+        let someNumberB = 291;
+
+        beforeEach(() => {
+            interpreter = new Interpreter();
+        });
+
+        it("setLongInt", () => {
+            setLongIntA = a.getMethod("setLongInt");
+            setLongIntB = b.getMethod("setLongInt");
+
+            expect(setLongIntA).toBeInstanceOf(Callable);
+            expect(setLongIntB).toBeInstanceOf(Callable);
+
+            setLongIntA.call(interpreter, new Int64(someNumberA));
+            setLongIntB.call(interpreter, new Int64(someNumberB));
+
+            expect(a.equalTo(new roLongInteger(new Int64(someNumberA)))).toBe(BrsBoolean.True);
+            expect(b.equalTo(new roLongInteger(new Int64(someNumberB)))).toBe(BrsBoolean.True);
+        });
+
+        it("getLongInt", () => {
+            a = new roLongInteger(new Int64(someNumberA));
+            b = new roLongInteger(new Int64(someNumberB));
+
+            getLongIntA = a.getMethod("getLongInt");
+            getLongIntB = b.getMethod("getLongInt");
+
+            expect(getLongIntA).toBeInstanceOf(Callable);
+            expect(getLongIntB).toBeInstanceOf(Callable);
+
+            let resultA = getLongIntA.call(interpreter);
+            let resultB = getLongIntB.call(interpreter);
+
+            expect(resultA).toEqual(new Int64(someNumberA));
+            expect(resultB).toEqual(new Int64(someNumberB));
+        });
+
+        it("toStr", () => {
+            a = new roLongInteger(new Int64(someNumberA));
+            b = new roLongInteger(new Int64(someNumberB));
+
+            toStrA = a.getMethod("toStr");
+            toStrB = b.getMethod("toStr");
+
+            let resultA = toStrA.call(interpreter);
+            let resultB = toStrB.call(interpreter);
+
+            expect(resultA).toEqual(new BrsString(String(someNumberA)));
+            expect(resultB).toEqual(new BrsString(String(someNumberB)));
+        });
+    });
+});
diff --git a/test/brsTypes/components/RoSGNode.test.js b/test/brsTypes/components/RoSGNode.test.js
index 5d2658c..6192ac0 100644
--- a/test/brsTypes/components/RoSGNode.test.js
+++ b/test/brsTypes/components/RoSGNode.test.js
@@ -13,6 +13,7 @@ const {
     ValueKind,
     Uninitialized,
     Callable,
+    MarkupGrid,
 } = brs.types;
 const { Interpreter } = require("../../../lib/interpreter");
 const { Scope } = require("../../../lib/interpreter/Environment");
@@ -2436,6 +2437,83 @@ describe("RoSGNode", () => {
                 let result = subtype.call(interpreter);
                 expect(result.value).toBe("randomType");
             });
+
+            describe("issubtype", () => {
+                class ParentComponent extends RoSGNode {
+                    constructor(name = "ParentComponent") {
+                        super([], name);
+                    }
+                }
+
+                class ChildComponent extends ParentComponent {
+                    constructor(name = "ChildComponent") {
+                        super(name);
+                    }
+                }
+
+                it("returns true for all ancestor types, false otherwise", () => {
+                    let childNode = new ChildComponent();
+                    let issubtype = childNode.getMethod("issubtype");
+
+                    expect(issubtype.call(interpreter, new BrsString("ChildComponent")).value).toBe(
+                        true
+                    );
+                    expect(
+                        issubtype.call(interpreter, new BrsString("ParentComponent")).value
+                    ).toBe(true);
+                    expect(issubtype.call(interpreter, new BrsString("Node")).value).toBe(true);
+
+                    let parentNode = new ParentComponent();
+                    issubtype = parentNode.getMethod("issubtype");
+
+                    expect(issubtype.call(interpreter, new BrsString("ChildComponent")).value).toBe(
+                        false
+                    );
+                    expect(issubtype.call(interpreter, new BrsString("MarkupGrid")).value).toBe(
+                        false
+                    );
+                });
+
+                it("is case-insensitive", () => {
+                    let childNode = new ChildComponent();
+                    let issubtype = childNode.getMethod("issubtype");
+
+                    expect(issubtype.call(interpreter, new BrsString("Node")).value).toBe(true);
+                    expect(issubtype.call(interpreter, new BrsString("node")).value).toBe(true);
+                    expect(issubtype.call(interpreter, new BrsString("NODE")).value).toBe(true);
+                });
+
+                it("does isSubType for other built in components", () => {
+                    let markupNode = new MarkupGrid();
+                    let issubtype = markupNode.getMethod("issubtype");
+
+                    expect(issubtype.call(interpreter, new BrsString("MarkupGrid")).value).toBe(
+                        true
+                    );
+                    expect(issubtype.call(interpreter, new BrsString("ArrayGrid")).value).toBe(
+                        true
+                    );
+                    expect(issubtype.call(interpreter, new BrsString("Node")).value).toBe(true);
+                });
+            });
+
+            describe("parentsubtype", () => {
+                it("returns the parent subtype", () => {
+                    let markupNode = new MarkupGrid();
+                    let parentsubtype = markupNode.getMethod("parentsubtype");
+
+                    let result = parentsubtype.call(interpreter, new BrsString("MarkUpGrid"));
+                    expect(result.value).toBe("ArrayGrid");
+                });
+
+                it("returns invalid if it does not exist", () => {
+                    let node = new RoSGNode([]);
+                    let parentsubtype = node.getMethod("parentsubtype");
+
+                    let result = parentsubtype.call(interpreter, new BrsString("UnknownNode"));
+                    expect(result).toBe(BrsInvalid.Instance);
+                });
+            });
         });
     });
 });
diff --git a/test/brsTypes/components/RoXMLElement.test.js b/test/brsTypes/components/RoXMLElement.test.js
new file mode 100644
index 0000000..1286aad
--- /dev/null
+++ b/test/brsTypes/components/RoXMLElement.test.js
@@ -0,0 +1,100 @@
+const brs = require("brs");
+const { BrsString, RoXMLElement } = brs.types;
+const { Interpreter } = require("../../../lib/interpreter");
+
+describe("RoXMLElement", () => {
+    let xmlParser;
+    let interpreter;
+
+    beforeEach(() => {
+        xmlParser = new RoXMLElement();
+        interpreter = new Interpreter();
+    });
+
+    describe("test methods for object with successful parsed xml", () => {
+        beforeEach(() => {
+            let parse = xmlParser.getMethod("parse");
+            parse.call(interpreter, new BrsString(getXmlString()));
+        });
+
+        it("getName", () => {
+            let getName = xmlParser.getMethod("getName");
+            expect(getName.call(interpreter)).toEqual(new BrsString("tag1"));
+        });
+
+        it("getNamedElementsCi", () => {
+            let getNamedElementsCi = xmlParser.getMethod("getNamedElementsCi");
+            expect(getNamedElementsCi.call(interpreter, new BrsString("any")).elements).toEqual([]);
+
+            let children = getNamedElementsCi.call(interpreter, new BrsString("CHiLd1"));
+            expect(children.elements.length).toEqual(2);
+
+            let getName = children.elements[0].getMethod("getName");
+            expect(getName.call(interpreter)).toEqual(new BrsString("Child1"));
+
+            getName = children.elements[1].getMethod("getName");
+            expect(getName.call(interpreter)).toEqual(new BrsString("CHILD1"));
+        });
+
+        it("getAttributes", () => {
+            let getAttributes = xmlParser.getMethod("getAttributes");
+            expect(getAttributes.call(interpreter).elements).not.toEqual(new Map());
+            expect(getAttributes.call(interpreter).elements).toEqual(
+                new Map([
+                    ["id", new BrsString("someId")],
+                    ["attr1", new BrsString("0")],
+                ])
+            );
+        });
+    });
+
+    describe.each([
+        ["test methods for object with no parsed xml", () => {}],
+        [
+            "test methods for object with failed parsing of xml",
+            () => {
+                let parse = xmlParser.getMethod("parse");
+                parse.call(interpreter, new BrsString('>bad_tag id="12" <  some text >/bad_tag<'));
+            },
+        ],
+    ])("%s", (name, tryParse) => {
+        beforeEach(() => {
+            tryParse();
+        });
+
+        it("getName", () => {
+            let getName = xmlParser.getMethod("getName");
+            expect(getName).toBeTruthy();
+            expect(getName.call(interpreter)).toEqual(new BrsString(""));
+        });
+
+        it("getNamedElementsCi", () => {
+            let getNamedElementsCi = xmlParser.getMethod("getNamedElementsCi");
+            expect(getNamedElementsCi).toBeTruthy();
+            expect(getNamedElementsCi.call(interpreter, new BrsString("any")).elements).toEqual([]);
+        });
+
+        it("getAttributes", () => {
+            let getAttributes = xmlParser.getMethod("getAttributes");
+            expect(getAttributes).toBeTruthy();
+            expect(getAttributes.call(interpreter).elements).toEqual(new Map());
+        });
+    });
+
+    describe("test parse method with different xml strings", () => {
+        test.each([
+            ["<tag>some text<tag>", true],
+            ["<tag>some text <child1> child's text </child1> </tag>", true],
+            [getXmlString(), true],
+            ['>bad_tag id="12" <  some text >/bad_tag<', false],
+            ["", false],
+        ])("test parse with string %s", (xmlString, expected) => {
+            let parse = xmlParser.getMethod("parse");
+            expect(parse.call(interpreter, new BrsString(xmlString)).value).toBe(expected);
+        });
+    });
+});
+
+function getXmlString() {
+    return '<tag1 id="someId" attr1="0"> <Child1 id="id1"></Child1> <CHILD1 id="id2"></CHILD1> </tag1>';
+}
diff --git a/test/e2e/BrsComponents.test.js b/test/e2e/BrsComponents.test.js
index 160df83..35d5557 100644
--- a/test/e2e/BrsComponents.test.js
+++ b/test/e2e/BrsComponents.test.js
@@ -188,6 +188,35 @@ describe("end to end brightscript functions", () => {
         ]);
     });
 
+    test("components/roXMLElement.brs", () => {
+        return execute([resourceFile("components", "roXMLElement.brs")], outputStreams).then(() => {
+            expect(allArgs(outputStreams.stdout.write).filter((arg) => arg !== "\n")).toEqual([
+                "xmlParser = ",
+                "<Component: roXMLElement>",
+                "type(xmlParser) = ",
+                "roXMLElement",
+                "parse bad xml string, result = ",
+                "false",
+                "parse good xml string, result = ",
+                "true",
+                "getName() = ",
+                "tag1",
+                "getAttributes() = ",
+                `<Component: roAssociativeArray> =\n` +
+                    `{\n` +
+                    `    id: someId\n` +
+                    `    attr1: 0\n` +
+                    `}`,
+                'getNamedElementsCi("child1") count = ',
+                "2",
+                "name of first child  = ",
+                "Child1",
+                "mame of second child = ",
+                "CHILD1",
+            ]);
+        });
+    });
+
     test("components/customComponent.brs", async () => {
         await execute([resourceFile("components", "customComponent.brs")], outputStreams);
 
@@ -227,6 +256,12 @@ describe("end to end brightscript functions", () => {
             "ExtendedChild init",
             "ExtendedComponent init",
             "ExtendedComponent start",
+            "true", //m.top.isSubtype("ExtendedComponent")
+            "true", //m.top.isSubtype("BaseComponent")
+            "true", //m.top.isSubtype("Node")
+            "false", // m.top.isSubtype("OtherComponent")
+            "BaseComponent", //m.top.parentSubtype("ExtendedComponent")
+            "Node", //m.top.parentSubtype("BaseComponent")
         ]);
     });
 
@@ -259,6 +294,10 @@ describe("end to end brightscript functions", () => {
             "789.012",
             "Integer to string ",
             "23",
+            "LongInteger object type",
+            "roLongInteger",
+            "LongInteger to string ",
+            "2000111222333",
         ]);
     });
 
diff --git a/test/e2e/createExecuteWithScope.test.js b/test/e2e/createExecuteWithScope.test.js
new file mode 100644
index 0000000..28d4872
--- /dev/null
+++ b/test/e2e/createExecuteWithScope.test.js
@@ -0,0 +1,76 @@
+const brs = require("brs");
+const { createExecuteWithScope } = brs;
+const { RoArray, BrsString } = brs.types;
+let { createMockStreams, resourceFile, allArgs } = require("./E2ETests");
+
+resourceFile = resourceFile.bind(null, "execute-with-scope");
+
+describe("createExecuteWithScope", () => {
+    let outputStreams;
+
+    beforeAll(() => {
+        outputStreams = createMockStreams();
+        outputStreams.root = __dirname + "/resources";
+    });
+
+    afterEach(() => {
+        jest.resetAllMocks();
+    });
+
+    afterAll(() => {
+        jest.restoreAllMocks();
+    });
+
+    test("returns a function that executes a file", async () => {
+        let execute = await createExecuteWithScope([resourceFile("in-scope.brs")], outputStreams);
+
+        expect(execute).toBeTruthy();
+
+        let returnValue = execute([resourceFile("main.brs")], [new BrsString("argz4main")]);
+        expect(allArgs(outputStreams.stdout.write).filter((arg) => arg !== "\n")).toEqual([
+            "main:arg:argz4main",
+            "main:commonUtil",
+            "main:onlyInScopeForMain",
+        ]);
+        expect(returnValue).toBeInstanceOf(BrsString);
+        expect(returnValue.value).toEqual("main return value");
+    });
+
+    test("code defined in earlier execution calls is not accessible to subsequent executions", async () => {
+        let execute = await createExecuteWithScope([resourceFile("in-scope.brs")], outputStreams);
+
+        // main defines a function
+        execute([resourceFile("main.brs")], [new BrsString("argz4main")]);
+
+        // main2 tries to call that function, and fails
+        expect(() => execute([resourceFile("main2.brs")], [])).toThrow();
+
+        // the output from both files should be there
+        expect(allArgs(outputStreams.stdout.write).filter((arg) => arg !== "\n")).toEqual([
+            "main:arg:argz4main",
+            "main:commonUtil",
+            "main:onlyInScopeForMain",
+            "main2:commonUtil",
+        ]);
+    });
+
+    test("interpreter errors in earlier executions don't affect subsequent executions", async () => {
+        let execute = await createExecuteWithScope([resourceFile("in-scope.brs")], outputStreams);
+
+        // main2 throws an error
+        expect(() => execute([resourceFile("main2.brs")], [])).toThrow();
+
+        // main should be error-free still
+        expect(() =>
+            execute([resourceFile("main.brs")], [new BrsString("argz4main")])
+        ).not.toThrow();
+
+        // the output from both files should be there
+        expect(allArgs(outputStreams.stdout.write).filter((arg) => arg !== "\n")).toEqual([
+            "main2:commonUtil",
+            "main:arg:argz4main",
+            "main:commonUtil",
+            "main:onlyInScopeForMain",
+        ]);
+    });
+});
diff --git a/test/e2e/resources/components/roIntrinsics.brs b/test/e2e/resources/components/roIntrinsics.brs
index 2a1b6e6..701ba03 100644
--- a/test/e2e/resources/components/roIntrinsics.brs
+++ b/test/e2e/resources/components/roIntrinsics.brs
@@ -4,6 +4,7 @@ sub main()
     doubleObject = createObject("roDouble", 123.456)
     floatObject = createObject("roFloat", 789.012)
     integerObject = createObject("roInt", 23)
+    longIntegerObject = createObject("roLongInteger", 2000111222333)
 
     print "Boolean object A " booleanObjectA.toStr()
     print "Boolean object B " booleanObjectB
@@ -17,5 +18,7 @@ sub main()
     print "Double to string "doubleObject.toStr()
     print "Float to string "floatObject.toStr()
     print "Integer to string "integerObject.toStr()
+    print "LongInteger object type"type(longIntegerObject)
+    print "LongInteger to string "longIntegerObject.toStr()
 
 end sub
diff --git a/test/e2e/resources/components/roXMLElement.brs b/test/e2e/resources/components/roXMLElement.brs
new file mode 100644
index 0000000..92ed9b3
--- /dev/null
+++ b/test/e2e/resources/components/roXMLElement.brs
@@ -0,0 +1,13 @@
+sub main()
+    xmlParser = createObject("roXMLElement")
+    ?"xmlParser = "xmlParser 
+    ?"type(xmlParser) = "type(xmlParser) 
+    ?"parse bad xml string, result = "xmlParser.parse("some_xml_doc")
+    ?"parse good xml string, result = "xmlParser.parse("<tag1 id=""someId"" attr1=""0""> <Child1 id=""id1""></Child1> <CHILD1 id=""id2""></CHILD1> </tag1>")
+    ?"getName() = " xmlParser.getName()
+    ?"getAttributes() = " xmlParser.getAttributes()
+    children = xmlParser.getNamedElementsCi("child1")
+    ?"getNamedElementsCi(""child1"") count = " children.count()
+    ?"name of first child  = "children[0].getName()
+    ?"mame of second child = "children[1].getName()
+end sub
\ No newline at end of file
diff --git a/test/e2e/resources/components/scripts/ExtendedComponent.brs b/test/e2e/resources/components/scripts/ExtendedComponent.brs
index 908af81..6c2ad15 100644
--- a/test/e2e/resources/components/scripts/ExtendedComponent.brs
+++ b/test/e2e/resources/components/scripts/ExtendedComponent.brs
@@ -1,4 +1,11 @@
 sub init()
     print "ExtendedComponent init"
     start()
+
+    print m.top.isSubtype("ExtendedComponent")
+    print m.top.isSubtype("BaseComponent")
+    print m.top.isSubtype("Node")
+    print m.top.isSubtype("OtherComponent")
+    print m.top.parentSubtype("ExtendedComponent")
+    print m.top.parentSubtype("BaseComponent")
 end sub
diff --git a/test/e2e/resources/execute-with-scope/in-scope.brs b/test/e2e/resources/execute-with-scope/in-scope.brs
new file mode 100644
index 0000000..acfbc93
--- /dev/null
+++ b/test/e2e/resources/execute-with-scope/in-scope.brs
@@ -0,0 +1,3 @@
+function commonUtil()
+    return "commonUtil"
+end function
diff --git a/test/e2e/resources/execute-with-scope/main.brs b/test/e2e/resources/execute-with-scope/main.brs
new file mode 100644
index 0000000..d0ee204
--- /dev/null
+++ b/test/e2e/resources/execute-with-scope/main.brs
@@ -0,0 +1,11 @@
+function main(arg)
+    print "main:arg:" + arg
+    print "main:" + commonUtil()
+    print "main:" + onlyInScopeForMain()
+
+    return "main return value"
+end function
+
+function onlyInScopeForMain()
+    return "onlyInScopeForMain"
+end function
diff --git a/test/e2e/resources/execute-with-scope/main2.brs b/test/e2e/resources/execute-with-scope/main2.brs
new file mode 100644
index 0000000..9013b92
--- /dev/null
+++ b/test/e2e/resources/execute-with-scope/main2.brs
@@ -0,0 +1,4 @@
+sub main()
+    print "main2:" + commonUtil()
+    print "main2:" + onlyInScopeForMain()
+end sub
diff --git a/test/interpreter/Variables.test.js b/test/interpreter/Variables.test.js
index 22d096f..a8a2198 100644
--- a/test/interpreter/Variables.test.js
+++ b/test/interpreter/Variables.test.js
@@ -59,7 +59,9 @@ describe("interpreter variables", () => {
             new Stmt.Assignment(tokens, identifier("int32%"), new Expr.Literal(new Int32(1))),
             new Stmt.Assignment(tokens, identifier("float!"), new Expr.Literal(new Float(2))),
             new Stmt.Assignment(tokens, identifier("double#"), new Expr.Literal(new Double(3))),
+            new Stmt.Assignment(tokens, identifier("double#"), new Expr.Literal(new Float(3))),
             new Stmt.Assignment(tokens, identifier("int64&"), new Expr.Literal(new Int64(4))),
+            new Stmt.Assignment(tokens, identifier("int64&"), new Expr.Literal(new Int32(4))),
         ];
 
         expect(() => interpreter.exec(assign)).not.toThrow();
@@ -100,11 +102,11 @@ describe("interpreter variables", () => {
             },
             {
                 lhs: "double#",
-                values: [str, int32, float, int64],
+                values: [str, int32, int64],
             },
             {
                 lhs: "int64&",
-                values: [str, int32, float, double],
+                values: [str, float, double],
             },
         ].forEach(({ lhs, values }) => {
             test(lhs, () => {