github.com/nevalang/neva@v0.23.1-0.20240507185603-7696a9bb8dda/internal/cli/cli.go (about) 1 package cli 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "os" 8 "path/filepath" 9 "strings" 10 11 cli "github.com/urfave/cli/v2" 12 13 "github.com/nevalang/neva/internal/builder" 14 "github.com/nevalang/neva/internal/compiler" 15 "github.com/nevalang/neva/internal/interpreter" 16 "github.com/nevalang/neva/pkg" 17 ) 18 19 func NewApp( //nolint:funlen 20 workdir string, 21 bldr builder.Builder, 22 goc compiler.Compiler, 23 nativec compiler.Compiler, 24 wasmc compiler.Compiler, 25 jsonc compiler.Compiler, 26 dotc compiler.Compiler, 27 ) *cli.App { 28 var ( 29 target string 30 debug bool 31 ) 32 33 return &cli.App{ 34 Name: "neva", 35 Usage: "Flow-based programming language", 36 Commands: []*cli.Command{ 37 { 38 Name: "version", 39 Usage: "Get current Nevalang version", 40 Action: func(_ *cli.Context) error { 41 fmt.Println(pkg.Version) 42 return nil 43 }, 44 }, 45 { 46 Name: "new", 47 Usage: "Create new Nevalang project", 48 Args: true, 49 Action: func(cCtx *cli.Context) error { 50 if path := cCtx.Args().First(); path != "" { 51 if err := os.Mkdir(path, 0755); err != nil { 52 return err 53 } 54 return createNevaMod(path) 55 } 56 return createNevaMod(workdir) 57 }, 58 }, 59 { 60 Name: "get", 61 Usage: "Add dependency to current module", 62 Args: true, 63 ArgsUsage: "Provide path to the module", 64 Action: func(cCtx *cli.Context) error { 65 installedPath, err := bldr.Get( 66 workdir, 67 cCtx.Args().Get(0), 68 cCtx.Args().Get(1), 69 ) 70 if err != nil { 71 return err 72 } 73 fmt.Printf( 74 "%s installed to %s\n", cCtx.Args().Get(0), 75 installedPath, 76 ) 77 return nil 78 }, 79 }, 80 { 81 Name: "run", 82 Usage: "Run neva program from source code in interpreter mode", 83 Args: true, 84 ArgsUsage: "Provide path to the executable package", 85 Flags: []cli.Flag{ 86 &cli.BoolFlag{ 87 Name: "debug", 88 Usage: "Show message events in stdout", 89 Destination: &debug, 90 }, 91 }, 92 Action: func(cCtx *cli.Context) error { 93 dirFromArg, err := getMainPkgFromArgs(cCtx) 94 if err != nil { 95 return err 96 } 97 intr := interpreter.New(bldr, goc, debug) 98 if err := intr.Interpret( 99 context.Background(), 100 workdir, 101 dirFromArg, 102 ); err != nil { 103 return err 104 } 105 return nil 106 }, 107 }, 108 { 109 Name: "build", 110 Usage: "Build executable binary from neva program source code", 111 Args: true, 112 Flags: []cli.Flag{ 113 &cli.StringFlag{ 114 Name: "target", 115 Required: false, 116 Usage: "Emit Go or WASM instead of machine code", 117 Destination: &target, 118 Action: func(ctx *cli.Context, s string) error { 119 switch s { 120 case "go", "wasm", "native", "json", "dot": 121 default: 122 return fmt.Errorf("Unknown target %s", s) 123 } 124 return nil 125 }, 126 }, 127 }, 128 ArgsUsage: "Provide path to the executable package", 129 Action: func(cCtx *cli.Context) error { 130 dirFromArg, err := getMainPkgFromArgs(cCtx) 131 if err != nil { 132 return err 133 } 134 switch target { 135 case "go": 136 return goc.Compile( 137 workdir, dirFromArg, workdir, 138 ) 139 case "wasm": 140 return wasmc.Compile( 141 workdir, dirFromArg, workdir, 142 ) 143 case "json": 144 return jsonc.Compile( 145 workdir, dirFromArg, workdir, 146 ) 147 case "dot": 148 return dotc.Compile( 149 workdir, dirFromArg, workdir, 150 ) 151 default: 152 return nativec.Compile( 153 workdir, dirFromArg, workdir, 154 ) 155 } 156 }, 157 }, 158 }, 159 } 160 } 161 162 func getMainPkgFromArgs(cCtx *cli.Context) (string, error) { 163 firstArg := cCtx.Args().First() 164 dirFromArg := strings.TrimSuffix(firstArg, "/main.neva") 165 if filepath.Ext(dirFromArg) != "" { 166 return "", errors.New( 167 "Use path to directory with executable package, relative to module root", 168 ) 169 } 170 return dirFromArg, nil 171 } 172 173 func createNevaMod(path string) error { 174 // Create neva.yml file 175 nevaYmlContent := fmt.Sprintf("neva: %s", pkg.Version) 176 if err := os.WriteFile( 177 filepath.Join(path, "neva.yml"), 178 []byte(nevaYmlContent), 179 0644, 180 ); err != nil { 181 return err 182 } 183 184 // Create src sub-directory 185 srcPath := filepath.Join(path, "src") 186 if err := os.Mkdir(srcPath, 0755); err != nil { 187 return err 188 } 189 190 // Create main.neva file 191 mainNevaContent := `component Main(start) (stop) { 192 nodes { Println } 193 net { 194 :start -> ('Hello, World!' -> println -> :stop) 195 } 196 }` 197 198 if err := os.WriteFile( 199 filepath.Join(srcPath, "main.neva"), 200 []byte(mainNevaContent), 201 0644, 202 ); err != nil { 203 return err 204 } 205 206 return nil 207 }