Skip to content

Commit

Permalink
Created ifToStr() and refactored components to use it and improve `…
Browse files Browse the repository at this point in the history
…sprintf` formatting to match Roku (#443)
  • Loading branch information
lvcabral authored Jan 9, 2025
1 parent 4fba752 commit 9aee9fd
Show file tree
Hide file tree
Showing 20 changed files with 252 additions and 222 deletions.
2 changes: 1 addition & 1 deletion src/core/brsTypes/Double.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ export class Double implements Numeric, Comparable, Boxable {
}

toString(parent?: BrsType): string {
return this.value.toString();
return this.value.toPrecision();
}

box() {
Expand Down
2 changes: 1 addition & 1 deletion src/core/brsTypes/Float.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ export class Float implements Numeric, Comparable, Boxable {
}

toString(parent?: BrsType): string {
return this.value.toString();
return this.value.toPrecision();
}

box() {
Expand Down
2 changes: 1 addition & 1 deletion src/core/brsTypes/components/BrsComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { bscs } from "../..";
import { BrsType } from "..";
import { BrsBoolean, BrsInvalid } from "../BrsType";
import { Callable } from "../Callable";
import { BrsInterface } from "../BrsInterface";
import { BrsInterface } from "../interfaces/BrsInterface";

export class BrsComponent {
private methods: Map<string, Callable> = new Map();
Expand Down
21 changes: 5 additions & 16 deletions src/core/brsTypes/components/RoBoolean.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { BrsComponent } from "./BrsComponent";
import { BrsValue, ValueKind, BrsString, BrsBoolean, BrsInvalid } from "../BrsType";
import { BrsValue, ValueKind, BrsBoolean, BrsInvalid } from "../BrsType";
import { Callable, StdlibArgument } from "../Callable";
import { Interpreter } from "../../interpreter";
import { BrsType, isBrsNumber } from "..";
import { Unboxable } from "../Boxing";
import { ifToStr } from "../interfaces/ifToStr";

export class RoBoolean extends BrsComponent implements BrsValue, Unboxable {
readonly kind = ValueKind.Object;
Expand All @@ -21,7 +22,7 @@ export class RoBoolean extends BrsComponent implements BrsValue, Unboxable {
}
this.registerMethods({
ifBoolean: [this.getBoolean, this.setBoolean],
ifToStr: [this.toStr],
ifToStr: [new ifToStr(this).toStr],
});
}

Expand Down Expand Up @@ -50,7 +51,7 @@ export class RoBoolean extends BrsComponent implements BrsValue, Unboxable {
args: [],
returns: ValueKind.Boolean,
},
impl: (interpreter: Interpreter) => {
impl: (_: Interpreter) => {
return this.intrinsic;
},
});
Expand All @@ -60,21 +61,9 @@ export class RoBoolean extends BrsComponent implements BrsValue, Unboxable {
args: [new StdlibArgument("value", ValueKind.Boolean)],
returns: ValueKind.Void,
},
impl: (_interpreter, value: BrsBoolean) => {
impl: (_, value: BrsBoolean) => {
this.intrinsic = value;
return BrsInvalid.Instance;
},
});

// -------------- ifToStr --------------

private readonly toStr = new Callable("toStr", {
signature: {
args: [],
returns: ValueKind.String,
},
impl: (interpreter: Interpreter) => {
return new BrsString(this.intrinsic.toString());
},
});
}
30 changes: 3 additions & 27 deletions src/core/brsTypes/components/RoDouble.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { BrsComponent } from "./BrsComponent";
import { BrsValue, ValueKind, BrsString, BrsBoolean, BrsInvalid } from "../BrsType";
import { BrsValue, ValueKind, BrsBoolean, BrsInvalid } from "../BrsType";
import { Callable, StdlibArgument } from "../Callable";
import { BrsType, isBrsNumber } from "..";
import { Unboxable } from "../Boxing";
import { Double } from "../Double";
import { vsprintf } from "sprintf-js";
import { ifToStr } from "../interfaces/ifToStr";

export class RoDouble extends BrsComponent implements BrsValue, Unboxable {
readonly kind = ValueKind.Object;
Expand All @@ -20,7 +20,7 @@ export class RoDouble extends BrsComponent implements BrsValue, Unboxable {
this.intrinsic = new Double(isBrsNumber(initialValue) ? initialValue.getValue() : 0);
this.registerMethods({
ifDouble: [this.getDouble, this.setDouble],
ifToStr: [this.toStr],
ifToStr: [new ifToStr(this, "%g").toStr],
});
}

Expand Down Expand Up @@ -62,28 +62,4 @@ export class RoDouble extends BrsComponent implements BrsValue, Unboxable {
return BrsInvalid.Instance;
},
});

