diff --git a/package-lock.json b/package-lock.json index 4f9f497b..e831b82b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "@helios-lang/compiler", - "version": "0.17.0-37", + "version": "0.17.0-43", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@helios-lang/compiler", - "version": "0.17.0-37", + "version": "0.17.0-43", "license": "BSD-3-Clause", "dependencies": { "@helios-lang/codec-utils": "^0.1.32", "@helios-lang/compiler-utils": "^0.1.53", "@helios-lang/ir": "^0.1.26", - "@helios-lang/type-utils": "^0.1.20", + "@helios-lang/type-utils": "^0.1.21", "@helios-lang/uplc": "^0.1.35" }, "devDependencies": { @@ -64,9 +64,9 @@ } }, "node_modules/@helios-lang/type-utils": { - "version": "0.1.20", - "resolved": "https://registry.npmjs.org/@helios-lang/type-utils/-/type-utils-0.1.20.tgz", - "integrity": "sha512-WBxslD8hBeMmiNTN8Uaj0IxNZIu5yT94qzW+KrK6cw/WlFXMfGWB7/wSa5eH2UL4k/wadI1psvGurygJc5Ebxw==" + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/@helios-lang/type-utils/-/type-utils-0.1.21.tgz", + "integrity": "sha512-z12O84kEwVzqYmcYL+SWCaZNIkmF4cDvKFOtL3KiR6pwl8KngqiQk8MnBEyG06FUMKxCSknWayPGIYzM2HcqBw==" }, "node_modules/@helios-lang/uplc": { "version": "0.1.36", @@ -168,9 +168,9 @@ } }, "@helios-lang/type-utils": { - "version": "0.1.20", - "resolved": "https://registry.npmjs.org/@helios-lang/type-utils/-/type-utils-0.1.20.tgz", - "integrity": "sha512-WBxslD8hBeMmiNTN8Uaj0IxNZIu5yT94qzW+KrK6cw/WlFXMfGWB7/wSa5eH2UL4k/wadI1psvGurygJc5Ebxw==" + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/@helios-lang/type-utils/-/type-utils-0.1.21.tgz", + "integrity": "sha512-z12O84kEwVzqYmcYL+SWCaZNIkmF4cDvKFOtL3KiR6pwl8KngqiQk8MnBEyG06FUMKxCSknWayPGIYzM2HcqBw==" }, "@helios-lang/uplc": { "version": "0.1.36", diff --git a/package.json b/package.json index 80668961..a4d78665 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@helios-lang/compiler", - "version": "0.17.0-43", + "version": "0.17.0-44", "description": "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 build 100% client-side dApps for Cardano.", "main": "src/index.js", "types": "types/index.d.ts", @@ -54,7 +54,7 @@ "@helios-lang/codec-utils": "^0.1.32", "@helios-lang/compiler-utils": "^0.1.53", "@helios-lang/ir": "^0.1.26", - "@helios-lang/type-utils": "^0.1.20", + "@helios-lang/type-utils": "^0.1.21", "@helios-lang/uplc": "^0.1.35" } } diff --git a/src/program/DatumRedeemerEntryPoint.js b/src/program/DatumRedeemerEntryPoint.js index 9ad92a8a..a53fe7e8 100644 --- a/src/program/DatumRedeemerEntryPoint.js +++ b/src/program/DatumRedeemerEntryPoint.js @@ -9,7 +9,7 @@ import { None } from "@helios-lang/type-utils" import { UplcProgramV2 } from "@helios-lang/uplc" import { TAB, ToIRContext } from "../codegen/index.js" import { GlobalScope } from "../scopes/index.js" -import { BoolType, DefaultTypeClass } from "../typecheck/index.js" +import { BoolType, isDataType } from "../typecheck/index.js" import { EntryPointImpl } from "./EntryPoint.js" import { ModuleCollection } from "./ModuleCollection.js" @@ -102,10 +102,7 @@ export class DatumRedeemerEntryPoint extends EntryPointImpl { } for (let i = 0; i < nArgs; i++) { - if ( - argTypeNames[i] != "" && - !new DefaultTypeClass().isImplementedBy(argTypes[i]) - ) { + if (argTypeNames[i] != "" && !isDataType(argTypes[i])) { throw CompilerError.type( main.site, `illegal type for arg ${i + 1} in main ${i == nArgs - 2 ? "(datum) " : i == nArgs - 3 ? "(redeemer) " : ""}: '${argTypes[i].toString()}` diff --git a/src/program/GenericEntryPoint.js b/src/program/GenericEntryPoint.js index 4044561c..981a29b8 100644 --- a/src/program/GenericEntryPoint.js +++ b/src/program/GenericEntryPoint.js @@ -3,7 +3,7 @@ import { $, SourceMappedString } from "@helios-lang/ir" import { None, expectSome } from "@helios-lang/type-utils" import { TAB, ToIRContext } from "../codegen/index.js" import { GlobalScope } from "../scopes/index.js" -import { DefaultTypeClass } from "../typecheck/index.js" +import { isDataType } from "../typecheck/index.js" import { EntryPointImpl } from "./EntryPoint.js" import { ModuleCollection } from "./ModuleCollection.js" @@ -60,10 +60,7 @@ export class GenericEntryPoint extends EntryPointImpl { const retType = main.retType argTypeNames.forEach((argTypeName, i) => { - if ( - argTypeName != "" && - !new DefaultTypeClass().isImplementedBy(argTypes[i]) - ) { + if (argTypeName != "" && !isDataType(argTypes[i])) { throw CompilerError.type( main.site, `illegal argument type in main: '${argTypes[i].toString()}` @@ -71,8 +68,7 @@ export class GenericEntryPoint extends EntryPointImpl { } }) - // TODO: support tuple return values ? - if (!new DefaultTypeClass().isImplementedBy(retType)) { + if (!isDataType(retType)) { throw CompilerError.type( main.site, `illegal return type for main: '${retType.toString()}'` diff --git a/src/program/Program.js b/src/program/Program.js index 5cf16c28..e3c8ec05 100644 --- a/src/program/Program.js +++ b/src/program/Program.js @@ -1,6 +1,5 @@ -import { ErrorCollector, Source, Word } from "@helios-lang/compiler-utils" +import { ErrorCollector, Source } from "@helios-lang/compiler-utils" import { - $, DEFAULT_PARSE_OPTIONS, SourceMappedString, compile as compileIR @@ -12,10 +11,11 @@ import { FuncStatement, StructStatement } from "../statements/index.js" +import { isDataType } from "../typecheck/index.js" import { newEntryPoint } from "./newEntryPoint.js" import { Module } from "./Module.js" -import { UserFunc } from "./UserFunc.js" import { ModuleCollection } from "./ModuleCollection.js" +import { UserFunc } from "./UserFunc.js" /** * @typedef {import("@helios-lang/compiler-utils").Site} Site @@ -156,8 +156,8 @@ export class Program { // make sure all arg types and return type are compatible and that the function doesn't have any typeparameters if ( - fn.argTypes.every((a) => !!a.asDataType) && - !!fn.retType.asDataType && + fn.argTypes.every((a) => isDataType(a)) && + isDataType(fn.retType) && !fn.typeParameters.hasParameters() ) { const filteredImportedModules = diff --git a/src/program/Program.test.js b/src/program/Program.test.js index 6f9872ac..bfbcce38 100644 --- a/src/program/Program.test.js +++ b/src/program/Program.test.js @@ -1,4 +1,4 @@ -import { strictEqual, throws } from "node:assert" +import { deepEqual, strictEqual, throws } from "node:assert" import { describe, it } from "node:test" import { removeWhitespace } from "@helios-lang/codec-utils" import { Program } from "./Program.js" @@ -190,4 +190,36 @@ describe(Program.name, () => { fn.mainFunc fn.toIR({}) }) + + it("tuple type schema ok", () => { + const src = `testing m + + func my_func() -> (Int, Int) { + (0, 0) + } + + func main() -> Int { + 0 + }` + + const program = new Program(src) + + const fns = program.userFunctions["m"] + + deepEqual(Object.keys(fns), ["my_func", "main"]) + + deepEqual(fns["my_func"].mainFunc.retType.asDataType?.toSchema(), { + kind: "tuple", + itemTypes: [ + { + kind: "internal", + name: "Int" + }, + { + kind: "internal", + name: "Int" + } + ] + }) + }) }) diff --git a/src/program/RedeemerEntryPoint.js b/src/program/RedeemerEntryPoint.js index 9d8b10c6..efdc1c89 100644 --- a/src/program/RedeemerEntryPoint.js +++ b/src/program/RedeemerEntryPoint.js @@ -3,7 +3,7 @@ import { $, SourceMappedString } from "@helios-lang/ir" import { None } from "@helios-lang/type-utils" import { TAB, ToIRContext } from "../codegen/index.js" import { GlobalScope } from "../scopes/index.js" -import { BoolType, DefaultTypeClass } from "../typecheck/index.js" +import { BoolType, isDataType } from "../typecheck/index.js" import { EntryPointImpl } from "./EntryPoint.js" import { ModuleCollection } from "./ModuleCollection.js" @@ -58,10 +58,7 @@ export class RedeemerEntryPoint extends EntryPointImpl { throw CompilerError.type(main.site, "expected 1 arg for main") } - if ( - argTypeNames[0] != "" && - !new DefaultTypeClass().isImplementedBy(argTypes[0]) - ) { + if (argTypeNames[0] != "" && !isDataType(argTypes[0])) { throw CompilerError.type( main.site, `illegal redeemer argument type in main: '${argTypes[0].toString()}` diff --git a/src/program/version.js b/src/program/version.js index fc13b3aa..24de71bd 100644 --- a/src/program/version.js +++ b/src/program/version.js @@ -1 +1 @@ -export const VERSION = "0.17.0-43" +export const VERSION = "0.17.0-44" diff --git a/src/typecheck/containers.js b/src/typecheck/containers.js index e8c92c0e..6a666c7c 100644 --- a/src/typecheck/containers.js +++ b/src/typecheck/containers.js @@ -271,9 +271,26 @@ export function TupleType$(itemTypes, isAllDataTypes = null) { return isDataType(it) }) + /** + * @type {GenericTypeProps} + */ const props = { name: `(${itemTypes.map((it) => it.toString()).join(", ")})`, path: `__helios__tuple[${itemTypes.map((it) => (it.asDataType ? it.asDataType.path : "__helios__func")).join("@")}]`, + genTypeSchema: (self) => { + if (isData) { + return { + kind: "tuple", + itemTypes: itemTypes.map((it) => + expectSome(it.asDataType).toSchema() + ) + } + } else { + throw new Error( + `TypeSchema not available for ${self.toString()}` + ) + } + }, genInstanceMembers: (self) => { const members = isData ? genCommonInstanceMembers(self) : {}