@informalsystems/quint
Version:
Core tool for the Quint specification language
145 lines (128 loc) • 4 kB
text/typescript
import { describe, it } from 'mocha'
import { assert } from 'chai'
import { parseType } from '../../src/types/parser'
describe('parseType', () => {
it('parses tuple of literal types', () => {
const type = parseType('(bool, int, str)')
assert.isTrue(type.isRight())
type.map(value =>
assert.deepEqual(value, {
kind: 'tup',
fields: {
kind: 'row',
fields: [
{ fieldName: '0', fieldType: { kind: 'bool', id: 1n } },
{ fieldName: '1', fieldType: { kind: 'int', id: 2n } },
{ fieldName: '2', fieldType: { kind: 'str', id: 3n } },
],
other: { kind: 'empty' },
},
id: 4n,
})
)
})
it('parses operator with type vars', () => {
const type = parseType('(a, b) => ((a) => b)')
assert.isTrue(type.isRight())
type.map(value =>
assert.deepEqual(value, {
kind: 'oper',
args: [
{ kind: 'var', name: 'a', id: 1n },
{ kind: 'var', name: 'b', id: 2n },
],
res: {
kind: 'oper',
args: [{ kind: 'var', name: 'a', id: 3n }],
res: { kind: 'var', name: 'b', id: 4n },
id: 5n,
},
id: 6n,
})
)
})
// Regression test for https://github.com/informalsystems/quint/issues/1336
it('parses qualified type constants', () => {
const type = parseType('modname::TypeConstructor')
assert.isTrue(type.isRight())
type.map(value => {
assert(value.kind === 'const')
assert.deepEqual(value.name, 'modname::TypeConstructor')
})
})
it('parses function of const types', () => {
const type = parseType('T1 -> (T2 -> T1)')
assert.isTrue(type.isRight())
type.map(value =>
assert.deepEqual(value, {
kind: 'fun',
arg: { kind: 'const', name: 'T1', id: 1n },
res: {
kind: 'fun',
arg: { kind: 'const', name: 'T2', id: 2n },
res: { kind: 'const', name: 'T1', id: 3n },
id: 4n,
},
id: 5n,
})
)
})
it('parses records of sets and lists', () => {
const type = parseType('{ mySet: Set[a], mySeq: List[a] | r }')
assert.isTrue(type.isRight())
type.map(value =>
assert.deepEqual(value, {
kind: 'rec',
fields: {
kind: 'row',
fields: [
{ fieldName: 'mySet', fieldType: { kind: 'set', elem: { kind: 'var', name: 'a', id: 1n }, id: 2n } },
{ fieldName: 'mySeq', fieldType: { kind: 'list', elem: { kind: 'var', name: 'a', id: 3n }, id: 4n } },
],
other: { kind: 'var', name: 'r' },
},
id: 5n,
})
)
})
it('parses type application', () => {
const type = parseType('Foo[int, bool, str]')
assert.isTrue(type.isRight())
type.map(value =>
assert.deepEqual(value, {
kind: 'app',
ctor: { kind: 'const', name: 'Foo', id: 5n },
args: [
{ kind: 'int', id: 1n },
{ kind: 'bool', id: 2n },
{ kind: 'str', id: 3n },
],
id: 4n,
})
)
})
it('throws error when type is invalid', () => {
const type = parseType('Set(int, bool)')
assert.isTrue(type.isLeft())
type.mapLeft(error =>
assert.deepEqual(
error[0].explanation,
'[QNT009] Use square brackets instead of parenthesis for type application: Set[int, bool]'
)
)
})
it('throws error when row separators are invalid', () => {
const type = parseType('{ f1: int, | r }')
assert.isTrue(type.isLeft())
type.mapLeft(error =>
assert.sameDeepMembers(error, [
{
// TODO We should not expect a '=>' here,
// but do because of https://github.com/informalsystems/quint/issues/456
explanation: "mismatched input '|' expecting '}'",
locs: [{ start: { line: 0, col: 11, index: 11 }, end: { line: 0, col: 11, index: 11 } }],
},
])
)
})
})