Skip to content

Commit 94304cd

Browse files
committed
Fixed val() edge cases: hex without radix and NaN
1 parent f1546e3 commit 94304cd

File tree

5 files changed

+66
-26
lines changed

5 files changed

+66
-26
lines changed

README.md

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
- [Build](#build)
1717
- [Testing](#testing)
1818
- [Cleaning](#cleaning)
19-
- [All Together](#all-together)
2019
- [Documentation](#documentation)
2120

2221
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
2322

2423
# BRS: Off-Roku BrightScript
24+
2525
An interpreter for the BrightScript language that runs on non-Roku platforms.
2626

2727
[![build status](https://img.shields.io/github/actions/workflow/status/rokucommunity/brs/build.yml?branch=master&logo=github)](https://github.com/rokucommunity/brs/actions?query=branch%3Amaster+workflow%3Abuild)
@@ -31,32 +31,35 @@ An interpreter for the BrightScript language that runs on non-Roku platforms.
3131
[![license](https://img.shields.io/github/license/rokucommunity/brs.svg)](LICENSE)
3232
[![Slack](https://img.shields.io/badge/Slack-RokuCommunity-4A154B?logo=slack)](https://join.slack.com/t/rokudevelopers/shared_invite/zt-4vw7rg6v-NH46oY7hTktpRIBM_zGvwA)
3333

34-
3534
## Installation
35+
3636
The BRS project is published as a `node` package, so use `npm`:
3737

3838
```shell
39-
$ npm install -g brs
39+
$ npm install -g @rokucommunity/brs
4040
```
4141

4242
## Usage
43+
4344
This repo provides the `brs` executable, which operates in two ways.
4445

4546
### REPL
47+
4648
An interactive BrightScript REPL (Read-Execute-Print Loop) is available by running `brs` with no arguments, e.g.:
4749

48-
```
50+
```shell
4951
$ brs
5052
brs> ?"Dennis Ritchie said ""Hello, World!"""
5153
Dennis Ritchie said "Hello, World!"
5254
```
5355

54-
Quit by entering `^D` (Control-D).
56+
Quit by pressing `^D` (Control-D) or executing `exit`.
5557

5658
### Executing a file
59+
5760
BRS can execute an arbitrary BrightScript file as well! Simply pass the file to the `brs` executable, e.g.:
5861

59-
```
62+
```shell
6063
$ cat hello-world.brs
6164
?"Dennis Ritchie said ""Hello, World!"""
6265

@@ -65,30 +68,45 @@ Dennis Ritchie said "Hello, World!"
6568
```
6669

6770
## Sure, but why?
71+
6872
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.
6973

7074
## So can I use this to watch TV without a Roku?
75+
7176
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.
7277

7378
## Building from source
79+
7480
The BRS project follows pretty standard `node` development patterns, with the caveat that it uses `yarn` for dependency management.
7581

7682
### Prerequisites
83+
7784
BRS builds (and runs) in `node`, so you'll need to [install that first](https://nodejs.org).
7885

7986
### Setup
87+
8088
1. Clone this repo:
81-
```
89+
90+
```shell
8291
$ git clone https://github.com/rokucommunity/brs.git
8392
```
8493

8594
2. Install dependencies:
95+
8696
```shell
8797
$ npm install
8898
```
8999

100+
3. Get `brs` onto your `PATH`:
101+
102+
```shell
103+
$ npm link
104+
```
105+
90106
### The build-test-clean dance
107+
91108
#### Build
109+
92110
This project is written in TypeScript, so it needs to be compiled before it can be executed. `npm run build` compiles files in `src/` into JavaScript and TypeScript declarations, and puts them in `lib/` and `types/` respectively.
93111

94112
```shell
@@ -102,12 +120,15 @@ index.d.ts (and friends)
102120
```
103121

104122
Alternatively, you can run the build step in "watch" mode. This will run `npm run build` for you automatically, every time it detects source file changes:
123+
105124
```shell
106125
$ npm run watch
107126
```
127+
108128
This is often useful for testing that local changes work in your BrightScript project, without having to run `npm run build` over and over.
109129

110130
#### Testing
131+
111132
Tests are written in plain-old JavaScript with [Facebook's Jest](http://facebook.github.io/jest/), and can be run with the `test` target:
112133
113134
```shell
@@ -119,10 +140,11 @@ $ npm run test
119140
Note that only test files ending in `.test.js` will be executed by `yarn test`.
120141
121142
#### Cleaning
143+
122144
Compiled output in `lib/` and `types/` can be removed with the `clean` target:
123145
124146
```shell
125-
$ yarn clean
147+
$ npm run clean
126148
127149
$ ls lib/
128150
ls: cannot access 'lib': No such file or directory
@@ -131,13 +153,6 @@ $ ls types/
131153
ls: cannot access 'types': No such file or directory
132154
```
133155
134-
#### All Together
135-
Thanks to the [npm-run-all](https://www.npmjs.com/package/npm-run-all) package, it's trivially easy to combine these into a sequence of tasks without relying on shell semantics:
136-
137-
```shell
138-
$ yarn run-s clean build test
139-
```
140-
141156
## Documentation
142157
143-
For the most part, `brs` attempts to emulate BrightScript as closely as possible. However, there are certain implementation gaps. Also, in the spirit of unit testing, there are a few extensions that will help with testing. All of our documentation for APIs, extensions, gaps, and more is hosted on our docs site, [hulu.github.io/roca](https://hulu.github.io/roca).
158+
For the most part, `brs` attempts to emulate BrightScript as closely as possible. However, as a work in progress, there are certain implementation gaps, please refer to the [BrightScript language reference](https://developer.roku.com/docs/references/brightscript/language/brightscript-language-reference.md) and report an issue for any gaps found. Also, in the spirit of unit testing, there are a few extensions that will help with testing. All of our documentation for APIs, extensions, gaps, and more is hosted on our docs site, [hulu.github.io/roca](https://hulu.github.io/roca).

src/stdlib/String.ts

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { BrsType, Callable, ValueKind, BrsString, Int32, Float, StdlibArgument } from "../brsTypes";
1+
import { BrsType, Callable, ValueKind, BrsString, Int32, Float, StdlibArgument, BrsInvalid } from "../brsTypes";
22
import * as Expr from "../parser/Expression";
33
import { Interpreter } from "../interpreter";
44
import { BrsNumber } from "../brsTypes/BrsNumber";
@@ -251,20 +251,25 @@ export const Val = new Callable("Val", {
251251
signature: {
252252
args: [
253253
new StdlibArgument("s", ValueKind.String),
254-
new StdlibArgument("radix", ValueKind.Int32, new Int32(10)),
254+
new StdlibArgument("radix", ValueKind.Int32, BrsInvalid.Instance),
255255
],
256256
returns: ValueKind.Dynamic,
257257
},
258-
impl: (interpreter: Interpreter, s: BrsString, brsRadix: Int32): BrsNumber => {
259-
function isBrsStrFloat(str: BrsString): boolean {
260-
return str.value.includes(".");
261-
}
258+
impl: (interpreter: Interpreter, s: BrsString, brsRadix: Int32 | BrsInvalid): BrsNumber => {
259+
const isFloat = s.value.includes(".");
262260

263-
if (isBrsStrFloat(s)) {
264-
return new Float(Number(s.value));
261+
let retNumber = 0;
262+
if (isFloat || brsRadix instanceof BrsInvalid) {
263+
retNumber = Number(s.value);
265264
} else {
266-
return new Int32(parseInt(s.value, brsRadix.getValue()));
265+
retNumber = parseInt(s.value, brsRadix.getValue());
266+
}
267+
268+
if (Number.isNaN(retNumber)) {
269+
return new Int32(0);
267270
}
271+
272+
return isFloat ? new Float(retNumber) : new Int32(retNumber);
268273
},
269274
});
270275

test/e2e/StdLib.test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ describe("end to end standard libary", () => {
5353
" 9.7",
5454
"-3",
5555
"12.34",
56+
"0",
57+
"255",
58+
"170",
5659
"Mary and Bob",
5760
"252",
5861
"abababab",

test/e2e/resources/stdlib/strings.brs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ print Str(3.4) ' " 3.4"
1616
print Str(9.7#) ' " 9.7"
1717
print StrI(-3) ' "-3"
1818
print Val("12.34") ' 12.34
19+
print Val("") ' 0
20+
print Val("0xFF") ' 255
21+
print Val("0xAA") ' 170
1922
print Substitute("{0} and {1}", "Mary", "Bob")
2023
print StrToI("252")
2124
print String(4, "ab") ' abababab

test/stdlib/String.test.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,21 @@ describe("global string functions", () => {
302302
expect(Val.call(interpreter, new BrsString("0.0"))).toEqual(new Float(0.0));
303303
});
304304

305-
it("returns an integer from a string an radix", () => {
305+
it("returns zero if the string is not a number", () => {
306+
expect(Val.call(interpreter, new BrsString(""))).toEqual(new Int32(0));
307+
308+
expect(Val.call(interpreter, new BrsString("Not a Number"))).toEqual(new Int32(0));
309+
310+
expect(Val.call(interpreter, new BrsString("10+2"))).toEqual(new Int32(0));
311+
});
312+
313+
it("returns an integer from a string", () => {
314+
expect(Val.call(interpreter, new BrsString("65535"))).toEqual(new Int32(65535));
315+
316+
expect(Val.call(interpreter, new BrsString("0xFA"))).toEqual(new Int32(250));
317+
});
318+
319+
it("returns an integer from a string and radix", () => {
306320
expect(Val.call(interpreter, new BrsString("7"), new Int32(10))).toEqual(new Int32(7));
307321

308322
expect(Val.call(interpreter, new BrsString("0x80"), new Int32(0))).toEqual(

0 commit comments

Comments
 (0)