Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/lib/op/LibAllStandardOps.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import {LibOpMin} from "./math/LibOpMin.sol";
import {LibOpMinNegativeValue} from "./math/LibOpMinNegativeValue.sol";
import {LibOpMinPositiveValue} from "./math/LibOpMinPositiveValue.sol";
import {LibOpMul} from "./math/LibOpMul.sol";
import {LibOpPi} from "./math/LibOpPi.sol";
import {LibOpPower} from "./math/LibOpPower.sol";
import {LibOpSqrt} from "./math/LibOpSqrt.sol";
import {LibOpSub} from "./math/LibOpSub.sol";
Expand All @@ -102,7 +103,7 @@ import {LibParseLiteralHex} from "../parse/literal/LibParseLiteralHex.sol";
import {LibParseLiteralSubParseable} from "../parse/literal/LibParseLiteralSubParseable.sol";

/// @dev Number of ops currently provided by `AllStandardOps`.
uint256 constant ALL_STANDARD_OPS_LENGTH = 72;
uint256 constant ALL_STANDARD_OPS_LENGTH = 73;

/// @title LibAllStandardOps
/// @notice Every opcode available from the core repository laid out as a single
Expand Down Expand Up @@ -287,6 +288,7 @@ library LibAllStandardOps {
"The minimum positive representable float value. This is the smallest number that can be represented that is still greater than zero."
),
AuthoringMetaV2("mul", "Multiplies all numbers together."),
AuthoringMetaV2("pi", "The mathematical constant pi."),
AuthoringMetaV2("power", "Raises the first number to the power of the second number."),
AuthoringMetaV2("sqrt", "Calculates the square root of the input. Errors if the input is negative."),
AuthoringMetaV2("sub", "Subtracts all numbers from the first number."),
Expand Down Expand Up @@ -502,6 +504,8 @@ library LibAllStandardOps {
LibParseOperand.handleOperandDisallowed,
// mul
LibParseOperand.handleOperandDisallowed,
// pi
LibParseOperand.handleOperandDisallowed,
// power
LibParseOperand.handleOperandDisallowed,
// sqrt
Expand Down Expand Up @@ -620,6 +624,7 @@ library LibAllStandardOps {
LibOpMinNegativeValue.integrity,
LibOpMinPositiveValue.integrity,
LibOpMul.integrity,
LibOpPi.integrity,
LibOpPower.integrity,
LibOpSqrt.integrity,
LibOpSub.integrity,
Expand Down Expand Up @@ -724,6 +729,7 @@ library LibAllStandardOps {
LibOpMinNegativeValue.run,
LibOpMinPositiveValue.run,
LibOpMul.run,
LibOpPi.run,
LibOpPower.run,
LibOpSqrt.run,
LibOpSub.run,
Expand Down
44 changes: 44 additions & 0 deletions src/lib/op/math/LibOpPi.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity ^0.8.25;

import {Pointer} from "rain-solmem-0.1.28/src/lib/LibPointer.sol";
import {OperandV2, StackItem} from "rainlang-interface-0.2.8/src/interface/IInterpreterV4.sol";
import {InterpreterState} from "../../state/LibInterpreterState.sol";
import {IntegrityCheckState} from "../../integrity/LibIntegrityCheck.sol";
import {Float, LibDecimalFloat} from "rain-math-float-0.2.1/src/lib/LibDecimalFloat.sol";

/// @title LibOpPi
/// @notice Stacks the mathematical constant pi.
library LibOpPi {
/// @notice `pi` integrity check. Requires 0 inputs and produces 1 output.
/// @return The number of inputs.
/// @return The number of outputs.
function integrity(IntegrityCheckState memory, OperandV2) internal pure returns (uint256, uint256) {
return (0, 1);
}

/// @notice `pi` opcode. Pushes the mathematical constant pi onto the stack.
/// @param stackTop Pointer to the top of the stack.
/// @return The new stack top pointer after execution.
function run(InterpreterState memory, OperandV2, Pointer stackTop) internal pure returns (Pointer) {
Float pi = LibDecimalFloat.FLOAT_PI;
assembly ("memory-safe") {
stackTop := sub(stackTop, 0x20)
mstore(stackTop, pi)
}
return stackTop;
}

/// @notice Reference implementation of `pi` for testing.
/// @return The output values to push onto the stack.
function referenceFn(InterpreterState memory, OperandV2, StackItem[] memory)
internal
pure
returns (StackItem[] memory)
{
StackItem[] memory outputs = new StackItem[](1);
outputs[0] = StackItem.wrap(Float.unwrap(LibDecimalFloat.FLOAT_PI));
return outputs;
}
}
28 changes: 15 additions & 13 deletions test/src/lib/op/LibAllStandardOps.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -201,33 +201,35 @@ contract LibAllStandardOpsTest is Test {
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[58].word, bytes32("mul"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[59].word, bytes32("power"));
assertEq(words[59].word, bytes32("pi"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[60].word, bytes32("sqrt"));
assertEq(words[60].word, bytes32("power"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[61].word, bytes32("sub"));
assertEq(words[61].word, bytes32("sqrt"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[62].word, bytes32("sub"));
// math/growth/
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[62].word, bytes32("exponential-growth"));
assertEq(words[63].word, bytes32("exponential-growth"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[63].word, bytes32("linear-growth"));
assertEq(words[64].word, bytes32("linear-growth"));
// math/uint256/
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[64].word, bytes32("uint256-add"));
assertEq(words[65].word, bytes32("uint256-add"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[65].word, bytes32("uint256-div"));
assertEq(words[66].word, bytes32("uint256-div"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[66].word, bytes32("uint256-max-value"));
assertEq(words[67].word, bytes32("uint256-max-value"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[67].word, bytes32("uint256-mul"));
assertEq(words[68].word, bytes32("uint256-mul"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[68].word, bytes32("uint256-power"));
assertEq(words[69].word, bytes32("uint256-power"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[69].word, bytes32("uint256-sub"));
assertEq(words[70].word, bytes32("uint256-sub"));
// store/
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[70].word, bytes32("get"));
assertEq(words[71].word, bytes32("get"));
//forge-lint: disable-next-line(unsafe-typecast)
assertEq(words[71].word, bytes32("set"));
assertEq(words[72].word, bytes32("set"));
}
}
82 changes: 82 additions & 0 deletions test/src/lib/op/math/LibOpPi.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity =0.8.25;

import {OpTest, UnexpectedOperand} from "test/abstract/OpTest.sol";
import {InterpreterState} from "../../../../../src/lib/state/LibInterpreterState.sol";
import {LibOpPi} from "../../../../../src/lib/op/math/LibOpPi.sol";
import {LibOperand, OperandV2} from "test/lib/operand/LibOperand.sol";
import {IntegrityCheckState} from "../../../../../src/lib/integrity/LibIntegrityCheck.sol";
import {
EvalV4,
StackItem,
FullyQualifiedNamespace,
SourceIndexV2
} from "rainlang-interface-0.2.8/src/interface/IInterpreterV4.sol";
import {SignedContextV1} from "rainlang-interface-0.2.8/src/interface/IInterpreterCallerV4.sol";
import {LibContext} from "rainlang-interface-0.2.8/src/lib/caller/LibContext.sol";
import {Float, LibDecimalFloat} from "rain-math-float-0.2.1/src/lib/LibDecimalFloat.sol";

/// @title LibOpPiTest
/// @notice Tests for the mathematical constant pi opcode.
contract LibOpPiTest is OpTest {
/// Directly test the integrity logic of LibOpPi.
function testOpPiIntegrity(IntegrityCheckState memory state, uint8 inputs, uint8 outputs, uint16 operandData)
external
pure
{
inputs = uint8(bound(inputs, 0, 0x0F));
outputs = uint8(bound(outputs, 0, 0x0F));
(uint256 calcInputs, uint256 calcOutputs) =
LibOpPi.integrity(state, LibOperand.build(inputs, outputs, operandData));

assertEq(calcInputs, 0);
assertEq(calcOutputs, 1);
}

/// Directly test the runtime logic of LibOpPi. This tests that the
/// opcode correctly pushes the mathematical constant pi onto the stack.
function testOpPiRun(uint16 operandData) external view {
InterpreterState memory state = opTestDefaultInterpreterState();
OperandV2 operand = LibOperand.build(0, 1, operandData);
StackItem[] memory inputs = new StackItem[](0);
opReferenceCheck(state, operand, LibOpPi.referenceFn, LibOpPi.integrity, LibOpPi.run, inputs);
}

/// Test the eval of a mathematical constant pi opcode parsed from a string.
function testOpPiEval() external view {
bytes memory bytecode = I_DEPLOYER.parse2("_: pi();");

(StackItem[] memory stack, bytes32[] memory kvs) = I_INTERPRETER.eval4(
EvalV4({
store: I_STORE,
namespace: FullyQualifiedNamespace.wrap(0),
bytecode: bytecode,
sourceIndex: SourceIndexV2.wrap(0),
context: LibContext.build(new bytes32[][](0), new SignedContextV1[](0)),
inputs: new StackItem[](0),
stateOverlay: new bytes32[](0)
})
);
assertEq(stack.length, 1);
assertEq(StackItem.unwrap(stack[0]), Float.unwrap(LibDecimalFloat.FLOAT_PI));
assertEq(kvs.length, 0);
}

function testOpPiEvalOneInput() external {
checkBadInputs("_: pi(0x00);", 1, 0, 1);
}

function testOpPiEvalZeroOutputs() external {
checkBadOutputs(": pi();", 0, 1, 0);
}

function testOpPiEvalTwoOutputs() external {
checkBadOutputs("_ _: pi();", 0, 1, 2);
}

/// Test that operand is disallowed.
function testOpPiEvalOperandDisallowed() external {
checkUnhappyParse("_: pi<0>();", abi.encodeWithSelector(UnexpectedOperand.selector));
}
}
Loading