Skip to content

Commit

Permalink
Fixed conversion functions to Integer: Int(), CInt() and Fix() (#…
Browse files Browse the repository at this point in the history
…74)

Co-authored-by: Bronley Plumb <[email protected]>
  • Loading branch information
lvcabral and TwitchBronBron authored May 3, 2024
1 parent cb787ae commit a1d0a1c
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 34 deletions.
1 change: 1 addition & 0 deletions src/brsTypes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export * from "./components/ContentNode";
export * from "./components/Timer";
export * from "./components/RoAppInfo";
export * from "./components/RoPath";
export * from "./Boxing";
export * from "./coercion";

/**
Expand Down
100 changes: 81 additions & 19 deletions src/stdlib/Math.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import { Callable, ValueKind, Int32, Float, StdlibArgument } from "../brsTypes";
import { RuntimeError, RuntimeErrorDetail } from "../Error";
import {
Callable,
ValueKind,
Int32,
Float,
StdlibArgument,
BrsType,
BrsNumber,
isBrsNumber,
isUnboxable,
} from "../brsTypes";
import { Interpreter } from "../interpreter";

/** Returns the absolute value of a float. */
Expand All @@ -7,7 +18,7 @@ export const Abs = new Callable("Abs", {
args: [new StdlibArgument("x", ValueKind.Float)],
returns: ValueKind.Float,
},
impl: (interpreter: Interpreter, x: Float) => new Float(Math.abs(x.getValue())),
impl: (_: Interpreter, x: Float) => new Float(Math.abs(x.getValue())),
});

/*
Expand All @@ -20,16 +31,26 @@ export const Cdbl = new Callable("Cdbl", {
args: [new StdlibArgument("x", ValueKind.Int32)],
returns: ValueKind.Float,
},
impl: (interpreter: Interpreter, x: Int32) => new Float(x.getValue()),
impl: (_: Interpreter, x: Int32) => new Float(x.getValue()),
});

/** Returns an integer from a float rounding up from midpoints */
export const Cint = new Callable("Cint", {
signature: {
args: [new StdlibArgument("x", ValueKind.Float)],
args: [new StdlibArgument("x", ValueKind.Dynamic)],
returns: ValueKind.Int32,
},
impl: (interpreter: Interpreter, x: Int32) => new Int32(Math.round(x.getValue())),
impl: (interpreter: Interpreter, x: BrsType) => {
if (isUnboxable(x)) {
x = x.unbox();
}
if (isBrsNumber(x)) {
return toInt32(x, "round");
}
interpreter.addError(
new RuntimeError(RuntimeErrorDetail.TypeMismatch, interpreter.location)
);
},
});

/** Returns the integer as a 32-bit float. */
Expand All @@ -38,28 +59,69 @@ export const Csng = new Callable("Csng", {
args: [new StdlibArgument("x", ValueKind.Int32)],
returns: ValueKind.Float,
},
impl: (interpreter: Interpreter, x: Int32) => new Float(x.getValue()),
impl: (_: Interpreter, x: Int32) => new Float(x.getValue()),
});

/** Returns an integer from a float removing fractional parts. */
export const Fix = new Callable("Fix", {
signature: {
args: [new StdlibArgument("x", ValueKind.Float)],
args: [new StdlibArgument("x", ValueKind.Dynamic)],
returns: ValueKind.Int32,
},
impl: (interpreter: Interpreter, x: Int32) => new Int32(Math.trunc(x.getValue())),
impl: (interpreter: Interpreter, x: BrsType) => {
if (isUnboxable(x)) {
x = x.unbox();
}
if (isBrsNumber(x)) {
return toInt32(x, "trunc");
}
interpreter.addError(
new RuntimeError(RuntimeErrorDetail.TypeMismatch, interpreter.location)
);
},
});

