This project converts Scala 3 TASTy (.tasty) files into Morphir IR JSON (distribution format 3).
It uses the Scala 3 scala3-tasty-inspector API to read compiled Scala trees and emits a VersionedDistribution JSON suitable for Morphir-based analysis.
- Morphir JVM: https://github.com/finos/morphir-jvm
- Morphir Elm CLI: https://github.com/finos/morphir-elm
- Scala 3 TASTy Inspector docs: https://docs.scala-lang.org/scala3/reference/metaprogramming/tasty-inspect.html
- JDK
21 sbt1.12.5- Scala
3.3.7(managed by SBT) morphir-elmCLI available onPATH
sbt compileMain entrypoint:
morphir.codegen.tasty.tastyToMorphirIR
Examples:
# Convert one .tasty file
sbt "runMain morphir.codegen.tasty.tastyToMorphirIR /tmp/output.json /path/to/File.tasty"
# Convert multiple related .tasty files together
sbt "runMain morphir.codegen.tasty.tastyToMorphirIR /tmp/output.json /path/to/One.tasty /path/to/Two.tasty"Arguments:
- Output path for the generated Morphir IR JSON
- One or more compiled Scala 3
.tastyfiles
examples/CurrentSupportedExample.scalashows the most complex concise Scala shape currently supported end-to-end.- Keep this example updated as translation support expands so it remains the quick reference for current capabilities.
BooleanIntLong(currently mapped to Morphirint)FloatDouble(mapped to Morphirfloat)CharStringBigDecimalOption[T]List[T]for the current narrow empty-list, directList(...)literal, nested-list literal, and directlengthslices- narrow Scala
enumcustom types, including direct constructor payloads up to the current two-argument slice - Scala tuples, currently the direct
(A, B)value/type slice - Scala
case classdata fields, including generic multi-parameter and nested record references
- literals, including
Boolean,Long,Char, and directStringliterals - arithmetic operators:
+,-,*,/ - boolean operators:
&&,|| - comparison operators:
<,<=,>,>= - function application
if / else- pattern matching for
Optionconstructors and supported scalar literal patterns, includingFloat - constructor references, direct constructor application, and direct constructor pattern matches for the current narrow
enumslice, including flat three-argument constructors - tuple literals and tuple-typed pass-through values
- narrow tuple destructuring in
matchexpressions for tuple element capture, including flat 4-tuples - narrow tuple destructuring in local
valbindings for direct tuple element capture, including flat 4-tuples - local
valbindings and block expressions - case-class field access, including nested record access
- narrow case-class methods defined directly on case classes, including the current two-explicit-parameter slice and richer supported
if-based method bodies - empty list values via
List()andNil - populated list values via
List(...) - nested list literals such as
List(List(1, 2), List(3)) - direct
List.length
Int /maps to MorphirintegerDivideBigDecimalarithmetic and comparison map to Morphir decimal SDK functions- Scala
BigDecimal /maps tomorphir.SDK.decimal.div.unsafe - Scala
Longcurrently maps to Morphirint - Scala
Doublemaps to Morphirfloat - Scala
Charmaps to Morphirchar - Scala
List[T]maps to Morphirmorphir.SDK.list.list[T] - Scala
List.lengthmaps to Morphirmorphir.SDK.list.length - Scala
TupleNmaps to Morphir tuple types and tuple values - Scala case classes are emitted as Morphir
type aliasrecords - narrow case-class methods are emitted as module values with an explicit record receiver input, including the current two-explicit-parameter slice
- narrow Scala
enumfamilies are emitted as Morphir custom types - generic case-class fields preserve declared type-parameter order and substitute concrete nested type arguments during field access
The converter can merge multiple related .tasty files into one Morphir distribution.
For inputs from related Scala namespaces such as:
a.ba.b.c
the converter:
- computes the longest common package prefix as the output Morphir package
- moves the remaining namespace suffix into module paths
- rebases user-defined type and value references to that common package root
Unrelated package roots still fail fast.
This is the current ordered plan for the next 5 supportable tastyToMorphirIR features.
Keep this section updated as the roadmap changes.
- Broader user-defined ADTs
Build on the new flat three-argument enum-constructor slice by adding richer constructor families only where full Elm parity remains exact. - Broader literal widening
Build on the new float-literal-pattern parity slice only where the Morphir target type stays explicit and exact Elm parity remains stable. - Broader collections support
Build on the new direct-List.lengthparity slice by adding more collection operations only where exact Elm parity remains stable. - Broader case-class methods
Build on the new two-explicit-parameter conditional-method slice by adding slightly richer method shapes only where full Elm parity remains exact. - Broader tuple destructuring
Build on the new flat 4-tuple match and local-valparity slices by adding richer tuple-pattern shapes only where exact Elm parity stays stable.
The repository has a fixture-driven MUnit test suite under src/test/scala/morphir/codegen/tasty/.
The baseline is always the JSON generated from equivalent Elm source using morphir-elm make -f.
Main suites:
SupportedFunctionEquivalenceTestCaseClassEquivalenceTestCaseClassFieldAccessEquivalenceTestMixedNamespaceMultiTastyTest
sbt test
sbt "testOnly morphir.codegen.tasty.SupportedFunctionEquivalenceTest"
sbt "testOnly morphir.codegen.tasty.CaseClassEquivalenceTest"
sbt "testOnly morphir.codegen.tasty.CaseClassFieldAccessEquivalenceTest"
sbt "testOnly morphir.codegen.tasty.MixedNamespaceMultiTastyTest"Both test and testOnly automatically:
- compile the Scala fixtures in
test-fixtures/scala/ - generate Elm baseline IR in each fixture project under
test-fixtures/elm/
Fixture inputs live in:
test-fixtures/scala/for Scala sources compiled to.tastytest-fixtures/elm/for Elm projects compiled tomorphir-ir.json
The tests compare full generated JSON distributions directly, so Scala and Elm namespaces are intentionally aligned.
src/main/scala/morphir/codegen/tasty/TastyToMorphir.scala- entrypoint and multi-file merge logicsrc/main/scala/morphir/codegen/tasty/TreeMorph.scala- package-level conversion to Morphir distributionssrc/main/scala/morphir/codegen/tasty/TypeDefMorph.scala- object and case-class module extractionsrc/main/scala/morphir/codegen/tasty/DefDefMorph.scala- method definition conversionsrc/main/scala/morphir/codegen/tasty/ApplyMorph.scala- function application conversionsrc/main/scala/morphir/codegen/tasty/IdentMorph.scala- identifier and FQName conversionsrc/main/scala/morphir/codegen/tasty/SelectMorph.scala- selection and field-access conversionsrc/main/scala/morphir/codegen/tasty/IfMorph.scala-if / elseconversionsrc/main/scala/morphir/codegen/tasty/TreeResolver.scala- shared type resolutionsrc/main/scala/morphir/codegen/tasty/StandardTypes.scala- Scala-to-Morphir type mappingssrc/main/scala/morphir/codegen/tasty/StandardFunctions.scala- Scala operator/function mappings
- support is intentionally narrow and fail-fast
- generic case classes are supported for the current narrow slice, including multi-parameter data-only records and nested record references
- user-defined ADTs are currently limited to Scala
enumcases with the current direct-constructor slice up to three constructor arguments - additional literal widening currently covers
Long,Char, directStringliterals, andFloatliteral patterns; other scalar literal expansions remain unsupported - collection support is currently limited to
List[T]types plus directList(...)literals, nested-list literals, and empty-list values (List()andNil) - case-class methods are currently limited to direct methods on the case class plus at most two explicit parameters, with supported bodies staying within the current expression surface
- tuple destructuring is currently limited to narrow flat tuple-match and local-
valslices up to the current 4-tuple coverage; broader tuple patterns are still unsupported - many Scala constructs are still unsupported, including broader ADT families, collection operations, and richer tuple or case-method shapes
sbt cleanThis removes normal build output as well as generated Elm fixture IR files used by the test suite.