@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
JavaScript
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