// -------------- ifToStr --------------

private readonly toStr = new Callable("toStr", {
signature: {
args: [new StdlibArgument("format", ValueKind.String, BrsInvalid.Instance)],
returns: ValueKind.String,
},
impl: (_interpreter, format: BrsString) => {
if (format instanceof BrsString) {
const tokens = format.value.split("%").length - 1;
if (tokens === 0) {
return new BrsString(format.value);
}
const params = Array(tokens).fill(this.intrinsic.getValue());
try {
return new BrsString(vsprintf(format.value, params));
} catch (error: any) {
throw new Error("Invalid Format Specifier (runtime error &h24)");
}
}
return new BrsString(this.intrinsic.toString());
},
});
}
30 changes: 3 additions & 27 deletions src/core/brsTypes/components/RoFloat.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { BrsComponent } from "./BrsComponent";
import { BrsValue, ValueKind, BrsString, BrsBoolean, BrsInvalid } from "../BrsType";
import { BrsValue, ValueKind, BrsBoolean, BrsInvalid } from "../BrsType";
import { Callable, StdlibArgument } from "../Callable";
import { BrsType, isBrsNumber } from "..";
import { Unboxable } from "../Boxing";
import { Float } from "../Float";
import { vsprintf } from "sprintf-js";
import { ifToStr } from "../interfaces/ifToStr";

export class RoFloat extends BrsComponent implements BrsValue, Unboxable {
readonly kind = ValueKind.Object;
Expand All @@ -20,7 +20,7 @@ export class RoFloat extends BrsComponent implements BrsValue, Unboxable {
this.intrinsic = new Float(isBrsNumber(initialValue) ? initialValue.getValue() : 0);
this.registerMethods({
ifFloat: [this.getFloat, this.setFloat],
ifToStr: [this.toStr],
ifToStr: [new ifToStr(this, "%g").toStr],
});
}

Expand Down Expand Up @@ -62,28 +62,4 @@ export class RoFloat extends BrsComponent implements BrsValue, Unboxable {
return BrsInvalid.Instance;
},
});

// -------------- ifToStr --------------

private readonly toStr = new Callable("toStr", {
signature: {
args: [new StdlibArgument("format", ValueKind.String, BrsInvalid.Instance)],
returns: ValueKind.String,
},
impl: (_interpreter, format: BrsString) => {
if (format instanceof BrsString) {
const tokens = format.value.split("%").length - 1;
if (tokens === 0) {
return new BrsString(format.value);
}
const params = Array(tokens).fill(this.intrinsic.getValue());
try {
return new BrsString(vsprintf(format.value, params));
} catch (error: any) {
throw new Error("Invalid Format Specifier (runtime error &h24)");
}
}
return new BrsString(this.intrinsic.toString());
},
});
}
4 changes: 3 additions & 1 deletion src/core/brsTypes/components/RoFunction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Callable, StdlibArgument } from "../Callable";
import { Interpreter } from "../../interpreter";
import { BrsType } from "..";
import { Unboxable } from "../Boxing";
import { ifToStr } from "../interfaces/ifToStr";

