import * as Commands from './../../ast/commands'; import { Types } from './../../typeSystem/types'; import * as Parsers from "./../../typeSystem/parsers"; import { Decimal } from 'decimal.js'; import { MultiType } from '../../typeSystem/multiType'; import { ArrayType } from '../../typeSystem/array_type'; import { Modes } from '../modes'; import { StoreValue } from '../store/value/store_value'; import { ProcessorErrorFactory } from '../error/processorErrorFactory'; /** * sin * cos * tan * sqrt * pow * log * abs * negate * invert * max * min */ function convertToRadians(degrees) { return degrees.times(Decimal.acos(-1)).div(180); } export function createSinFun () { const sinFun = async (sto, _) => { const x = sto.applyStore('x'); const angle = x.get().mod(360); let result = null; if(angle.eq(90)) { result = new Decimal(1); } else if (angle.eq(180)) { result = new Decimal(0); } else if (angle.eq(270)) { result = new Decimal(-1); } else { result = Decimal.sin(convertToRadians(angle)); } const temp = new StoreValue(Types.REAL, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock([], [new Commands.SysCall(sinFun)]); const func = new Commands.Function( "$sin", Types.REAL, [ new Commands.FormalParameter( new MultiType([Types.INTEGER, Types.REAL]), "x", false ) ], block ); return func; } export function createCosFun () { const cosFun = async (sto, _) => { const x = sto.applyStore('x'); const angle = x.get().mod(360); let result = null; if (angle.eq(90)) { result = new Decimal(0); } else if (angle.eq(180)) { result = new Decimal(-1); } else if (angle.eq(270)) { result = new Decimal(0); } result = Decimal.cos(convertToRadians(angle)); const temp = new StoreValue(Types.REAL, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock([], [new Commands.SysCall(cosFun)]); const func = new Commands.Function( "$cos", Types.REAL, [ new Commands.FormalParameter( new MultiType([Types.INTEGER, Types.REAL]), "x", false ) ], block ); return func; } export function createTanFun () { const tanFun = async function (sto, _) { const x = sto.applyStore('x'); const angle = x.get().mod(360); if(angle.eq(90) || angle.eq(270)) { throw ProcessorErrorFactory.undefined_tanget_value(x.get().toNumber(), this.function_call_stack.pop()); } const result = Decimal.tan(convertToRadians(angle)); const temp = new StoreValue(Types.REAL, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock([], [new Commands.SysCall(tanFun)]); const func = new Commands.Function( "$tan", Types.REAL, [ new Commands.FormalParameter( new MultiType([Types.INTEGER, Types.REAL]), "x", false ) ], block ); return func; } export function createSqrtFun () { const sqrtFun = async function (sto, _) { const x = sto.applyStore('x'); if(x.get().isNeg()) { return Promise.reject(ProcessorErrorFactory.negative_sqrt_value(this.function_call_stack.pop())); } const result = x.get().sqrt(); const temp = new StoreValue(Types.REAL, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock([], [new Commands.SysCall(sqrtFun)]); const func = new Commands.Function( "$sqrt", Types.REAL, [ new Commands.FormalParameter( new MultiType([Types.INTEGER, Types.REAL]), "x", false ) ], block ); return func; } export function createPowFun () { const powFun = async (sto, _) => { const x = sto.applyStore('x'); const y = sto.applyStore('y'); const result = x.get().pow(y.get()); const temp = new StoreValue(Types.REAL, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock([], [new Commands.SysCall(powFun)]); const func = new Commands.Function( "$pow", Types.REAL, [ new Commands.FormalParameter( new MultiType([Types.INTEGER, Types.REAL]), "x", false ), new Commands.FormalParameter( new MultiType([Types.INTEGER, Types.REAL]), "y", false ) ], block ); return func; } export function createLogFun () { const logFun = async function (sto, _) { const x = sto.applyStore('x'); if (x.get().isNegative()) { return Promise.reject( ProcessorErrorFactory.negative_log_value(this.function_call_stack.pop()) ); } const result = Decimal.log10(x.get()); const temp = new StoreValue(Types.REAL, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock([], [new Commands.SysCall(logFun)]); const func = new Commands.Function( "$log", Types.REAL, [ new Commands.FormalParameter( new MultiType([Types.INTEGER, Types.REAL]), "x", false ) ], block ); return func; } export function createAbsFun () { const absFun = async (sto, _) => { const x = sto.applyStore('x'); const result = x.get().abs(); const temp = new StoreValue(x.type, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock([], [new Commands.SysCall(absFun)]); const func = new Commands.Function( "$abs", new MultiType([Types.INTEGER, Types.REAL]), [ new Commands.FormalParameter( new MultiType([Types.INTEGER, Types.REAL]), "x", false ) ], block ); return func; } export function createNegateFun () { const negateFun = async (sto, _) => { const x = sto.applyStore('x'); const result = x.get().negated(); const temp = new StoreValue(x.type, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock( [], [new Commands.SysCall(negateFun)] ); const func = new Commands.Function( "$negate", new MultiType([Types.INTEGER, Types.REAL]), [ new Commands.FormalParameter( new MultiType([Types.INTEGER, Types.REAL]), "x", false ) ], block ); return func; } export function createInvertFun() { const invertFun = async (sto, _) => { const x = sto.applyStore('x'); const result = Parsers.toReal(1).dividedBy(x.get()); const temp = new StoreValue(Types.REAL, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock( [], [new Commands.SysCall(invertFun)] ); const func = new Commands.Function( "$invert", Types.REAL, [ new Commands.FormalParameter( new MultiType([Types.INTEGER, Types.REAL]), "x", false ) ], block ); return func; } export function createMaxFun () { const maxFun = async (sto, _) => { const x = sto.applyStore('x'); const numbers = x.get().map(sto_addrs => sto_addrs.get()); const result = Decimal.max(...numbers); const temp = new StoreValue(x.type.innerType, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const paramType = new ArrayType( new MultiType([Types.INTEGER, Types.REAL]), 1 ); const block = new Commands.CommandBlock([], [new Commands.SysCall(maxFun)]); const func = new Commands.Function( "$max", new MultiType([Types.INTEGER, Types.REAL]), [new Commands.FormalParameter(paramType, "x", false)], block ); return func; } export function createMinFun () { const minFun = async (sto, _) => { const x = sto.applyStore('x'); const numbers = x.get().map(sto_addrs => sto_addrs.get()); const result = Decimal.min(...numbers); const temp = new StoreValue(x.type.innerType, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const paramType = new ArrayType( new MultiType([Types.INTEGER, Types.REAL]), 1 ); const block = new Commands.CommandBlock([], [new Commands.SysCall(minFun)]); const func = new Commands.Function( "$min", new MultiType([Types.INTEGER, Types.REAL]), [new Commands.FormalParameter(paramType, "x", false)], block ); return func; } let seed = Date.now(); export function createRandFun() { const a = 16807; const m = 2147483647; const c = 12345; const randFun = async (sto, _) => { seed = (a * seed + c) % m; const val = seed / (m - 1); const temp = new StoreValue(Types.REAL, new Decimal(val)); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock([], [new Commands.SysCall(randFun)]); const func = new Commands.Function("$rand", Types.REAL, [], block); return func; } export function createSetSeedFun() { const setSeedFun = async (sto, _) => { const value = sto.applyStore("x"); seed = value.get().toNumber(); sto.mode = Modes.RETURN; return sto; }; const block = new Commands.CommandBlock( [], [new Commands.SysCall(setSeedFun)] ); const func = new Commands.Function( "$setSeed", Types.VOID, [new Commands.FormalParameter(Types.INTEGER, "x", false)], block ); return func; }