Skip to content

Commit

Permalink
Implemented Box() function and improved boxing (#54)
Browse files Browse the repository at this point in the history
* Implemented `Box()` function and improved boxing on Numbers and Boolean

* Fixed lint issue

* Fixed Invalid check when on the left side does not work (boxing issue) #7

* Moved `debugLocalVariables()` to interpreter (to be used by MicroDebugger in the future)

* Fixed `-n, --no-color` CLI option

* Documented `debugLocalVariables()`
  • Loading branch information
lvcabral authored Apr 3, 2024
1 parent d78ff38 commit 5ea0f3c
Show file tree
Hide file tree
Showing 19 changed files with 191 additions and 87 deletions.
2 changes: 1 addition & 1 deletion bin/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ program
)
.option("-n, --no-color", "Disable colorized output", false)
.action(async (brsFiles, program) => {
chalk.level = program.noColor ? 0 : chalk.level;
chalk.level = program.color ? chalk.level : 0;
if (brsFiles.length > 0) {
try {
await brs.execute(brsFiles, {
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
],
"dependencies": {
"chalk": "^4.1.2",
"commander": "^2.12.2",
"commander": "^2.20.3",
"crc": "^3.8.0",
"dayjs": "^1.11.10",
"decompress": "^4.2.1",
Expand Down
8 changes: 3 additions & 5 deletions src/brsTypes/BrsType.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BrsNumber, BrsType, isStringComp } from ".";
import { BrsNumber, BrsType, isBrsNumber, isStringComp } from ".";
import { Boxable } from "./Boxing";
import { RoString } from "./components/RoString";
import { Int32 } from "./Int32";
Expand Down Expand Up @@ -298,19 +298,17 @@ export class BrsBoolean implements BrsValue, Comparable, Boxable {

lessThan(other: BrsType): BrsBoolean {
// booleans aren't less than anything
// TODO: Validate on a Roku
return BrsBoolean.False;
}

greaterThan(other: BrsType): BrsBoolean {
// but isn't greater than anything either
// TODO: Validate on a Roku
return BrsBoolean.False;
}

equalTo(other: BrsType): BrsBoolean {
if (other.kind === ValueKind.Boolean) {
return BrsBoolean.from(this === other);
if (other.kind === ValueKind.Boolean || isBrsNumber(other)) {
return BrsBoolean.from(this.toBoolean() === other.toBoolean());
}
return BrsBoolean.False;
}
Expand Down
6 changes: 3 additions & 3 deletions src/brsTypes/Int32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export class Int32 implements Numeric, Comparable, Boxable {
add(rhs: BrsNumber): BrsNumber {
switch (rhs.kind) {
case ValueKind.Int32:
return new Int32(this.getValue() + rhs.getValue());
return new Int32((this.getValue() + rhs.getValue()) | 0);
case ValueKind.Int64:
return new Int64(rhs.getValue().add(this.getValue()));
case ValueKind.Float:
Expand All @@ -66,7 +66,7 @@ export class Int32 implements Numeric, Comparable, Boxable {
subtract(rhs: BrsNumber): BrsNumber {
switch (rhs.kind) {
case ValueKind.Int32:
return new Int32(this.getValue() - rhs.getValue());
return new Int32((this.getValue() - rhs.getValue()) | 0);
case ValueKind.Int64:
return new Int64(this.getValue()).subtract(rhs);
case ValueKind.Float:
Expand All @@ -79,7 +79,7 @@ export class Int32 implements Numeric, Comparable, Boxable {
multiply(rhs: BrsNumber): BrsNumber {
switch (rhs.kind) {
case ValueKind.Int32:
return new Int32(this.getValue() * rhs.getValue());
return new Int32((this.getValue() * rhs.getValue()) | 0);
case ValueKind.Int64:
return new Int64(rhs.getValue().multiply(this.getValue()));
case ValueKind.Float:
Expand Down
10 changes: 6 additions & 4 deletions src/brsTypes/components/RoBoolean.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { BrsComponent } from "./BrsComponent";
import { BrsValue, ValueKind, BrsString, BrsBoolean, BrsInvalid } from "../BrsType";
import { Callable, StdlibArgument } from "../Callable";
import { Interpreter } from "../../interpreter";
import { BrsType } from "..";
import { BrsType, isBrsNumber } from "..";
import { Unboxable } from "../Boxing";

export class roBoolean extends BrsComponent implements BrsValue, Unboxable {
readonly kind = ValueKind.Object;
private intrinsic: BrsBoolean;

public getValue(): BrsBoolean {
return this.intrinsic;
public getValue(): boolean {
return this.intrinsic.toBoolean();
}

constructor(initialValue: BrsBoolean) {
Expand All @@ -29,7 +29,9 @@ export class roBoolean extends BrsComponent implements BrsValue, Unboxable {

equalTo(other: BrsType): BrsBoolean {
if (other instanceof roBoolean) {
return BrsBoolean.from(other.getValue().toBoolean() === this.intrinsic.toBoolean());
return BrsBoolean.from(other.getValue() === this.getValue());
} else if (isBrsNumber(other) || other instanceof BrsBoolean) {
return BrsBoolean.from(other.toBoolean() === this.intrinsic.toBoolean());
}

return BrsBoolean.False;
Expand Down
8 changes: 4 additions & 4 deletions src/brsTypes/components/RoDouble.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ 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 { BrsType, isBrsNumber } from "..";
import { Unboxable } from "../Boxing";
import { Double } from "../Double";

export class roDouble extends BrsComponent implements BrsValue, Unboxable {
readonly kind = ValueKind.Object;
private intrinsic: Double;

public getValue(): Double {
return this.intrinsic;
public getValue(): number {
return this.intrinsic.getValue();
}

constructor(initialValue: Double) {
super("roDouble");

this.intrinsic = initialValue;
this.intrinsic = new Double(isBrsNumber(initialValue) ? initialValue.getValue() : 0);
this.registerMethods({
ifDouble: [this.getDouble, this.setDouble],
ifToStr: [this.toStr],
Expand Down
8 changes: 4 additions & 4 deletions src/brsTypes/components/RoFloat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ 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 { BrsType, isBrsNumber } from "..";
import { Unboxable } from "../Boxing";
import { Float } from "../Float";

export class roFloat extends BrsComponent implements BrsValue, Unboxable {
readonly kind = ValueKind.Object;
private intrinsic: Float;

public getValue(): Float {
return this.intrinsic;
public getValue(): number {
return this.intrinsic.getValue();
}

constructor(initialValue: Float) {
super("roFloat");

this.intrinsic = initialValue;
this.intrinsic = new Float(isBrsNumber(initialValue) ? initialValue.getValue() : 0);
this.registerMethods({
ifFloat: [this.getFloat, this.setFloat],
ifToStr: [this.toStr],
Expand Down
9 changes: 4 additions & 5 deletions src/brsTypes/components/RoInt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,21 @@ import { BrsComponent } from "./BrsComponent";
import { BrsValue, ValueKind, BrsString, BrsBoolean, BrsInvalid } from "../BrsType";
import { Callable, StdlibArgument } from "../Callable";
import { Interpreter } from "../../interpreter";
import { BrsType } from "..";
import { BrsType, isBrsNumber } from "..";
import { Unboxable } from "../Boxing";
import { Int32 } from "../Int32";

export class roInt extends BrsComponent implements BrsValue, Unboxable {
readonly kind = ValueKind.Object;
private intrinsic: Int32;

public getValue(): Int32 {
return this.intrinsic;
public getValue(): number {
return this.intrinsic.getValue();
}

constructor(initialValue: Int32) {
super("roInt");

this.intrinsic = initialValue;
this.intrinsic = new Int32(isBrsNumber(initialValue) ? initialValue.getValue() : 0);
this.registerMethods({
ifInt: [this.getInt, this.setInt],
// Per https://developer.roku.com/docs/references/brightscript/interfaces/ifintops.md,
Expand Down
8 changes: 4 additions & 4 deletions src/brsTypes/components/RoLongInteger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@ 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 { BrsType, isBrsNumber } 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;
public getValue(): Long {
return this.intrinsic.getValue();
}

constructor(initialValue: Int64) {
super("roLongInteger");

this.intrinsic = initialValue;
this.intrinsic = new Int64(isBrsNumber(initialValue) ? initialValue.getValue() : 0);
this.registerMethods({
ifLongInt: [this.getLongInt, this.setLongInt],
ifToStr: [this.toStr],
Expand Down
20 changes: 20 additions & 0 deletions src/brsTypes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ import { BrsComponent } from "./components/BrsComponent";
import { RoString } from "./components/RoString";
import { BrsInterface } from "./BrsInterface";
import { RoPath } from "./components/RoPath";
import { roDouble } from "./components/RoDouble";
import { roFloat } from "./components/RoFloat";
import { roInt } from "./components/RoInt";
import { roLongInteger } from "./components/RoLongInteger";

export * from "./BrsType";
export * from "./Int32";
Expand Down Expand Up @@ -139,9 +143,25 @@ export function isStringComp(value: BrsType): value is BrsString & Comparable {
return isBrsString(value) || value instanceof RoPath;
}

/** Determines whether or not the given value is a BrightScript boxed number.
* @param value the BrightScript value in question.
* @returns `true` if `value` is a boxed number, otherwise `false`.
*/
export function isBoxedNumber(value: BrsType): value is BoxedNumber {
return (
value instanceof roInt ||
value instanceof roFloat ||
value instanceof roDouble ||
value instanceof roLongInteger
);
}

/** The set of BrightScript numeric types. */
export type BrsNumber = Int32 | Int64 | Float | Double;

/** The set of BrightScript boxed numeric types. */
export type BoxedNumber = roInt | roFloat | roDouble | roLongInteger;

/**
* The set of all comparable BrightScript types. Only primitive (i.e. intrinsic * and unboxed)
* BrightScript types are comparable to each other.
Expand Down
33 changes: 2 additions & 31 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
} from "./componentprocessor";
import { Parser } from "./parser";
import { Interpreter, ExecutionOptions, defaultExecutionOptions, colorize } from "./interpreter";
import { Environment, Scope } from "./interpreter/Environment";
import { resetTestData } from "./extensions";
import * as BrsError from "./Error";
import * as LexerParser from "./LexerParser";
Expand All @@ -27,7 +26,6 @@ import * as _lexer from "./lexer";
export { _lexer as lexer };
import * as BrsTypes from "./brsTypes";
export { BrsTypes as types };
import { PrimitiveKinds, ValueKind, isIterable } from "./brsTypes";
export { PP as preprocessor };
import * as _parser from "./parser";
export { _parser as parser };
Expand Down Expand Up @@ -292,7 +290,8 @@ export function repl() {
rl.prompt();
return;
} else if (["vars", "var"].includes(cmd)) {
printLocalVariables(replInterpreter.environment);
console.log(chalk.cyanBright(`\r\nLocal variables:\r\n`));
console.log(chalk.cyanBright(replInterpreter.debugLocalVariables()));
rl.prompt();
return;
}
Expand Down Expand Up @@ -370,31 +369,3 @@ function printHelp() {
helpMsg += " Type any valid BrightScript expression for a live compile and run.\r\n";
console.log(chalk.cyanBright(helpMsg));
}

/**
* Display the local variables on the console.
* @param environment an object with the Interpreter Environment data
*/
function printLocalVariables(environment: Environment) {
let debugMsg = "\r\nLocal variables:\r\n";
debugMsg += `${"m".padEnd(16)} roAssociativeArray count:${
environment.getM().getElements().length
}\r\n`;
let fnc = environment.getList(Scope.Function);
fnc.forEach((value, key) => {
if (PrimitiveKinds.has(value.kind)) {
debugMsg += `${key.padEnd(16)} ${ValueKind.toString(
value.kind
)} val:${value.toString()}\r\n`;
} else if (isIterable(value)) {
debugMsg += `${key.padEnd(16)} ${value.getComponentName()} count:${
value.getElements().length
}\r\n`;
} else if (value.kind === ValueKind.Object) {
debugMsg += `${key.padEnd(17)}${value.getComponentName()}\r\n`;
} else {
debugMsg += `${key.padEnd(17)}${value.toString()}\r\n`;
}
});
console.log(chalk.cyanBright(debugMsg));
}
Loading

0 comments on commit 5ea0f3c

Please sign in to comment.