diff --git a/README.md b/README.md index a5fea1b..abc62b2 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ![release](https://img.shields.io/github/v/release/melvic-ybanez/chi?include_prereleases) ![issues](https://img.shields.io/github/issues/melvic-ybanez/chi) ![loc](https://img.shields.io/tokei/lines/github/melvic-ybanez/chi) [![License](https://img.shields.io/badge/license-MIT-green)](./LICENSE) -A code generator for fully parametric functions. +A code generator for fully parametric functions and functions between selected set of built-in and standard types. Chi stands for [Curry-Howard Isomorphism](https://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspondence). @@ -150,3 +150,23 @@ Generated code: }; } ``` + +# Built-in types +Chi also recognize built-in types: +```scala +chi> String idString(String s) +Detected language: Java +Generated code: +String idString(String s) { + return s; +} + +chi> def foo(f: String => Int, g: Float => Int): Either[String, Float] => Int +Detected language: Scala +Generated code: +def foo(f: (String => Int), g: (Float => Int)): (Either[String, Float] => Int) = + e => e match { + case Left(s) => f(s) + case Right(h) => g(h) + } +``` diff --git a/src/main/scala/com/melvic/chi/eval/CodeGen.scala b/src/main/scala/com/melvic/chi/eval/Generate.scala similarity index 82% rename from src/main/scala/com/melvic/chi/eval/CodeGen.scala rename to src/main/scala/com/melvic/chi/eval/Generate.scala index 61800a1..94656ee 100644 --- a/src/main/scala/com/melvic/chi/eval/CodeGen.scala +++ b/src/main/scala/com/melvic/chi/eval/Generate.scala @@ -1,6 +1,6 @@ package com.melvic.chi.eval -import com.melvic.chi.ast.Proposition.{Identifier, PUnit} +import com.melvic.chi.ast.Proposition.{Atom, Identifier, PUnit} import com.melvic.chi.ast.{Definition, Proposition, Signature} import com.melvic.chi.env.Env import com.melvic.chi.out.Fault.UnknownPropositions @@ -8,14 +8,14 @@ import com.melvic.chi.out.Result import com.melvic.chi.out.Result.Result import com.melvic.chi.parsers.{JavaParser, Language, ScalaParser} -object CodeGen { +object Generate { def fromSignature(signature: Signature, language: Language): Result[Definition] = { val Signature(name, typeParams, params, proposition) = signature val unknownTypes = Proposition.filter(proposition) { case PUnit => false - case atom => - !typeParams.map(Identifier).contains(atom) + case atom @ Atom(value) => + !typeParams.map(Identifier).contains(atom) && !Language.builtInTypes(language).contains(value) } if (unknownTypes.nonEmpty) Result.fail(UnknownPropositions(unknownTypes)) diff --git a/src/main/scala/com/melvic/chi/eval/package.scala b/src/main/scala/com/melvic/chi/eval/package.scala index 0d0af0b..7fccd9e 100644 --- a/src/main/scala/com/melvic/chi/eval/package.scala +++ b/src/main/scala/com/melvic/chi/eval/package.scala @@ -6,5 +6,5 @@ package object eval { type Evaluate = String => String def generateAndShow: Evaluate = code => - Result.show(CodeGen.fromSignatureString(code)) + Result.show(Generate.fromSignatureString(code)) } diff --git a/src/main/scala/com/melvic/chi/package.scala b/src/main/scala/com/melvic/chi/package.scala index 4e618d9..ee99f74 100644 --- a/src/main/scala/com/melvic/chi/package.scala +++ b/src/main/scala/com/melvic/chi/package.scala @@ -1,6 +1,6 @@ package com.melvic -import com.melvic.chi.eval.{CodeGen, Prover} +import com.melvic.chi.eval.{Generate, Prover} import com.melvic.chi.out.Result package object chi { diff --git a/src/main/scala/com/melvic/chi/parsers/JavaParser.scala b/src/main/scala/com/melvic/chi/parsers/JavaParser.scala index 8992b91..8a0d53c 100644 --- a/src/main/scala/com/melvic/chi/parsers/JavaParser.scala +++ b/src/main/scala/com/melvic/chi/parsers/JavaParser.scala @@ -27,8 +27,8 @@ object JavaParser extends BaseParser { lazy val proposition: PackratParser[Proposition] = function | biFunction | identifier val functionCode: Parser[Signature] = - typeParams ~ proposition ~ nameParser ~ opt(paramList) ^^ { + opt(typeParams) ~ proposition ~ nameParser ~ opt(paramList) ^^ { case typeParams ~ returnType ~ name ~ params => - Signature(name, typeParams.map(_.value), params.getOrElse(Nil), returnType) + Signature(name, typeParams.getOrElse(Nil).map(_.value), params.getOrElse(Nil), returnType) } } diff --git a/src/main/scala/com/melvic/chi/parsers/Language.scala b/src/main/scala/com/melvic/chi/parsers/Language.scala index 85171e5..8ff630f 100644 --- a/src/main/scala/com/melvic/chi/parsers/Language.scala +++ b/src/main/scala/com/melvic/chi/parsers/Language.scala @@ -5,4 +5,15 @@ sealed trait Language object Language { case object Java extends Language case object Scala extends Language + + def builtInTypes(language: Language): List[String] = { + val builtinTypeString = language match { + case Scala => "Char,Byte,Short,Int,Long,Float,Double,String" + case Java => + val primitive = "byte,short,int,long,float,double,boolean,char" + val boxed = "Byte,Boolean,Char,Float,Int,Long,Short,Double,String" + primitive + boxed + } + builtinTypeString.split(",").toList + } } diff --git a/src/test/scala/com/melvic/chi/tests/JavaFunctionsSpec.scala b/src/test/scala/com/melvic/chi/tests/JavaFunctionsSpec.scala index b4010e1..efa8e5a 100644 --- a/src/test/scala/com/melvic/chi/tests/JavaFunctionsSpec.scala +++ b/src/test/scala/com/melvic/chi/tests/JavaFunctionsSpec.scala @@ -36,4 +36,14 @@ class JavaFunctionsSpec extends AnyFlatSpec with should.Matchers { |}""".stripMargin ) } + + "Built-in types" should "be included in the type search" in { + generateAndShow("String idString(String s)") should be( + """Detected language: Java + |Generated code: + |String idString(String s) { + | return s; + |}""".stripMargin + ) + } } diff --git a/src/test/scala/com/melvic/chi/tests/ScalaDefSpec.scala b/src/test/scala/com/melvic/chi/tests/ScalaDefSpec.scala index 62f4604..5f9940e 100644 --- a/src/test/scala/com/melvic/chi/tests/ScalaDefSpec.scala +++ b/src/test/scala/com/melvic/chi/tests/ScalaDefSpec.scala @@ -196,4 +196,16 @@ class ScalaDefSpec extends AnyFlatSpec with should.Matchers { | }""".stripMargin ) } + + "Built-in types" should "be included in the type search" in { + generateAndShow("def foo(f: String => Int, g: Float => Int): Either[String, Float] => Int") should be( + """Detected language: Scala + |Generated code: + |def foo(f: (String => Int), g: (Float => Int)): (Either[String, Float] => Int) = + | e => e match { + | case Left(s) => f(s) + | case Right(h) => g(h) + | }""".stripMargin + ) + } }