/** Returns an integer from a float. */
export const Int = new Callable("Int", {
signature: {
args: [new StdlibArgument("x", ValueKind.Float)],
args: [new StdlibArgument("x", ValueKind.Dynamic)],
returns: ValueKind.Int32,
},
impl: (interpreter: Interpreter, x: Int32) => new Int32(Math.floor(x.getValue())),
impl: (interpreter: Interpreter, x: BrsType) => {
if (isUnboxable(x)) {
x = x.unbox();
}
if (isBrsNumber(x)) {
return toInt32(x);
}
interpreter.addError(
new RuntimeError(RuntimeErrorDetail.TypeMismatch, interpreter.location)
);
},
});

function SgnImpl(interpreter: Interpreter, x: Int32 | Float) {
function toInt32(x: BrsNumber, decimal = "floor"): Int32 {
if (x.kind === ValueKind.Float || x.kind === ValueKind.Double) {
if (decimal === "round") {
return new Int32(Math.round(x.getValue()));
} else if (decimal === "trunc") {
return new Int32(Math.trunc(x.getValue()));
}
return new Int32(Math.floor(x.getValue()));
} else if (x.kind === ValueKind.Int64) {
const maxInt = 0x80000000;
if (x.getValue().lessThan(maxInt) && x.getValue().greaterThan(-maxInt)) {
return new Int32(x.getValue());
} else if (x.getValue().greaterThan(maxInt - 1)) {
return new Int32(maxInt - 1);
} else {
return new Int32(-maxInt);
}
}
return x;
}

function SgnImpl(_: Interpreter, x: Int32 | Float) {
let val = x.getValue();
if (val > 0.0) return new Int32(1);
else if (val < 0.0) return new Int32(-1);
Expand Down Expand Up @@ -91,7 +153,7 @@ export const Atn = new Callable("Atn", {
args: [new StdlibArgument("x", ValueKind.Float)],
returns: ValueKind.Float,
},
impl: (interpreter: Interpreter, x: Float) => new Float(Math.atan(x.getValue())),
impl: (_: Interpreter, x: Float) => new Float(Math.atan(x.getValue())),
});

/** Returns the cosine of a float (argument must be provided in radians). */
Expand All @@ -100,7 +162,7 @@ export const Cos = new Callable("Cos", {
args: [new StdlibArgument("x", ValueKind.Float)],
returns: ValueKind.Float,
},
impl: (interpreter: Interpreter, x: Float) => new Float(Math.cos(x.getValue())),
impl: (_: Interpreter, x: Float) => new Float(Math.cos(x.getValue())),
});

/** Returns the sine of a float (argument must be provided in radians). */
Expand All @@ -109,7 +171,7 @@ export const Sin = new Callable("Sin", {
args: [new StdlibArgument("x", ValueKind.Float)],
returns: ValueKind.Float,
},
impl: (interpreter: Interpreter, x: Float) => new Float(Math.sin(x.getValue())),
impl: (_: Interpreter, x: Float) => new Float(Math.sin(x.getValue())),
});

/** Returns the tangent float (argument must be provided in radians). */
Expand All @@ -118,7 +180,7 @@ export const Tan = new Callable("Tan", {
args: [new StdlibArgument("x", ValueKind.Float)],
returns: ValueKind.Float,
},
impl: (interpreter: Interpreter, x: Float) => new Float(Math.tan(x.getValue())),
impl: (_: Interpreter, x: Float) => new Float(Math.tan(x.getValue())),
});

/** Returns the natural exponent of a float. */
Expand All @@ -127,7 +189,7 @@ export const Exp = new Callable("Exp", {
args: [new StdlibArgument("x", ValueKind.Float)],
returns: ValueKind.Float,
},
impl: (interpreter: Interpreter, x: Float) => new Float(Math.exp(x.getValue())),
impl: (_: Interpreter, x: Float) => new Float(Math.exp(x.getValue())),
});

