Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 16 additions & 2 deletions src/end-to-end.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,18 @@ testCases(endToEnd, code => code)('end-to-end tests', [
],
[':match({ a: A })({ tag: a, value: {} })', either.makeRight('A')],
[':atom.prepend(a)(b)', either.makeRight('ab')],
[`:natural_number.add(1)(1)`, either.makeRight('2')],
[
`:natural_number.add(one)(juan)`,
`{
:atom.equal(hello)(hello)
:atom.equal("")("")
:atom.equal(hello)(Hello)
:atom.equal("1.0")("1.00")
}`,
either.makeRight({ 0: 'true', 1: 'true', 2: 'false', 3: 'false' }),
],
[`:integer.add(1)(1)`, either.makeRight('2')],
[
`:integer.add(one)(juan)`,
output => {
assert(either.isLeft(output))
},
Expand All @@ -236,6 +245,11 @@ testCases(endToEnd, code => code)('end-to-end tests', [
[`1 - 2 - 3`, either.makeRight('-4')],
[`1 - (2 - 3)`, either.makeRight('2')],
[`(1 - 2) - 3`, either.makeRight('-4')],
[`:integer.multiply(2)(2)`, either.makeRight('4')],
[`2 * 2`, either.makeRight('4')],
[`2 * -2`, either.makeRight('-4')],
[`-2 * -2`, either.makeRight('4')],
[`2 * 0`, either.makeRight('0')],
[':flow(:atom.append(b))(:atom.append(a))(z)', either.makeRight('zab')],
[
`@runtime { :object.lookup("key which does not exist in runtime context") }`,
Expand Down
1 change: 1 addition & 0 deletions src/language/semantics/prelude.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export const prelude = makeObjectNode({
'>>': globalFunctions.flow,
'|>': globalFunctions.identity,
'+': integer.add,
'*': integer.multiply,
'-': integer.subtract,
'<': integer.less_than,
'>': integer.greater_than,
Expand Down
35 changes: 35 additions & 0 deletions src/language/semantics/stdlib/atom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,41 @@ export const atom = {
),
),
),
// Note that this is simple string equality; e.g. `:atom.equal(1)(01)`
// is `false`. For this reason it should not be aliased as a global `==`
// operator or similar as its behavior may not be what users expect for all
// types of values.
equal: preludeFunction(
['atom', 'equal'],
{
parameter: types.atom,
return: makeFunctionType('', {
parameter: types.atom,
return: types.boolean,
}),
},
atom2 =>
either.makeRight(
makeFunctionNode(
{
parameter: types.atom,
return: types.atom,
},
serializeOnceAppliedFunction(['atom', 'equal'], atom2),
option.none,
atom1 => {
if (typeof atom2 !== 'string' || typeof atom1 !== 'string') {
return either.makeLeft({
kind: 'panic',
message: 'equal received a non-atom argument',
})
} else {
return either.makeRight(String(atom1 === atom2))
}
},
),
),
),
prepend: preludeFunction(
['atom', 'prepend'],
{
Expand Down
52 changes: 48 additions & 4 deletions src/language/semantics/stdlib/integer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,12 @@ export const integer = {
})
} else {
return either.makeRight(
// TODO: See comment in `natural_number.add`.
// FIXME: It's wasteful to always convert here.
//
// Consider `add(add(1)(1))(1)`—the `2` returned from the inner `add` is
// stringified only to be converted back to a bigint. This is acceptable for the
// prototype, but a real implementation could use a fancier `SemanticGraph` which
// can model atoms as different native data types.
String(BigInt(number1) + BigInt(number2)),
)
}
Expand Down Expand Up @@ -97,7 +102,7 @@ export const integer = {
})
} else {
return either.makeRight(
// TODO: See comment in `natural_number.add`.
// TODO: See comment in `integer.add`.
String(BigInt(number1) > BigInt(number2)),
)
}
Expand Down Expand Up @@ -136,14 +141,53 @@ export const integer = {
})
} else {
return either.makeRight(
// TODO: See comment in `natural_number.add`.
// TODO: See comment in `integer.add`.
String(BigInt(number1) < BigInt(number2)),
)
}
},
),
),
),
multiply: preludeFunction(
['integer', 'multiply'],
{
parameter: types.integer,
return: makeFunctionType('', {
parameter: types.integer,
return: types.integer,
}),
},
number2 =>
either.makeRight(
makeFunctionNode(
{
parameter: types.integer,
return: types.integer,
},
serializeOnceAppliedFunction(['integer', 'multiply'], number2),
option.none,
number1 => {
if (
typeof number1 !== 'string' ||
!types.integer.isAssignableFrom(makeUnionType('', [number1])) ||
typeof number2 !== 'string' ||
!types.integer.isAssignableFrom(makeUnionType('', [number2]))
) {
return either.makeLeft({
kind: 'panic',
message: 'numbers must be atoms',
})
} else {
return either.makeRight(
// TODO: See comment in `integer.add`.
String(BigInt(number1) * BigInt(number2)),
)
}
},
),
),
),
subtract: preludeFunction(
['integer', 'subtract'],
{
Expand Down Expand Up @@ -175,7 +219,7 @@ export const integer = {
})
} else {
return either.makeRight(
// TODO: See comment in `natural_number.add`.
// TODO: See comment in `integer.add`.
String(BigInt(number1) - BigInt(number2)),
)
}
Expand Down
48 changes: 0 additions & 48 deletions src/language/semantics/stdlib/natural-number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,54 +9,6 @@ import {
} from './stdlib-utilities.js'

export const natural_number = {
add: preludeFunction(
['natural_number', 'add'],
{
parameter: types.naturalNumber,
return: makeFunctionType('', {
parameter: types.naturalNumber,
return: types.naturalNumber,
}),
},
number2 =>
either.makeRight(
makeFunctionNode(
{
parameter: types.naturalNumber,
return: types.naturalNumber,
},
serializeOnceAppliedFunction(['natural_number', 'add'], number2),
option.none,
number1 => {
if (
typeof number1 !== 'string' ||
!types.naturalNumber.isAssignableFrom(
makeUnionType('', [number1]),
) ||
typeof number2 !== 'string' ||
!types.naturalNumber.isAssignableFrom(
makeUnionType('', [number2]),
)
) {
return either.makeLeft({
kind: 'panic',
message: 'numbers must be atoms',
})
} else {
return either.makeRight(
// FIXME: It's wasteful to always convert here.
//
// Consider `add(add(1)(1))(1)`—the `2` returned from the inner `add` is
// stringified only to be converted back to a bigint. This is acceptable for the
// prototype, but a real implementation could use a fancier `SemanticGraph` which
// can model atoms as different native data types.
String(BigInt(number1) + BigInt(number2)),
)
}
},
),
),
),
is: preludeFunction(
['natural_number', 'is'],
{
Expand Down