UNPKG

@helios-lang/compiler

Version:

Helios is a Domain Specific Language that compiles to Plutus-Core (i.e. Cardano on-chain validator scripts). Helios is a non-Haskell alternative to Plutus. With this library you can compile Helios scripts and build Cardano transactions, all you need to bu

2,234 lines (2,205 loc) 292 kB
import { REAL_PRECISION } from "@helios-lang/compiler-utils" import { expectDefined } from "@helios-lang/type-utils" import { FTPP, TTPP } from "./ParametricName.js" import { makeRawFunc } from "./RawFunc.js" const MISSING = "<missing>" /** * @import { RawFuncI } from "../index.js" */ /** * Initializes the db containing all the builtin functions * @param {boolean} simplify * @param {boolean} isTestnet // needed for Address.to_bytes() and Address.to_hex() * @returns {Map<string, RawFuncI>} */ // only need to wrap these source in IR right at the very end export function makeRawFunctions(simplify, isTestnet) { /** @type {Map<string, RawFuncI>} */ let db = new Map() // local utility functions /** * @param {RawFuncI} fn */ function add(fn) { if (db.has(fn.name)) { throw new Error(`builtin ${fn.name} duplicate`) } db.set(fn.name, fn) } /** * @param {string} ns */ function addNeqFunc(ns) { add( makeRawFunc( `${ns}____neq`, `(self, other) -> { __helios__bool____not(${ns}____eq(self, other)) }` ) ) } /** * @param {string} ns */ function addDataLikeEqFunc(ns) { add( makeRawFunc( `${ns}____eq`, `(self, other) -> { __core__equalsData(${ns}____to_data(self), ${ns}____to_data(other)) }` ) ) } /** * @param {string} ns */ function addSerializeFunc(ns) { add( makeRawFunc( `${ns}__serialize`, `(self) -> { () -> { __core__serialiseData(${ns}____to_data(self)) } }` ) ) } /** * @param {string} ns */ function addIntLikeFuncs(ns) { add(makeRawFunc(`${ns}____eq`, "__helios__int____eq")) add(makeRawFunc(`${ns}____neq`, "__helios__int____neq")) add(makeRawFunc(`${ns}__serialize`, "__helios__int__serialize")) add(makeRawFunc(`${ns}__from_data`, "__helios__int__from_data")) add( makeRawFunc( `${ns}__from_data_safe`, "__helios__int__from_data_safe" ) ) add(makeRawFunc(`${ns}____to_data`, "__helios__int____to_data")) } /** * @param {string} ns */ function addByteArrayLikeFuncs(ns) { add(makeRawFunc(`${ns}____eq`, "__helios__bytearray____eq")) add(makeRawFunc(`${ns}____neq`, "__helios__bytearray____neq")) add(makeRawFunc(`${ns}__serialize`, "__helios__bytearray__serialize")) add(makeRawFunc(`${ns}__from_data`, "__helios__bytearray__from_data")) add( makeRawFunc( `${ns}__from_data_safe`, "__helios__bytearray__from_data_safe" ) ) add(makeRawFunc(`${ns}____to_data`, "__helios__bytearray____to_data")) add(makeRawFunc(`${ns}____lt`, "__helios__bytearray____lt")) add(makeRawFunc(`${ns}____leq`, "__helios__bytearray____leq")) add(makeRawFunc(`${ns}____gt`, "__helios__bytearray____gt")) add(makeRawFunc(`${ns}____geq`, "__helios__bytearray____geq")) add(makeRawFunc(`${ns}__new`, `__helios__common__identity`)) add(makeRawFunc(`${ns}__bytes`, "__helios__common__identity")) add(makeRawFunc(`${ns}__show`, "__helios__bytearray__show")) } /** * Adds basic auto members to a fully named type * TODO: many types that are currently treated as Data could in fact be treated as something slighly better (eg. lists or pairs) * @param {string} ns * @param {{ * eq?: string, * neq?: string, * serialize?: string, * from_data?: string, * from_data_safe?: string, * to_data?: string * }} custom */ function addDataFuncs(ns, custom = {}) { add(makeRawFunc(`${ns}____eq`, custom?.eq ?? "__helios__common____eq")) add( makeRawFunc( `${ns}____neq`, custom?.neq ?? "__helios__common____neq" ) ) add( makeRawFunc( `${ns}__serialize`, custom?.serialize ?? "__helios__common__serialize" ) ) add( makeRawFunc( `${ns}__from_data`, custom?.from_data ?? "__helios__common__identity" ) ) add( makeRawFunc( `${ns}__from_data_safe`, custom?.from_data_safe ?? `(data) -> {__helios__option__SOME_FUNC(data)}` ) ) add( makeRawFunc( `${ns}____to_data`, custom?.to_data ?? "__helios__common__identity" ) ) } /** * Adds basic auto members to a fully named enum type * @param {string} ns * @param {number} constrIndex */ function addEnumDataFuncs(ns, constrIndex) { add(makeRawFunc(`${ns}____eq`, "__helios__common____eq")) add(makeRawFunc(`${ns}____neq`, "__helios__common____neq")) add(makeRawFunc(`${ns}__serialize`, "__helios__common__serialize")) add(makeRawFunc(`${ns}____to_data`, "__helios__common__identity")) add( makeRawFunc( `${ns}____is`, `(data) -> { __helios__common__enum_tag_equals(data, ${constrIndex}) }` ) ) add( makeRawFunc( `${ns}__from_data`, `(data) -> { __helios__common__assert_constr_index(data, ${constrIndex}) }` ) ) add( makeRawFunc( `${ns}__from_data_safe`, `(data) -> { __core__chooseData( data, () -> { __core__ifThenElse( __core__equalsInteger(${constrIndex}, __core__fstPair(__core__unConstrData__safe(data))), () -> { __helios__option__SOME_FUNC(data) }, () -> { __helios__option__NONE_FUNC } )() }, () -> {__helios__option__NONE_FUNC}, () -> {__helios__option__NONE_FUNC}, () -> {__helios__option__NONE_FUNC}, () -> {__helios__option__NONE_FUNC} )() }` ) ) } /** * Generates the IR needed to unwrap a Plutus-core constrData * @param {string} dataExpr * @param {number} iConstr * @param {number} iField * @param {string} errorExpr * @returns {string} */ function unData( dataExpr, iConstr, iField, errorExpr = 'error("unexpected constructor index")' ) { let inner = "__core__sndPair(pair)" for (let i = 0; i < iField; i++) { inner = `__core__tailList(${inner})` } // deferred evaluation of ifThenElse branches return `(pair) -> {__core__ifThenElse(__core__equalsInteger(__core__fstPair(pair), ${iConstr}), () -> {__core__headList(${inner})}, () -> {${errorExpr}})()}(__core__unConstrData(${dataExpr}))` } /** * Generates IR for constructing a list. * By default the result is kept as list, and not converted to data * @param {string[]} args * @param {boolean} toData * @returns */ function makeList(args, toData = false) { let n = args.length let inner = "__core__mkNilData(())" for (let i = n - 1; i >= 0; i--) { inner = `__core__mkCons(${args[i]}, ${inner})` } if (toData) { inner = `__core__listData(${inner})` } return inner } // Common builtins add( makeRawFunc( "__helios__common__assert_constr_index", `(data, i) -> { __core__ifThenElse( __core__equalsInteger(__core__fstPair(__core__unConstrData(data)), i), () -> {data}, () -> {__helios__error("unexpected constructor index")} )() }` ) ) add(makeRawFunc("__helios__common__identity", `(self) -> {self}`)) add(makeRawFunc("__helios__common____eq", "__core__equalsData")) add( makeRawFunc( "__helios__common____neq", `(a, b) -> { __helios__bool____not(__core__equalsData(a, b)) }` ) ) add( makeRawFunc( "__helios__common__serialize", `(self) -> { () -> { __core__serialiseData(self) } }` ) ) add( makeRawFunc( "__helios__common__any", `(self, fn) -> { (recurse) -> { recurse(recurse, self, fn) }( (recurse, self, fn) -> { __core__chooseList( self, () -> {false}, () -> { __core__ifThenElse( fn(__core__headList__safe(self)), () -> {true}, () -> {recurse(recurse, __core__tailList__safe(self), fn)} )() } )() } ) }` ) ) add( makeRawFunc( "__helios__common__all", `(self, fn) -> { (recurse) -> { recurse(recurse, self, fn) }( (recurse, self, fn) -> { __core__chooseList( self, () -> {true}, () -> { __core__ifThenElse( fn(__core__headList__safe(self)), () -> {recurse(recurse, __core__tailList__safe(self), fn)}, () -> {false} )() } )() } ) }` ) ) add( makeRawFunc( "__helios__common__map", `(self, fn, init) -> { (recurse) -> { recurse(recurse, self, init) }( (recurse, rem, lst) -> { __core__chooseList( rem, () -> {lst}, () -> { __core__mkCons( fn(__core__headList__safe(rem)), recurse(recurse, __core__tailList__safe(rem), lst) ) } )() } ) }` ) ) add( makeRawFunc( "__helios__common__filter", `(self, fn, nil) -> { (recurse) -> { recurse(recurse, self, fn) }( (recurse, self, fn) -> { __core__chooseList( self, () -> {nil}, () -> { (head) -> { __core__ifThenElse( fn(head), () -> {__core__mkCons(head, recurse(recurse, __core__tailList__safe(self), fn))}, () -> {recurse(recurse, __core__tailList__safe(self), fn)} )() }(__core__headList__safe(self)) } )() } ) }` ) ) add( makeRawFunc( "__helios__common__filter_list", `(self, fn) -> { __helios__common__filter(self, fn, __helios__common__list_0) }` ) ) add( makeRawFunc( "__helios__common__filter_map", `(self, fn) -> { __helios__common__filter(self, fn, __core__mkNilPairData(())) }` ) ) add( makeRawFunc( "__helios__common__find", `(self, fn) -> { (recurse) -> { recurse(recurse, self, fn) }( (recurse, self, fn) -> { __core__chooseList( self, () -> {__helios__error("not found")}, () -> { (head) -> { __core__ifThenElse( fn(head), () -> {head}, () -> {recurse(recurse, __core__tailList__safe(self), fn)} )() }(__core__headList__safe(self)) } )() } ) }` ) ) add( makeRawFunc( "__helios__common__find_safe", `(self, fn, callback) -> { (recurse) -> { recurse(recurse, self, fn) }( (recurse, self, fn) -> { __core__chooseList( self, () -> {__core__constrData(1, __helios__common__list_0)}, () -> { (head) -> { __core__ifThenElse( fn(head), () -> {__core__constrData(0, __helios__common__list_1(callback(head)))}, () -> {recurse(recurse, __core__tailList__safe(self), fn)} )() }(__core__headList__safe(self)) } )() } ) }` ) ) add( makeRawFunc( "__helios__common__fold", `(self, fn, z) -> { (recurse) -> { recurse(recurse, self, z) }( (recurse, self, z) -> { __core__chooseList( self, () -> {z}, () -> {recurse(recurse, __core__tailList__safe(self), fn(z, __core__headList__safe(self)))} )() } ) }` ) ) add( makeRawFunc( "__helios__common__fold_lazy", `(self, fn, z) -> { (recurse) -> { recurse(recurse, self) }( (recurse, self) -> { __core__chooseList( self, () -> {z}, () -> {fn(__core__headList__safe(self), () -> {recurse(recurse, __core__tailList__safe(self))})} )() } ) }` ) ) add( makeRawFunc( "__helios__common__insert_in_sorted", `(x, lst, comp) -> { (recurse) -> { recurse(recurse, lst) }( (recurse, lst) -> { __core__chooseList( lst, () -> {__core__mkCons(x, lst)}, () -> { (head) -> { __core__ifThenElse( comp(x, head), () -> {__core__mkCons(x, lst)}, () -> {__core__mkCons(head, recurse(recurse, __core__tailList__safe(lst)))} )() }(__core__headList__safe(lst)) } )() } ) }` ) ) add( makeRawFunc( "__helios__common__sort", `(lst, comp) -> { (recurse) -> { recurse(recurse, lst) }( (recurse, lst) -> { __core__chooseList( lst, () -> {lst}, () -> { (head, tail) -> { __helios__common__insert_in_sorted(head, tail, comp) }(__core__headList__safe(lst), recurse(recurse, __core__tailList__safe(lst))) } )() } ) }` ) ) add( makeRawFunc( "__helios__common__map_get", `(self, key, fnFound, fnNotFound) -> { (recurse) -> { recurse(recurse, self, key) }( (recurse, self, key) -> { __core__chooseList( self, fnNotFound, () -> { (head) -> { __core__ifThenElse( __core__equalsData(key, __core__fstPair(head)), () -> {fnFound(__core__sndPair(head))}, () -> {recurse(recurse, __core__tailList__safe(self), key)} )() }(__core__headList__safe(self)) } )() } ) }` ) ) add( makeRawFunc( "__helios__common__is_in_bytearray_list", `(lst, key) -> { __helios__common__any(lst, (item) -> {__core__equalsData(item, key)}) }` ) ) add( makeRawFunc( "__helios__common__length", `(lst) -> { (recurse) -> { recurse(recurse, lst) }( (recurse, lst) -> { __core__chooseList( lst, () -> {0}, () -> {__core__addInteger(recurse(recurse, __core__tailList__safe(lst)), 1)} )() } ) }` ) ) add( makeRawFunc( "__helios__common__concat", `(a, b) -> { (recurse) -> { recurse(recurse, b, a) }( (recurse, lst, rem) -> { __core__chooseList( rem, () -> {lst}, () -> {__core__mkCons(__core__headList__safe(rem), recurse(recurse, lst, __core__tailList__safe(rem)))} )() } ) }` ) ) add( makeRawFunc( "__helios__common__slice_bytearray", `(self, selfLengthFn) -> { (start, end) -> { (normalize) -> { (fn) -> { fn(normalize(start)) }( (start) -> { (fn) -> { fn(normalize(end)) }( (end) -> { __core__sliceByteString(start, __core__subtractInteger(end, __helios__int__max(start, 0)), self) } ) } ) }( (pos) -> { __core__ifThenElse( __core__lessThanInteger(pos, 0), () -> { __core__addInteger(__core__addInteger(selfLengthFn(self), 1), pos) }, () -> { pos } )() } ) } }` ) ) add( makeRawFunc( "__helios__common__starts_with", `(self, selfLengthFn) -> { (prefix) -> { (n, m) -> { __core__ifThenElse( __core__lessThanInteger(n, m), () -> {false}, () -> { __core__equalsByteString(prefix, __core__sliceByteString(0, m, self)) } )() }(selfLengthFn(self), __core__lengthOfByteString(prefix)) } }` ) ) add( makeRawFunc( "__helios__common__ends_with", `(self, selfLengthFn) -> { (suffix) -> { n = selfLengthFn(self); m = __core__lengthOfByteString(suffix); __core__ifThenElse( __core__lessThanInteger(n, m), () -> { false }, () -> { __core__equalsByteString(suffix, __core__sliceByteString(__core__subtractInteger(n, m), m, self)) } )() } }` ) ) add( makeRawFunc( "__helios__common__mStruct_field", `(self, name) -> { __helios__common__mStruct_field_internal( __core__unMapData(self), name ) }` ) ) // map's underlying list was already extracted. // EXPECTS the indicated field to be present, or throws an error about that field add( /** name: bytes expression, ex: #616263 */ makeRawFunc( "__helios__common__mStruct_field_internal", `(map, name) -> { name_data = __core__bData(name); recurse = (recurse, map) -> { __core__chooseList( map, () -> { // this path is unreachable. In unoptimized code, all data goes through is_valid_data() first, which does a similar check // in optimized code, it seems like this just becomes an error(), as it's never logged. __helios__error( __core__appendString( __core__decodeUtf8__safe(__core__unBData__safe(__core__bData(name))), ": field not found" ) ) }, () -> { head = __core__headList__safe(map); key = __core__fstPair(head); value = __core__sndPair(head); __core__ifThenElse( __core__equalsData(key, name_data), () -> { value }, () -> { recurse(recurse, __core__tailList__safe(map)) } )() } )() }; recurse(recurse, map) }` ) ) // map is expected to already have been extracted // uses data-option instead of callback-option because the optimizer isn't able to optimize out the callback in recursions (calling Any results in MaybeError being added during Analysis) add( makeRawFunc( "__helios__common__mStruct_field_safe", `(map, name) -> { name = __core__bData(name); recurse = (map) -> { __core__chooseList( map, () -> { __helios__option__NONE }, () -> { head = __core__headList__safe(map); key = __core__fstPair(head); __core__ifThenElse( __core__equalsData(key, name), () -> { __helios__option[__helios__data]__some__new(__core__sndPair(head)) }, () -> { recurse(__core__tailList__safe(map)) } )() } )() }; recurse(map) }` ) ) //checks for the presence of a field in an mStruct (not its inner list) add( /** name: Data::ByteArray */ makeRawFunc( "__helios__common__test_mStruct_field", `(self, name, inner_test) -> { __core__chooseData( self, () -> {false}, () -> { map = __core__unMapData__safe(self); recurse = (recurse, map) -> { __core__chooseList(map, () -> { __core__trace( __core__appendString( "Warning: field not found: ", __core__decodeUtf8__safe(__core__unBData__safe(name)) ), () -> {false} )() }, () -> { head = __core__headList__safe(map); key = __core__fstPair(head); value = __core__sndPair(head); __core__ifThenElse( __core__equalsData(key, name), () -> { inner_test(value) }, () -> { recurse(recurse, __core__tailList__safe(map)) } )() } )() }; recurse(recurse, map) }, () -> {false}, () -> {false}, () -> {false} )() }` ) ) add( makeRawFunc( "__helios__common__enum_fields", `(self) -> { __core__sndPair(__core__unConstrData(self)) }` ) ) add( makeRawFunc( "__helios__common__enum_field_0", `(self) -> { __core__headList(__helios__common__enum_fields(self)) }` ) ) add( makeRawFunc( "__helios__common__enum_fields_after_0", `(self) -> { __core__tailList(__helios__common__enum_fields(self)) }` ) ) for (let i = 1; i < 20; i++) { add( makeRawFunc( `__helios__common__enum_field_${i.toString()}`, `(self) -> { __core__headList(__helios__common__enum_fields_after_${(i - 1).toString()}(self)) }` ) ) add( makeRawFunc( `__helios__common__enum_fields_after_${i.toString()}`, `(self) -> { __core__tailList(__helios__common__enum_fields_after_${(i - 1).toString()}(self)) }` ) ) } add(makeRawFunc("__helios__common__struct_field_0", "__core__headList")) add( makeRawFunc( "__helios__common__struct_fields_after_0", "__core__tailList" ) ) for (let i = 1; i < 20; i++) { add( makeRawFunc( `__helios__common__struct_field_${i.toString()}`, `(self) -> { __core__headList(__helios__common__struct_fields_after_${(i - 1).toString()}(self)) }` ) ) add( makeRawFunc( `__helios__common__struct_fields_after_${i.toString()}`, `(self) -> { __core__tailList(__helios__common__struct_fields_after_${(i - 1).toString()}(self)) }` ) ) } add(makeRawFunc("__helios__common__list_0", "__core__mkNilData(())")) add( makeRawFunc( "__helios__common__list_1", `(a) -> { __core__mkCons(a, __helios__common__list_0) }` ) ) for (let i = 2; i < 20; i++) { /** * @type {string[]} */ let args = [] for (let j = 0; j < i; j++) { args.push(`arg${j.toString()}`) } let woFirst = args.slice() let first = expectDefined(woFirst.shift()) add( makeRawFunc( `__helios__common__list_${i.toString()}`, `(${args.join(", ")}) -> { __core__mkCons(${first}, __helios__common__list_${(i - 1).toString()}(${woFirst.join(", ")})) }` ) ) } add( makeRawFunc( `__helios__common__hash_datum_data[${FTPP}0]`, `(data) -> { __core__blake2b_256(${FTPP}0__serialize(data)()) }` ) ) add( makeRawFunc( `__helios__common__test_constr_data_2`, `(data, index, test_a, test_b) -> { __core__chooseData( data, () -> { pair = __core__unConstrData__safe(data); __core__ifThenElse( __core__equalsInteger(__core__fstPair(pair), index), () -> { fields = __core__sndPair(pair); __core__chooseList( fields, () -> { false }, () -> { __core__ifThenElse( test_a(__core__headList__safe(fields)), () -> { tail = __core__tailList__safe(fields); __core__chooseList( tail, () -> { false }, () -> { __core__ifThenElse( test_b(__core__headList__safe(tail)), () -> { __core__chooseList( __core__tailList__safe(tail), () -> { true }, () -> { false } )() }, () -> { false } )() } )() }, () -> { false } )() } )() }, () -> { false } )() }, () -> {false}, () -> {false}, () -> {false}, () -> {false} )() }` ) ) add( makeRawFunc( "__helios__common__unConstrData__safe", `(data, callback_ok, callback_nok) -> { __core__chooseData( data, () -> { pair = __core__unConstrData__safe(data); callback_ok(__core__fstPair(pair), __core__sndPair(pair)) }, callback_nok, callback_nok, callback_nok, callback_nok )() }` ) ) add( makeRawFunc( "__helios__common__unMapData__safe", `(data, callback_ok, callback_nok) -> { __core__chooseData( data, callback_nok, () -> { callback_ok(__core__unMapData__safe(data)) }, callback_nok, callback_nok, callback_nok )() }` ) ) add( makeRawFunc( "__helios__common__unListData__safe", `(data, callback_ok, callback_nok) -> { __core__chooseData( data, callback_nok, callback_nok, () -> { callback_ok(__core__unListData__safe(data)) }, callback_nok, callback_nok )() }` ) ) add( makeRawFunc( "__helios__common__unBoolData__safe", `(data, callback_ok, callback_nok) -> { __helios__common__unConstrData__safe( data, (tag, _) -> { callback_ok( __core__ifThenElse( __core__equalsInteger(tag, 0), false, true ) ) }, callback_nok ) }` ) ) add( makeRawFunc( "__helios__common__unIData__safe", `(data, callback_ok, callback_nok) -> { __core__chooseData( data, callback_nok, callback_nok, callback_nok, () -> { callback_ok(__core__unIData__safe(data)) }, callback_nok )() }` ) ) add( makeRawFunc( "__helios__common__unBData__safe", `(data, callback_ok, callback_nok) -> { __core__chooseData( data, callback_nok, callback_nok, callback_nok, callback_nok, () -> { callback_ok(__core__unBData__safe(data)) } )() }` ) ) add( makeRawFunc( "__helios__common__test_list_head_data", `(test_head, test_tail) -> { (list) -> { __core__chooseList( list, () -> { false }, () -> { __core__ifThenElse( test_head(__core__headList(list)), () -> { test_tail(__core__tailList(list)) }, () -> { false } )() } )() } }` ) ) add( makeRawFunc( "__helios__common__test_list_empty", `(list) -> { __core__chooseList(list, true, false) }` ) ) add(makeRawFunc("__helios__common__test_list_any", `(list) -> {true}`)) add( makeRawFunc( `__helios__common__enum_tag_equals`, `(data, i) -> { __core__equalsInteger(__core__fstPair(__core__unConstrData(data)), i) }` ) ) // Global builtin functions add( makeRawFunc( "__helios__print", `(msg) -> { __core__trace(msg, ()) }` ) ) add( makeRawFunc( "__helios__error", `(msg) -> { __core__trace( msg, () -> { error() } )() }` ) ) add( makeRawFunc( "__helios__assert", `(cond, msg) -> { __core__ifThenElse( cond, () -> { () }, () -> { __core__trace( msg, () -> { error() } )() } )() }` ) ) // Int builtins add(makeRawFunc("__helios__int____eq", "__core__equalsInteger")) add(makeRawFunc("__helios__int__from_data", "__core__unIData")) add( makeRawFunc( "__helios__int__from_data_safe", `(data) -> { __core__chooseData( data, () -> {__helios__option__NONE_FUNC}, () -> {__helios__option__NONE_FUNC}, () -> {__helios__option__NONE_FUNC}, () -> { __helios__option__SOME_FUNC(__core__unIData__safe(data)) }, () -> {__helios__option__NONE_FUNC} )() }` ) ) add( makeRawFunc( "__helios__int__is_valid_data", `(data) -> { __core__chooseData(data, false, false, false, true, false) }` ) ) add(makeRawFunc("__helios__int____to_data", "__core__iData")) addNeqFunc("__helios__int") addSerializeFunc("__helios__int") add( makeRawFunc( "__helios__int____neg", `(self) -> { __core__multiplyInteger(self, -1) }` ) ) add(makeRawFunc("__helios__int____pos", "__helios__common__identity")) add(makeRawFunc("__helios__int____add", "__core__addInteger")) add(makeRawFunc("__helios__int____sub", "__core__subtractInteger")) add(makeRawFunc("__helios__int____mul", "__core__multiplyInteger")) add(makeRawFunc("__helios__int____div", "__core__quotientInteger")) add(makeRawFunc("__helios__int____mod", "__core__modInteger")) add( makeRawFunc( "__helios__int____add1", `(a, b) -> { __core__addInteger( __core__multiplyInteger(a, __helios__real__ONE), b ) }` ) ) add( makeRawFunc( "__helios__int____sub1", `(a, b) -> { __core__subtractInteger( __core__multiplyInteger(a, __helios__real__ONE), b ) }` ) ) add( makeRawFunc( "__helios__int____sub2", `(a, b) -> { bt = __helios__ratio__top(b); bb = __helios__ratio__bottom(b); __helios__ratio__new_internal( __helios__int____sub( __helios__int____mul(a, bb), bt ), bb ) }` ) ) add(makeRawFunc("__helios__int____mul1", "__helios__int____mul")) add( makeRawFunc( "__helios__int____div1", `(a, b) -> { __helios__real__round_calc_result( __core__quotientInteger( __core__multiplyInteger(a, __core__multiplyInteger(__helios__real__ONESQ, 10)), b ) ) }` ) ) add( makeRawFunc( "__helios__int____div2", `(a, b) -> { bt = __helios__ratio__top(b); bb = __helios__ratio__bottom(b); __helios__ratio__new( __helios__int____mul(a, bb), bt ) }` ) ) add( makeRawFunc( "__helios__int____geq", `(a, b) -> { __helios__bool____not(__core__lessThanInteger(a, b)) }` ) ) add( makeRawFunc( "__helios__int____gt", `(a, b) -> { __helios__bool____not(__core__lessThanEqualsInteger(a, b)) }` ) ) add(makeRawFunc("__helios__int____leq", "__core__lessThanEqualsInteger")) add(makeRawFunc("__helios__int____lt", "__core__lessThanInteger")) add( makeRawFunc( "__helios__int____geq1", `(a, b) -> { __helios__bool____not( __core__lessThanInteger( __core__multiplyInteger(a, __helios__real__ONE), b ) ) }` ) ) add( makeRawFunc( "__helios__int____geq2", `(a, b) -> { bt = __helios__ratio__top(b); bb = __helios__ratio__bottom(b); __core__lessThanEqualsInteger( bt, __helios__int____mul(a, bb) ) }` ) ) add( makeRawFunc( "__helios__int____gt1", `(a, b) -> { __helios__bool____not( __core__lessThanEqualsInteger( __core__multiplyInteger(a, __helios__real__ONE), b ) ) }` ) ) add( makeRawFunc( "__helios__int____gt2", `(a, b) -> { bt = __helios__ratio__top(b); bb = __helios__ratio__bottom(b); __core__lessThanInteger( bt, __helios__int____mul(a, bb) ) }` ) ) add( makeRawFunc( "__helios__int____leq1", `(a, b) -> { __core__lessThanEqualsInteger( __core__multiplyInteger(a, __helios__real__ONE), b ) }` ) ) add( makeRawFunc( "__helios__int____leq2", `(a, b) -> { bt = __helios__ratio__top(b); bb = __helios__ratio__bottom(b); __core__lessThanEqualsInteger( __helios__int____mul(a, bb), bt ) }` ) ) add( makeRawFunc( "__helios__int____lt1", `(a, b) -> { __core__lessThanInteger( __core__multiplyInteger(a, __helios__real__ONE), b ) }` ) ) add( makeRawFunc( "__helios__int____lt2", `(a, b) -> { bt = __helios__ratio__top(b); bb = __helios__ratio__bottom(b); __core__lessThanInteger( __helios__int____mul(a, bb), bt ) }` ) ) add( makeRawFunc( "__helios__int__min", `(a, b) -> { __core__ifThenElse( __core__lessThanInteger(a, b), a, b ) }` ) ) add( makeRawFunc( "__helios__int__max", `(a, b) -> { __core__ifThenElse( __core__lessThanInteger(a, b), b, a ) }` ) ) add( makeRawFunc( "__helios__int__bound_min", `(self) -> { (other) -> { __helios__int__max(self, other) } }` ) ) add( makeRawFunc( "__helios__int__bound_max", `(self) -> { (other) -> { __helios__int__min(self, other) } }` ) ) add( makeRawFunc( "__helios__int__bound", `(self) -> { (min, max) -> { __helios__int__max(__helios__int__min(self, max), min) } }` ) ) add( makeRawFunc( "__helios__int__abs", `(self) -> { () -> { __core__ifThenElse( __core__lessThanInteger(self, 0), () -> { __core__multiplyInteger(self, -1) }, () -> { self } )() } }` ) ) add( makeRawFunc( "__helios__int__encode_zigzag", `(self) -> { () -> { __core__ifThenElse( __core__lessThanInteger(self, 0), () -> { __core__subtractInteger(__core__multiplyInteger(self, -2), 1) }, () -> { __core__multiplyInteger(self, 2) } )() } }` ) ) add( makeRawFunc( "__helios__int__decode_zigzag", `(self) -> { () -> { __core__ifThenElse( __core__lessThanInteger(self, 0), () -> { __helios__error("expected positive int") }, () -> { __core__ifThenElse( __core__equalsInteger(__core__modInteger(self, 2), 0), () -> { __core__divideInteger(self, 2) }, () -> { __core__divideInteger(__core__addInteger(self, 1), -2) } )() } )() } }` ) ) add( makeRawFunc( "__helios__int__to_bool", `(self) -> { () -> { __core__ifThenElse(__core__equalsInteger(self, 0), false, true) } }` ) ) add( makeRawFunc( "__helios__int__to_ratio", `(self) -> { () -> { __helios__ratio__new( self, 1 ) } }` ) ) add( makeRawFunc( "__helios__int__to_real", `(self) -> { () -> { __core__multiplyInteger(self, __helios__real__ONE) } }` ) ) add( makeRawFunc( "__helios__int__to_hex", `(self) -> { () -> { recurse = (self, bytes) -> { digit = __core__modInteger(self, 16); bytes = __core__consByteString( __core__ifThenElse( __core__lessThanInteger(digit, 10), __core__addInteger(digit, 48), __core__addInteger(digit, 87) ), bytes ); __core__ifThenElse( __core__lessThanInteger(self, 16), () -> {bytes}, () -> { recurse(__core__divideInteger(self, 16), bytes) } )() }; __core__decodeUtf8__safe( __core__ifThenElse( __core__lessThanInteger(self, 0), () -> { __core__consByteString( 45, recurse(__core__multiplyInteger(self, -1), #) ) }, () -> { recurse(self, #) } )() ) } }` ) ) add( makeRawFunc( "__helios__common__BASE58_ALPHABET", "#31323334353637383941424344454647484a4b4c4d4e505152535455565758595a6162636465666768696a6b6d6e6f707172737475767778797a" ) ) add( makeRawFunc( "__helios__int__to_base58", `(self) -> { () -> { __core__decodeUtf8( __core__ifThenElse( __core__lessThanInteger(self, 0), () -> { __helios__error("expected positive number") }, () -> { recurse = (recurse, self, bytes) -> { digit = __core__modInteger(self, 58); bytes = __core__consByteString( __core__indexByteString(__helios__common__BASE58_ALPHABET, digit), bytes ); __core__ifThenElse( __core__lessThanInteger(self, 58), () -> { bytes }, () -> { recurse(recurse, __core__divideInteger(self, 58), bytes) } )() }; recurse(recurse, self, #) } )() ) } }` ) ) add( makeRawFunc( "__helios__int__BASE58_INVERSE_ALPHABET_1", "#ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff000102030405060708ffffffffffff" ) ) add( makeRawFunc( "__helios__int__BASE58_INVERSE_ALPHABET_2", "#ff090a0b0c0d0e0f10ff1112131415ff161718191a1b1c1d1e1f20ffffffffffff2122232425262728292a2bff2c2d2e2f30313233343536373839ffffffffff" ) ) add( makeRawFunc( "__helios__int__invert_base58_char", `(char) -> { digit = __core__ifThenElse( __core__lessThanInteger(char, 64), () -> { __core__indexByteString(__helios__int__BASE58_INVERSE_ALPHABET_1, char) }, () -> { __core__ifThenElse( __core__lessThanInteger(char, 128), () -> { __core__indexByteString( __helios__int__BASE58_INVERSE_ALPHABET_2, __core__subtractInteger(char, 64) ) }, () -> { 0xff } )() } )(); __core__ifThenElse( __core__equalsInteger(digit, 0xff), () -> { __helios__error("invalid base58 character") }, () -> { digit } )() }` ) ) add( makeRawFunc( "__helios__int__from_base58", `(str) -> { bytes = __core__encodeUtf8(str); n = __core__lengthOfByteString(bytes); recurse = (recurse, acc, pow, i) -> { __core__ifThenElse( __core__equalsInteger(i, -1), () -> { acc }, () -> { new_acc = __core__addInteger( acc, __core__multiplyInteger( __helios__int__invert_base58_char( __core__indexByteString(bytes, i) ), pow ) ); recurse(recurse, new_acc, __core__multiplyInteger(pow, 58), __core__subtractInteger(i, 1)) } )() }; recurse(recurse, 0, 1, __core__subtractInteger(n, 1)) }` ) ) add( makeRawFunc( "__helios__int__show_digit", `(x) -> { __core__addInteger(__core__modInteger(x, 10), 48) }` ) ) add( makeRawFunc( "__helios__int__show", `(self) -> { () -> { __core__decodeUtf8__safe( recurse = (recurse, i, bytes) -> { (bytes) -> { __core__ifThenElse( __core__lessThanInteger(i, 10), () -> { bytes }, () -> { recurse(recurse, __core__divideInteger(i, 10), bytes) } )() }(__core__consByteString(__helios__int__show_digit(i), bytes)) }; __core__ifThenElse( __core__lessThanInteger(self, 0), () -> {__core__consByteString(45, recurse(recurse, __core__multiplyInteger(self, -1), #))}, () -> {recurse(recurse, self, #)} )() ) } }` ) ) // not exposed, assumes positive number add( makeRawFunc( "__helios__int__show_padded", `(self, n) -> { recurse = (recurse, x, pos, bytes) -> { __core__ifThenElse( __core__equalsInteger(x, 0), () -> { __core__ifThenElse( __core__lessThanEqualsInteger(n, pos), () -> { bytes }, () -> { recurse( recurse, 0, __core__addInteger(pos, 1), __core__consByteString(48, bytes) ) } )() }, () -> { recurse( recurse, __core__divideInteger(x, 10), __core__addInteger(pos, 1), __core__consByteString(__helios__int__show_digit(x), bytes) ) } )() }; recurse(recurse, self, 0, #) }` ) ) add( makeRawFunc( "__helios__int__parse_digit", `(digit) -> { __core__ifThenElse( __core__lessThanEqualsInteger(digit, 57), () -> { __core__ifThenElse( __core__lessThanEqualsInteger(48, digit), () -> { __core__subtractInteger(digit, 48) }, () -> { __helios__error("not a digit") } )() }, () -> { __helios__error("not a digit") } )() }` ) ) add( makeRawFunc( "__helios__int__parse_hex_digit", `(hex) -> { __core__ifThenElse( __core__lessThanEqualsInteger(hex, 57), () -> { __core__ifThenElse( __core__lessThanEqualsInteger(48, hex), () -> { __core__subtractInteger(hex, 48) }, () -> { __helios__error("not a hex digit") } )() }, () -> { __core__ifThenElse( __core__lessThanEqualsInteger(hex, 70), () -> { __core__ifThenElse( __core__lessThanEqualsInteger(65, hex), () -> { __core__subtractInteger(hex, 55) }, () -> { __helios__error("not a hex digit") } )() }, () -> { __core__ifThenElse( __core__lessThanEqualsInteger(hex, 102), () -> { __core__ifThenElse( __core__lessThanEqualsInteger(97, hex), () -> { __core__subtractInteger(hex, 87) }, () -> { __helios__error("not a hex digit") } )() }, () -> { __helios__error("not a hex digit") } )() } )() } )() }` ) ) add( makeRawFunc( "__helios__int__parse", `(string) -> { bytes = __core__encodeUtf8(string); n = __core__lengthOfByteString(bytes); b0 = __core__indexByteString(bytes, 0); recurse = (recurse, acc, i) -> { __core__ifThenElse( __core__equalsInteger(i, n), () -> { acc }, () -> { new_acc = __core__addInteger( __core__multiplyInteger(acc, 10), __helios__int__parse_digit(__core__indexByteString(bytes, i)) ); recurse(recurse, new_acc, __core__addInteger(i, 1)) } )() }; __core__ifThenElse( __core__equalsInteger(b0, 48), () -> { __core__ifThenElse( __core__equalsInteger(n, 1), () -> { 0 }, () -> { __helios__error("zero padded integer can't be parsed") } )() }, () -> { __core__ifThenElse( __core__equalsInteger(b0, 45), () -> { __core__ifThenElse( __core__equalsInteger(__core__indexByteString(bytes, 1), 48), () -> { __helios__error("-0 not allowed") }, () -> { __core__multiplyInteger( recurse(recurse, 0, 1), -1 ) } )() }, () -> { recurse(recurse, 0, 0) } )() } )() }` ) ) add( makeRawFunc( "__helios__int__from_big_endian", `(bytes) -> { n = __core__lengthOfByteString(bytes); recurse = (recurse, acc, pow, i) -> { __core__ifThenElse( __core__equalsInteger(i, -1), () -> { acc }, () -> { new_acc = __core__addInteger( acc, __core__multiplyInteger(__core__indexByteString(bytes, i), pow) ); recurse(recurse, new_acc, __core__multiplyInteger(pow, 256), __core__subtractInteger(i, 1)) } )() }; recurse(recurse, 0, 1, __core__subtractInteger(n, 1)) }` ) ) add( makeRawFunc( "__helios__int__from_little_endian", `(bytes) -> { n = __core__lengthOfByteString(bytes); recurse = (recurse, acc, pow, i) -> { __core__ifThenElse( __core__equalsInteger(i, n), () -> { acc }, () -> { new_acc = __core__addInteger( acc, __core__multiplyInteger(__core__indexByteString(bytes, i), pow) ); recurse(recurse, new_acc, __core__multiplyInteger(pow, 256), __core__addInteger(i, 1)) } )() }; recurse(recurse, 0, 1, 0) }` ) ) add( makeRawFunc( "__helios__int__to_big_endian", `(self) -> { () -> { __core__ifThenElse( __core__lessThanInteger(self, 0), () -> { __helios__error("can't convert negative number to big endian bytearray") }, () -> { recurse = (recurse, self, bytes) -> { bytes = __core__consByteString(__core__modInteger(self, 256), bytes); __core__ifThenElse( __core__lessThanInteger(self, 256), () -> { bytes }, () -> { recurse( recurse, __core__divideInteger(self, 256), bytes ) } )() }; recurse(recurse, self, #) } )() } }` ) ) add( makeRawFunc( "__helios__int__to_little_endian", `(self) -> { () -> { __core__ifThenElse( __core__lessThanInteger(self, 0), () -> { __helios__error("can't convert negative number to little endian bytearray") }, () -> { recurse = (recurse, self) -> { __core__consByteString( __core__modInteger(self, 256), __core__ifThenElse( __core__lessThanInteger(self, 256), () -> { # }, () -> { recurse(recurse, __core__divideInteger(self, 256)) } )() ) }; recurse(recurse, self) } )() } }` ) ) add( makeRawFunc( "__helios__int__sqrt", `(x) -> { __core__ifThenElse( __core__lessThanInteger(x, 2), () -> { __core__ifThenElse( __core__equalsInteger(x, 1), () -> { 1 }, () -> { __core__ifThenElse( __core__equalsInteger(x, 0), () -> { 0 }, () -> { __helios__error("negative number in sqrt") } )() } )() }, () -> { recurse = (recurse, x0) -> { x1 = __core__divideInteger( __core__addInteger( x0, __core__divideInteger(x, x0) ), 2 ); __core__ifThenElse( __core__lessThanEqualsInteger(x0, x1), () -> { x0 }, () -> { recurse(recurse, x1) } )() }; recurse(recurse, __core__divideInteger(x, 2)) } )() }` ) ) // Ratio builtins addDataFuncs("__helios__ratio") add( makeRawFunc( "__helios__ratio__equals", `(self) -> { (other) -> { at = __helios__ratio__top(self); ab = __helios__ratio__bottom(self); bt = __helios__ratio__top(other); bb = __helios__ratio__bottom(other); __core__equalsInteger( __core__multiplyInteger(at, bb), __core__multiplyInteger(bt, ab) ) } }` ) ) add( makeRawFunc( "__helios__ratio__is_valid_data", `(data) -> { __helios__common__unListData__safe( data, __helios__common__test_list_head_data( __helios__int__is_valid_data, __helios__common__test_list_head_data( (bottom_data) -> { __helios__common__unIData__safe( bottom_data, (bottom) -> { __core__ifThenElse( __core__lessThanInteger(0, bottom), () -> { true }, () -> { false } )() }, () -> {false} ) }, __helios__common__test_list_empty ) ), () -> {false} ) }` ) ) add( makeRawFunc( "__helios__ratio__new_internal", `(top, bottom) -> { __core__listData( __core__mkCons( __core__iData(top), __core__mkCons( __core__iData(bottom), __core__mkNilData(()) ) ) ) }` ) ) add( makeRawFunc( "__helios__ratio__new", `(top, bottom) -> { __core__ifThenElse( __core__lessThanInteger(bottom, 0), () -> { __helios__ratio__new_internal(__core__multiplyInteger(top, -1), __core__multiplyInteger(bottom, -1)) }, () -> { __helios__ratio__new_internal(top, bottom) } )() }` ) ) add( makeRawFunc( "__helios__ratio__top", `(self) -> { __core__unIData(__core__headList(__core__unListData(self))) }` ) ) add( makeRawFunc( "__helios__ratio__bottom", `(self) -> { __core__unIData(__core__headList(__core__tailList(__core__unListData(self)))) }` ) ) add( makeRawFunc( "__helios__ratio____add", `(a, b) -> { at = __helios__ratio__top(a); ab = __helios__ratio__bottom(a); bt = __helios__ratio__top(b); bb = __helios__ratio__bottom(b); new_bottom = __helios__int____mul(ab, bb); new_top = __helios__int____add( __helios__int____mul(at, bb), __helios__int____mul(bt, ab) ); __helios__ratio__new_internal(new_top, new_bottom) }` ) ) add( makeRawFunc( "__helios__rat