/** Returns the log of a float. */
Expand All @@ -136,7 +198,7 @@ export const Log = new Callable("Log", {
args: [new StdlibArgument("x", ValueKind.Float)],
returns: ValueKind.Float,
},
impl: (interpreter: Interpreter, x: Float) => new Float(Math.log(x.getValue())),
impl: (_: Interpreter, x: Float) => new Float(Math.log(x.getValue())),
});

/** Returns the square root of a float. */
Expand All @@ -145,7 +207,7 @@ export const Sqr = new Callable("Sqr", {
args: [new StdlibArgument("x", ValueKind.Float)],
returns: ValueKind.Float,
},
impl: (interpreter: Interpreter, x: Float) => new Float(Math.sqrt(x.getValue())),
impl: (_: Interpreter, x: Float) => new Float(Math.sqrt(x.getValue())),
});

/**
Expand All @@ -163,7 +225,7 @@ export const Rnd = new Callable("Rnd", {
args: [new StdlibArgument("range", ValueKind.Int32)],
returns: ValueKind.Dynamic,
},
impl: (interpreter: Interpreter, range: Int32) => {
impl: (_: Interpreter, range: Int32) => {
if (range.getValue() === 0) return new Float(Math.random());
else return new Int32(Math.floor(Math.random() * range.getValue() + 1));
},
Expand Down
22 changes: 22 additions & 0 deletions test/e2e/StdLib.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,28 @@ describe("end to end standard libary", () => {
" 7",
" 1",
"-1",
" 10",
" 10",
" 11",
"-10",
"-11",
"-11",
" 10",
" 10",
" 11",
"-10",
"-11",
"-10",
" 122334343434",
" 2147483647",
" 2147483647",
" 2147483647",
" 2147483647",
" 2147483647",
" 2147483647",
"-2147483648",
"-2147483648",
"-2147483648",
]);
});

Expand Down
66 changes: 51 additions & 15 deletions test/e2e/resources/stdlib/math.brs
Original file line number Diff line number Diff line change
@@ -1,15 +1,51 @@
print Exp(3.1)
print Log(17.4)
print Sqr(11.17)
print Atn(0.5)
print Cos(3.14 / 4)
print Sin(3.14 / 2)
print Tan(3.14 / 4)
print Abs(-3.5)
print Cdbl(17)
print Cint(17.3)
print Csng(204)
print Fix(-2.2)
print Int(7.7)
print Sgn(33.2)
print Sgn(-800)
sub main()
print Exp(3.1)
print Log(17.4)
print Sqr(11.17)
print Atn(0.5)
print Cos(3.14 / 4)
print Sin(3.14 / 2)
print Tan(3.14 / 4)
print Abs(-3.5)
print Cdbl(17)
print Cint(17.3)
print Csng(204)
print Fix(-2.2)
print Int(7.7)
print Sgn(33.2)
print Sgn(-800)

' Positive numbers
print Fix(10.9) ' 10
print Int(10.9) ' 10
print Cint(10.9) ' 11

' Negative numbers
print Fix(-10.9) ' -10
print Int(-10.9) ' -11
print Cint(-10.9) ' -11

' Halfway cases
print Fix(10.5) ' 10
print Int(10.5) ' 10
print Cint(10.5) ' 11

print Fix(-10.5) ' -10
print Int(-10.5) ' -11
print Cint(-10.5) ' -10

' Overflow
lng& = 122334343434
print lng& ' => 122334343434
print Fix(lng&) ' => 2147483647
print Int(lng&) ' => 2147483647
print Cint(lng&)' => 2147483647
lng& = 2147483649
print Fix(lng&) ' => 2147483647
print Int(lng&) ' => 2147483647
print Cint(lng&)' => 2147483647
lng& = -2147483649
print Fix(lng&) ' => 2147483648
print Int(lng&) ' => 2147483648
print Cint(lng&)' => 2147483648
end sub

0 comments on commit a1d0a1c

Please sign in to comment.