export class RoFunction extends BrsComponent implements BrsValue, Unboxable {
readonly kind = ValueKind.Object;
Expand All @@ -19,6 +20,7 @@ export class RoFunction extends BrsComponent implements BrsValue, Unboxable {
this.intrinsic = sub;
this.registerMethods({
ifFunction: [this.getSub, this.setSub],
ifToStr: [new ifToStr(this).toStr],
});
}

Expand All @@ -31,7 +33,7 @@ export class RoFunction extends BrsComponent implements BrsValue, Unboxable {
}

toString(_parent?: BrsType): string {
return this.intrinsic.toString();
return this.intrinsic.toString().replace(/[<>]/g, "");
}

private readonly getSub = new Callable("getSub", {
Expand Down
38 changes: 5 additions & 33 deletions src/core/brsTypes/components/RoInt.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { BrsComponent } from "./BrsComponent";
import { BrsValue, ValueKind, BrsString, BrsBoolean, BrsInvalid } from "../BrsType";
import { BrsValue, ValueKind, BrsBoolean, BrsInvalid } from "../BrsType";
import { Callable, StdlibArgument } from "../Callable";
import { BrsType, isBrsNumber } from "..";
import { Unboxable } from "../Boxing";
import { Int32 } from "../Int32";
import { vsprintf } from "sprintf-js";
import { RuntimeError, RuntimeErrorDetail } from "../../Error";
import { Interpreter } from "../../interpreter";
import { ifToStr } from "../interfaces/ifToStr";
export class RoInt extends BrsComponent implements BrsValue, Unboxable {
readonly kind = ValueKind.Object;
private intrinsic: Int32;
Expand All @@ -19,12 +17,13 @@ export class RoInt extends BrsComponent implements BrsValue, Unboxable {
super("roInt");

this.intrinsic = new Int32(isBrsNumber(initialValue) ? initialValue.getValue() : 0);
const toStr = new ifToStr(this).toStr;
this.registerMethods({
ifInt: [this.getInt, this.setInt],
// Per https://developer.roku.com/docs/references/brightscript/interfaces/ifintops.md,
// ifIntOps _also_ implements toStr()
ifIntOps: [this.toStr],
ifToStr: [this.toStr],
ifIntOps: [toStr],
ifToStr: [toStr],
});
}

Expand Down Expand Up @@ -66,31 +65,4 @@ export class RoInt extends BrsComponent implements BrsValue, Unboxable {
return BrsInvalid.Instance;
},
});

// ---------- ifIntOps, ifToStr ----------

private readonly toStr = new Callable("toStr", {
signature: {
args: [new StdlibArgument("format", ValueKind.String, BrsInvalid.Instance)],
returns: ValueKind.String,
},
impl: (interpreter: Interpreter, format: BrsString) => {
if (format instanceof BrsString) {
const tokens = format.value.split("%").length - 1;
if (tokens === 0) {
return new BrsString(format.value);
}
const params = Array(tokens).fill(this.intrinsic.getValue());
try {
return new BrsString(vsprintf(format.value, params));
} catch (error: any) {
throw new RuntimeError(
RuntimeErrorDetail.InvalidFormatSpecifier,
interpreter.location
);
}
}
return new BrsString(this.intrinsic.toString());
},
});
}
35 changes: 3 additions & 32 deletions src/core/brsTypes/components/RoLongInteger.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { BrsComponent } from "./BrsComponent";
import { BrsValue, ValueKind, BrsString, BrsBoolean, BrsInvalid } from "../BrsType";
import { BrsValue, ValueKind, BrsBoolean, BrsInvalid } from "../BrsType";
import { Callable, StdlibArgument } from "../Callable";
import { BrsType, isBrsNumber } from "..";
import { Unboxable } from "../Boxing";
import { Int64 } from "../Int64";
import { vsprintf } from "sprintf-js";
import { RuntimeError, RuntimeErrorDetail } from "../../Error";
import { Interpreter } from "../../interpreter";
import { ifToStr } from "../interfaces/ifToStr";

export class RoLongInteger extends BrsComponent implements BrsValue, Unboxable {
readonly kind = ValueKind.Object;
Expand All @@ -22,7 +20,7 @@ export class RoLongInteger extends BrsComponent implements BrsValue, Unboxable {
this.intrinsic = new Int64(isBrsNumber(initialValue) ? initialValue.getValue() : 0);
this.registerMethods({
ifLongInt: [this.getLongInt, this.setLongInt],
ifToStr: [this.toStr],
ifToStr: [new ifToStr(this).toStr],
});
}

Expand Down Expand Up @@ -66,31 +64,4 @@ export class RoLongInteger extends BrsComponent implements BrsValue, Unboxable {
return BrsInvalid.Instance;
},
});

// ---------- ifToStr ----------

private readonly toStr = new Callable("toStr", {
signature: {
args: [new StdlibArgument("format", ValueKind.String, BrsInvalid.Instance)],
returns: ValueKind.String,
},
impl: (interpreter: Interpreter, format: BrsString) => {
if (format instanceof BrsString) {
const tokens = format.value.split("%").length - 1;
if (tokens === 0) {
return new BrsString(format.value);
}
const params = Array(tokens).fill(this.intrinsic.getValue());
try {
return new BrsString(vsprintf(format.value, params));
} catch (error: any) {
throw new RuntimeError(
RuntimeErrorDetail.InvalidFormatSpecifier,
interpreter.location
);
}
}
return new BrsString(this.intrinsic.toString());
},
});
}
Loading

0 comments on commit 9aee9fd

Please sign in to comment.