import * as Commands from "./../../ast/commands"; import { Types } from "./../../typeSystem/types"; import { toReal } 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 = (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 Promise.resolve(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 = (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 Promise.resolve(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 = function(sto, _) { const x = sto.applyStore("x"); const angle = x.get().mod(360); if (angle.eq(90) || angle.eq(270)) { return Promise.reject( 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 Promise.resolve(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 = 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 Promise.resolve(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 = (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 Promise.resolve(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 = 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 Promise.resolve(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 = (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 Promise.resolve(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 = (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 Promise.resolve(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 = (sto, _) => { const x = sto.applyStore("x"); const result = toReal(1).dividedBy(x.get()); const temp = new StoreValue(Types.REAL, result); sto.insertStore("$", temp); sto.mode = Modes.RETURN; return Promise.resolve(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 = (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 Promise.resolve(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 = (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 Promise.resolve(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 = (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 Promise.resolve(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 = (sto, _) => { const value = sto.applyStore("x"); seed = value.get().toNumber(); sto.mode = Modes.RETURN; return Promise.resolve(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; }