2023-07-13 16:14:38 +02:00
package cli
import (
"fmt"
"log"
"os"
"path/filepath"
"time"
C "github.com/urfave/cli/v2"
)
2023-07-17 13:55:35 +02:00
func eitherHKT ( typeE string ) func ( typeA string ) string {
return func ( typeA string ) string {
return fmt . Sprintf ( "Either[%s, %s]" , typeE , typeA )
}
}
func generateEitherTraverseTuple ( f * os . File , i int ) {
generateTraverseTuple1 ( eitherHKT ( "E" ) , "E" ) ( f , i )
}
func generateEitherSequenceTuple ( f * os . File , i int ) {
generateSequenceTuple1 ( eitherHKT ( "E" ) , "E" ) ( f , i )
}
func generateEitherSequenceT ( f * os . File , i int ) {
2023-07-17 18:03:21 +02:00
generateSequenceT1 ( eitherHKT ( "E" ) , "E" ) ( f , i )
2023-07-17 13:55:35 +02:00
}
2023-07-13 16:14:38 +02:00
func generateUneitherize ( f * os . File , i int ) {
// Create the optionize version
2023-07-13 17:34:13 +02:00
fmt . Fprintf ( f , "\n// Uneitherize%d converts a function with %d parameters returning an Either into a function with %d parameters returning a tuple\n// The inverse function is [Eitherize%d]\n" , i , i , i , i )
2023-07-13 16:14:38 +02:00
fmt . Fprintf ( f , "func Uneitherize%d[F ~func(" , i )
for j := 0 ; j < i ; j ++ {
if j > 0 {
fmt . Fprintf ( f , ", " )
}
fmt . Fprintf ( f , "T%d" , j )
}
fmt . Fprintf ( f , ") Either[error, R]" )
for j := 0 ; j < i ; j ++ {
fmt . Fprintf ( f , ", T%d" , j )
}
fmt . Fprintf ( f , ", R any](f F) func(" )
for j := 0 ; j < i ; j ++ {
if j > 0 {
fmt . Fprintf ( f , ", " )
}
fmt . Fprintf ( f , "T%d" , j )
}
fmt . Fprintf ( f , ") (R, error) {\n" )
fmt . Fprintf ( f , " return func(" )
for j := 0 ; j < i ; j ++ {
if j > 0 {
fmt . Fprintf ( f , ", " )
}
fmt . Fprintf ( f , "t%d T%d" , j , j )
}
fmt . Fprintf ( f , ") (R, error) {\n" )
fmt . Fprintf ( f , " return UnwrapError(f(" )
for j := 0 ; j < i ; j ++ {
if j > 0 {
fmt . Fprintf ( f , ", " )
}
fmt . Fprintf ( f , "t%d" , j )
}
fmt . Fprintln ( f , "))" )
fmt . Fprintln ( f , " }" )
fmt . Fprintln ( f , "}" )
}
func generateEitherize ( f * os . File , i int ) {
// Create the optionize version
2023-07-13 17:34:13 +02:00
fmt . Fprintf ( f , "\n// Eitherize%d converts a function with %d parameters returning a tuple into a function with %d parameters returning an Either\n// The inverse function is [Uneitherize%d]\n" , i , i , i , i )
2023-07-13 16:14:38 +02:00
fmt . Fprintf ( f , "func Eitherize%d[F ~func(" , i )
for j := 0 ; j < i ; j ++ {
if j > 0 {
fmt . Fprintf ( f , ", " )
}
fmt . Fprintf ( f , "T%d" , j )
}
fmt . Fprintf ( f , ") (R, error)" )
for j := 0 ; j < i ; j ++ {
fmt . Fprintf ( f , ", T%d" , j )
}
fmt . Fprintf ( f , ", R any](f F) func(" )
for j := 0 ; j < i ; j ++ {
if j > 0 {
fmt . Fprintf ( f , ", " )
}
fmt . Fprintf ( f , "T%d" , j )
}
fmt . Fprintf ( f , ") Either[error, R] {\n" )
fmt . Fprintf ( f , " return func(" )
for j := 0 ; j < i ; j ++ {
if j > 0 {
fmt . Fprintf ( f , ", " )
}
fmt . Fprintf ( f , "t%d T%d" , j , j )
}
fmt . Fprintf ( f , ") Either[error, R] {\n" )
fmt . Fprintf ( f , " return TryCatchError(func() (R, error) {\n" )
fmt . Fprintf ( f , " return f(" )
for j := 0 ; j < i ; j ++ {
if j > 0 {
fmt . Fprintf ( f , ", " )
}
fmt . Fprintf ( f , "t%d" , j )
}
fmt . Fprintln ( f , ")" )
fmt . Fprintln ( f , " })" )
fmt . Fprintln ( f , " }" )
fmt . Fprintln ( f , "}" )
}
func generateEitherHelpers ( filename string , count int ) error {
dir , err := os . Getwd ( )
if err != nil {
return err
}
absDir , err := filepath . Abs ( dir )
if err != nil {
return err
}
pkg := filepath . Base ( absDir )
2023-07-13 22:24:04 +02:00
f , err := os . Create ( filepath . Clean ( filename ) )
2023-07-13 16:14:38 +02:00
if err != nil {
return err
}
defer f . Close ( )
// log
log . Printf ( "Generating code in [%s] for package [%s] with [%d] repetitions ..." , filename , pkg , count )
// some header
fmt . Fprintln ( f , "// Code generated by go generate; DO NOT EDIT." )
fmt . Fprintln ( f , "// This file was generated by robots at" )
fmt . Fprintf ( f , "// %s\n" , time . Now ( ) )
fmt . Fprintf ( f , "package %s\n\n" , pkg )
2023-07-17 13:55:35 +02:00
fmt . Fprintf ( f , `
import (
2023-07-18 15:57:54 +02:00
A "github.com/IBM/fp-go/internal/apply"
T "github.com/IBM/fp-go/tuple"
2023-07-17 13:55:35 +02:00
)
` )
2023-07-13 16:14:38 +02:00
// zero level functions
// optionize
generateEitherize ( f , 0 )
// unoptionize
generateUneitherize ( f , 0 )
for i := 1 ; i <= count ; i ++ {
// optionize
generateEitherize ( f , i )
// unoptionize
generateUneitherize ( f , i )
2023-07-17 13:55:35 +02:00
// sequenceT
generateEitherSequenceT ( f , i )
// sequenceTuple
generateEitherSequenceTuple ( f , i )
// traverseTuple
generateEitherTraverseTuple ( f , i )
2023-07-13 16:14:38 +02:00
}
return nil
}
func EitherCommand ( ) * C . Command {
return & C . Command {
Name : "either" ,
Usage : "generate code for Either" ,
Flags : [ ] C . Flag {
flagCount ,
flagFilename ,
} ,
Action : func ( ctx * C . Context ) error {
return generateEitherHelpers (
ctx . String ( keyFilename ) ,
ctx . Int ( keyCount ) ,
)
} ,
}
}