fez-lisp
Version:
Lisp interpreted & compiled to JavaScript
1,562 lines (1,545 loc) • 39.1 kB
JavaScript
import stdT from '../lib/baked/std-T.js'
import std from '../lib/baked/std.js'
import { getReturn, getReturns, getType, getTypes, isSubType } from './check.js'
import {
APPLY,
ATOM,
DEBUG,
FLAG,
KEYWORDS,
PLACEHOLDER,
STATIC_TYPES,
TYPE,
VALUE,
WORD
} from './keywords.js'
import { isLeaf } from './parser.js'
import { shakedList, stringifyArgs } from './utils.js'
export const ARG_COUNT = 'argumentsN'
export const VARIADIC = Infinity
export const STATS = '__stats__'
export const ARGUMENTS = 'arguments'
export const RETURNS = 'returns'
export const SCOPE_NAME = '__scope__'
export const TYPE_PROP = 'type'
export const SIGNATURE = 'name'
export const TYPE_NAME = 'type_name'
export const RETURN_NAME = 'return_name'
export const UNBOUND_VARIABLE = '__unbound__'
export const UNKNOWN = -1
export const COLLECTION = 3
export const BOOLEAN = 5
export const NUMBER = 6
export const ANY = 4
export const GENERIC = 7
export const ANONYMOUS_FUNCTION_TYPE_PREFIX = 'lambda::annonymous::'
export const MAX_ARGUMENT_RETRY = 1
export const MAX_RETRY_DEFINITION = 30
export const IS_ARGUMENT = 'is_arg'
export const NIL = 'nil'
export const TRUE_WORD = 'true'
export const FALSE_WORD = 'false'
export const GET_ARRAY_INFERENCE_SET = new Set([
KEYWORDS.GET_ARRAY,
'array:get',
'array:at',
'array:first',
'array:second',
'array:third',
'array:last',
'array:pop!'
])
export class SubType {
constructor(args) {
this.types = []
this.types.push(...args)
}
add(type) {
this.types.push(type)
return this
}
has(type) {
return this.types[0] === type
}
nestedLevels() {
return this.types.length - 1
}
isMatching(b) {
for (let i = 0; i < this.types.length; ++i) {
if (
this.types[i] == undefined ||
b.types[i] == undefined ||
this.types[i] === UNKNOWN ||
b.types[i] === UNKNOWN ||
this.types[i] === ANY ||
b.types[i] === ANY ||
this.types[i] === GENERIC ||
b.types[i] === GENERIC
)
return true
if (this.types[i] !== b.types[i]) return false
}
return true
}
get size() {
return this.types.length
}
*[Symbol.iterator]() {
for (let i = 0, len = this.size; i < len; ++i) yield this.types[i]
}
}
export const BOOLEAN_SUBTYPE = () => new SubType([BOOLEAN])
export const COLLECTION_SUBTYPE = () => new SubType([COLLECTION])
export const NUMBER_SUBTYPE = () => new SubType([NUMBER])
export const GENERIC_SUBTYPE = () => new SubType([GENERIC])
export const ABSTRACTION_SUBTYPE = () => new SubType([APPLY])
export const UNKNOWN_SUBTYPE = () => new SubType([UNKNOWN])
const SPECIAL_BOOLEAN = BOOLEAN_SUBTYPE()
const SPECIAL_COLLECTION = COLLECTION_SUBTYPE()
const SPECIAL_NUMBER = NUMBER_SUBTYPE()
const SPECIAL_ABSTRACTION = ABSTRACTION_SUBTYPE()
export const toTypeNames = (type) => {
switch (type) {
case APPLY:
return 'Abstraction'
case BOOLEAN:
return 'Boolean'
case ATOM:
return 'Atom'
case NUMBER:
return 'Number'
case UNKNOWN:
return 'Unknown'
case COLLECTION:
return 'Unknown[]'
case ANY:
return 'Any'
case GENERIC:
// return 'T'
default:
return 'Unknown'
}
}
export const extractArrayType = (type) => {
const arr = [...type].filter((x) => x === '[')
return [type.replaceAll('[]', ''), arr.length]
}
const fillArrayType = (n) => Array.from({ length: n - 1 }).fill(COLLECTION)
export const toTypeCodes = (type, i) => {
const [t, n] = extractArrayType(type)
switch (t) {
case 'Abstraction':
if (n) return [COLLECTION, new SubType(fillArrayType(n).concat(APPLY))]
return [APPLY]
case 'Boolean':
if (n) return [COLLECTION, new SubType(fillArrayType(n).concat(BOOLEAN))]
return [ATOM, BOOLEAN_SUBTYPE()]
case 'Atom':
if (n) return [COLLECTION, new SubType(fillArrayType(n).concat(ATOM))]
return [ATOM]
case 'Number':
if (n) return [COLLECTION, new SubType(fillArrayType(n).concat(NUMBER))]
return [ATOM, NUMBER_SUBTYPE()]
case 'Unknown':
if (n) return [COLLECTION, new SubType(fillArrayType(n))]
return [UNKNOWN]
case 'Any':
return [ANY]
default: {
const d = type[0] === '[' ? -1 : 1
if (n)
return [
COLLECTION,
new SubType(fillArrayType(n).concat(UNKNOWN)),
[]
]
return [UNKNOWN, undefined, [i, d]]
}
}
}
export const toTypeNamesAnyToUknown = (type) => {
switch (type) {
case ANY:
return toTypeNames(UNKNOWN)
default:
return toTypeNames(type)
}
}
export const GETTER = 1
export const SETTER = 2
export const SPECIAL_FORM_TYPES = {
[]: ';',
// [ORDER]: 0,
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.ABSTRACTION,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [APPLY]
}
},
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.ABSTRACTIONS,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [COLLECTION, SPECIAL_ABSTRACTION]
}
},
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.ATOM,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [ATOM]
}
},
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.BOOLEAN,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.BOOLEANS,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [COLLECTION, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.NUMBER,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.NUMBERS,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [COLLECTION, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.COLLECTION,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [COLLECTION]
}
},
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.COLLECTIONS,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [COLLECTION, SPECIAL_COLLECTION]
}
},
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.UNKNOWN,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [UNKNOWN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: STATIC_TYPES.ANY,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
}
],
[]: [ANY]
}
},
[]: {
[]: {
[]: [APPLY],
[]: DEBUG.LOG,
retried: Infinity,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [UNKNOWN],
[]: [UNKNOWN],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [COLLECTION],
[]: [COLLECTION],
[]: [],
[]: 0
}
}
],
[]: 2,
[]: [UNKNOWN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: DEBUG.STRING,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [COLLECTION],
[]: [COLLECTION],
[]: [],
[]: 0
}
}
],
[]: [COLLECTION]
}
},
[]: {
[]: {
[]: [APPLY],
[]: DEBUG.UNQUOTED_STRING,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [COLLECTION],
[]: [COLLECTION],
[]: [],
[]: 0
}
}
],
[]: [COLLECTION]
}
},
[]: {
[]: {
[]: [APPLY],
[]: DEBUG.SIGNATURE,
retried: Infinity,
[]: VARIADIC,
[]: [UNKNOWN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: DEBUG.TYPE_SIGNATURE,
retried: Infinity,
[]: VARIADIC,
[]: [UNKNOWN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.BLOCK,
retried: Infinity,
[]: VARIADIC,
[]: [UNKNOWN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.ANONYMOUS_FUNCTION,
retried: Infinity,
[]: VARIADIC,
[]: [APPLY]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.CALL_FUNCTION,
retried: Infinity,
[]: VARIADIC,
[]: [UNKNOWN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.CREATE_ARRAY,
retried: Infinity,
[]: VARIADIC,
[]: [COLLECTION]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.LOOP,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM],
[]: [ATOM],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ANY],
[]: [ANY],
[]: [],
[]: 0
}
}
],
[]: [ATOM]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.ADDITION,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.MULTIPLICATION,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.SUBTRACTION,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.DIVISION,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.BITWISE_AND,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.BITWISE_NOT,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.BITWISE_OR,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.BITWISE_XOR,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.BITWISE_LEFT_SHIFT,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.BITWISE_RIGHT_SHIFT,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.GET_ARRAY,
tag: GETTER,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [COLLECTION],
[]: [COLLECTION],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ANY]
}
},
[]: {
[]: {
[]: [APPLY],
tag: SETTER,
retried: Infinity,
[]: 3,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [COLLECTION],
[]: [COLLECTION],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ANY],
[]: [ANY],
[]: [],
[]: 0
}
}
],
[]: [COLLECTION]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.POP_ARRAY,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [COLLECTION],
[]: [COLLECTION],
[]: [],
[]: 0
}
}
],
// [GENERIC, new SubType([PLACEHOLDER]), 0]
[]: [COLLECTION]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.ARRAY_LENGTH,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [COLLECTION],
[]: [COLLECTION],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_NUMBER]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.IF,
retried: Infinity,
[]: 3,
[]: [
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ANY],
[]: [ANY],
[]: [],
[]: 0
}
},
{
[]: {
retried: 0,
[]: PLACEHOLDER,
[]: [ANY],
[]: [ANY],
[]: [],
[]: 0
}
}
],
[]: [ANY]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.NOT,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.EQUAL,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM],
[]: [ATOM],
[]: [],
[]: 0
}
},
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM],
[]: [ATOM],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
retried: Infinity,
[]: KEYWORDS.LESS_THAN,
[]: 2,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.GREATHER_THAN,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.GREATHER_THAN_OR_EQUAL,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.LESS_THAN_OR_EQUAL,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
},
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_NUMBER],
[]: [ATOM, SPECIAL_NUMBER],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.AND,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [],
[]: 0
}
},
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.OR,
retried: Infinity,
[]: 2,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [],
[]: 0
}
},
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [ATOM, SPECIAL_BOOLEAN],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.IS_ATOM,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ANY],
[]: [ANY],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
},
[]: {
[]: {
[]: [APPLY],
[]: KEYWORDS.IS_LAMBDA,
retried: Infinity,
[]: 1,
[]: [
{
[]: {
retried: Infinity,
[]: PLACEHOLDER,
[]: [ANY],
[]: [ANY],
[]: [],
[]: 0
}
}
],
[]: [ATOM, SPECIAL_BOOLEAN]
}
}
}
export const formatSubType = (T) => {
switch (T[0]) {
case COLLECTION:
return `${
isSubType(T[1])
? T[1].has(COLLECTION)
? `${toTypeNamesAnyToUknown(T[1].types.at(-1))}${'[]'.repeat(
T[1].types.length - 1
)}`
: toTypeNamesAnyToUknown(T[1].types[0]) || toTypeNames(UNKNOWN)
: toTypeNames(UNKNOWN)
}[]`
case ATOM:
return `${
isSubType(T[1])
? toTypeNamesAnyToUknown(T[1].types[0])
: toTypeNamesAnyToUknown(NUMBER)
}`
default:
return toTypeNamesAnyToUknown(T[0])
}
}
export const formatType = (name, env) => {
const stats = env[name][STATS]
const isAnonymous = typeof name === 'number'
return stats
? getType(stats) === APPLY
? `${isAnonymous ? '' : `(${STATIC_TYPES.DEFINE_TYPE} ${name} `}(lambda ${
stats[ARG_COUNT] === VARIADIC
? '... '
: stats[ARGUMENTS]?.length
? stats[ARGUMENTS].map(
(x, i) =>
`${
getType(x[STATS]) === APPLY
? `${formatType(i, stats[ARGUMENTS])}`
: `${formatSubType(getTypes(x[STATS]))}`
}`
).join(' ') + ' '
: ''
// TODO format returned functions when type support is added
}(${KEYWORDS.BLOCK} ${formatSubType(getReturns(stats))})${
isAnonymous ? '' : ')'
})`
: `(${STATIC_TYPES.DEFINE_TYPE} ${name} ${formatSubType(
getTypes(stats)
)})`
: name
}
export const formatInlineType = (name, env) => {
const stats = env[name][STATS]
return stats
? getType(stats) === APPLY
? `(lambda ${
stats[ARG_COUNT] === VARIADIC
? '... '
: stats[ARGUMENTS]?.length
? stats[ARGUMENTS].map(
(x, i) =>
`${
getType(x[STATS]) === APPLY
? `${formatType(i, stats[ARGUMENTS])}`
: `${formatSubType(getTypes(x[STATS]))}`
}`
).join(' ') + ' '
: ''
// TODO format returned functions when type support is added
}(${KEYWORDS.BLOCK} ${formatSubType(getReturns(stats))}))`
: formatSubType(getTypes(stats))
: name
}
export const formatAstSubType = (T) => {
switch (T[0]) {
case COLLECTION:
return `${
isSubType(T[1])
? [...T[1]]
.map((x) =>
x === COLLECTION
? formatAstSubType([x])
: toTypeNamesAnyToUknown(x)
)
.join(' ') || toTypeNames(UNKNOWN)
: toTypeNames(UNKNOWN)
}[]`
case ATOM:
return `${
isSubType(T[1])
? [...T[1]].map((x) => toTypeNamesAnyToUknown(x)).join(' ')
: toTypeNamesAnyToUknown(NUMBER)
}`
default:
return toTypeNamesAnyToUknown(T[0])
}
}
export const formatAstTypes = (name, env) => {
const stats = env[name][STATS]
return stats
? getType(stats) === APPLY
? [
FLAG,
...(stats[ARG_COUNT] === VARIADIC
? []
: stats[ARGUMENTS]?.length
? stats[ARGUMENTS].map((x, i) =>
getType(x[STATS]) === APPLY
? formatAstTypes(i, stats[ARGUMENTS])
: formatAstSubType(getTypes(x[STATS]))
)
: []),
formatAstSubType(getReturns(stats))
]
: [FLAG, formatAstSubType(getTypes(stats))]
: [FLAG, name]
}
export const validateLambda = (exp, name) => {
if (exp.length === 1)
throw new TypeError(
`Incorrect number of arguments for (${
KEYWORDS.ANONYMOUS_FUNCTION
}). Expected at least 1 (the lambda body) but got 1 (${stringifyArgs(
exp
)})`
)
if (name)
for (let i = 0; i < exp.length - 1; ++i)
if (exp[i][VALUE] === name)
throw new TypeError(
`Arguments of (${
KEYWORDS.ANONYMOUS_FUNCTION
}) Should not have the same name as they were declared (${stringifyArgs(
exp
)})`
)
}
export const lambdaType = (t) => [t.slice(1, -1), t.at(-1)[1]]
export const toArgType = (A, i) => {
const out = []
const arg = isLeaf(A) ? A : A[0]
if (arg[TYPE] === APPLY) {
const [args, returns] = lambdaType(A)
out.push({
[]: {
argIndex: i,
retried: Infinity,
[]: true,
[]: PLACEHOLDER,
[]: [APPLY],
[]: PLACEHOLDER,
[]: returns[VALUE].replaceAll('[', '').replaceAll(']', ''),
[]: toTypeCodes(returns[VALUE], i),
[]: args.map(toArgType).flat(1),
[]: args.length
}
})
} else {
out.push({
[]: {
argIndex: i,
retried: Infinity,
[]: true,
[]: PLACEHOLDER,
[]: arg[VALUE].replaceAll('[', '').replaceAll(']', ''),
[]: toTypeCodes(arg[VALUE], i),
[]: toTypeCodes(arg[VALUE], i),
[]: [],
[]: 0
}
})
}
return out
}
export const fromSourceToType = (T) => {
const out = {}
for (const t of T) {
const name = t[1][VALUE]
const [args, returns] = lambdaType(t[2])
out[name] = {
[]: {
retried: Infinity,
[]: [APPLY],
[]: name,
[]: name,
[]: returns[VALUE].replaceAll('[', '').replaceAll(']', ''),
[]: args.length,
[]: args.map(toArgType).flat(1),
[]: toTypeCodes(
returns[VALUE],
args.findIndex(
(x) =>
!Array.isArray(x[VALUE]) &&
x[VALUE] ===
returns[VALUE].replaceAll('[', '').replaceAll(']', '')
)
)
}
}
}
return out
}
export const withCtxTypes = (T) => ({ ...SPECIAL_FORM_TYPES, ...T })
export const filteredDefinedTypes = (program, lib, libT) => {
const deps = new Set(shakedList(program, lib))
return libT.filter((x) => deps.has(x[1][1]))
}
export const definedTypes = (T) => fromSourceToType(T)
export const withStdDefinedTypes = (ast) =>
withCtxTypes(definedTypes(filteredDefinedTypes(ast, std, stdT)))
export const extractTypes = (source) => {
let types = ''
const src = source.replaceAll(/\(the.+\)/g, (match, token) => {
types += match + '\n'
return ''
})
return [src, types]
}