From c79fbbc593186c475ef6bdc66e890539a8acfb5b Mon Sep 17 00:00:00 2001 From: chai2010 Date: Mon, 24 Jul 2023 20:19:25 +0800 Subject: [PATCH] =?UTF-8?q?wa=20=E5=91=BD=E4=BB=A4=E8=B0=83=E6=95=B4?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/app/appast/appast.go | 25 ++ internal/app/appbuild/appbuild.go | 87 ++++++ internal/app/appcir/appcir.go | 24 ++ internal/app/appdev/appdev.go | 32 +++ internal/app/appdoc/cmd.go | 17 ++ internal/app/appfmt/appfmt.go | 14 + internal/app/appinit/appinit.go | 34 +++ internal/app/applex/applex.go | 20 ++ internal/app/appllvm/appllvm.go | 57 ++++ internal/app/applogo/applogo.go | 18 ++ internal/app/applsp/cmd.go | 23 ++ internal/app/appplay/play.go | 23 ++ internal/app/apprun/apprun.go | 21 ++ internal/app/appssa/appssa.go | 22 ++ internal/app/apptest/apptest.go | 27 ++ internal/app/appyacc/cmd.go | 58 ++++ internal/app/main.go | 463 ++---------------------------- internal/config/all_flags.go | 2 + internal/config/config.go | 1 + 19 files changed, 529 insertions(+), 439 deletions(-) create mode 100644 internal/app/appdev/appdev.go create mode 100644 internal/app/appdoc/cmd.go create mode 100644 internal/app/applsp/cmd.go create mode 100644 internal/app/appyacc/cmd.go diff --git a/internal/app/appast/appast.go b/internal/app/appast/appast.go index 8a49cdb..5016146 100644 --- a/internal/app/appast/appast.go +++ b/internal/app/appast/appast.go @@ -1,11 +1,36 @@ +// 版权 @2023 凹语言 作者。保留所有权利。 + package appast import ( + "fmt" + "os" + + "wa-lang.org/wa/internal/3rdparty/cli" "wa-lang.org/wa/internal/ast" "wa-lang.org/wa/internal/parser" "wa-lang.org/wa/internal/token" ) +var CmdAst = &cli.Command{ + Hidden: true, + Name: "ast", + Usage: "parse Wa source code and print ast", + Action: func(c *cli.Context) error { + if c.NArg() == 0 { + fmt.Fprintf(os.Stderr, "no input file") + os.Exit(1) + } + + err := PrintAST(c.Args().First()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return nil + }, +} + func PrintAST(filename string) error { fset := token.NewFileSet() // positions are relative to fset f, err := parser.ParseFile(nil, fset, filename, nil, 0) diff --git a/internal/app/appbuild/appbuild.go b/internal/app/appbuild/appbuild.go index 8fd0e44..2b0f385 100644 --- a/internal/app/appbuild/appbuild.go +++ b/internal/app/appbuild/appbuild.go @@ -5,12 +5,99 @@ package appbuild import ( "fmt" "os" + "strings" + "wa-lang.org/wa/internal/3rdparty/cli" "wa-lang.org/wa/internal/app/appbase" "wa-lang.org/wa/internal/backends/compiler_wat" + "wa-lang.org/wa/internal/config" "wa-lang.org/wa/internal/loader" + "wa-lang.org/wa/internal/wabt" ) +var CmdBuild = &cli.Command{ + Name: "build", + Usage: "compile Wa source code", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "output", + Aliases: []string{"o"}, + Usage: "set output file", + Value: "", + }, + &cli.StringFlag{ + Name: "target", + Usage: fmt.Sprintf("set target os (%s)", strings.Join(config.WaOS_List, "|")), + Value: config.WaOS_Default, + }, + &cli.StringFlag{ + Name: "tags", + Usage: "set build tags", + }, + &cli.IntFlag{ + Name: "ld-stack-size", + Usage: "set stack size", + }, + &cli.IntFlag{ + Name: "ld-max-memory", + Usage: "set max memory size", + }, + }, + Action: func(c *cli.Context) error { + var input string + if c.NArg() > 0 { + input = c.Args().First() + } else { + input, _ = os.Getwd() + } + + outfile := c.String("output") + if outfile == "" { + if fi, _ := os.Lstat(input); fi != nil && fi.IsDir() { + // /xxx/yyy/ => /xxx/yyy/output/yyy.wat + } else { + // /xxx/yyy/zzz.wa => /xxx/yyy/zzz.wat + } + outfile = "a.out.wasm" + } + + opt := appbase.BuildOptions(c) + watOutput, err := Build(opt, input) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + if outfile != "" && outfile != "-" { + watFilename := outfile + if !strings.HasSuffix(watFilename, ".wat") { + watFilename += ".wat" + } + err := os.WriteFile(watFilename, []byte(watOutput), 0666) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + if strings.HasSuffix(outfile, ".wasm") { + wasmBytes, err := wabt.Wat2Wasm(watOutput) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + if err := os.WriteFile(outfile, wasmBytes, 0666); err != nil { + fmt.Println(err) + os.Exit(1) + } + os.Remove(watFilename) + } + } else { + fmt.Println(string(watOutput)) + } + + return nil + }, +} + func Build(opt *appbase.Option, filename string) ([]byte, error) { if _, err := os.Lstat(filename); err != nil { return nil, fmt.Errorf("%q not found", filename) diff --git a/internal/app/appcir/appcir.go b/internal/app/appcir/appcir.go index 5268570..f52af1a 100644 --- a/internal/app/appcir/appcir.go +++ b/internal/app/appcir/appcir.go @@ -1,13 +1,37 @@ +// 版权 @2023 凹语言 作者。保留所有权利。 + package appcir import ( "fmt" + "os" + "wa-lang.org/wa/internal/3rdparty/cli" "wa-lang.org/wa/internal/app/appbase" "wa-lang.org/wa/internal/backends/compiler_c" "wa-lang.org/wa/internal/loader" ) +var CmdCir = &cli.Command{ + Hidden: true, + Name: "cir", + Usage: "print cir code", + Action: func(c *cli.Context) error { + if c.NArg() == 0 { + fmt.Fprintf(os.Stderr, "no input file") + os.Exit(1) + } + + opt := appbase.BuildOptions(c) + err := PrintCIR(opt, c.Args().First()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return nil + }, +} + func PrintCIR(opt *appbase.Option, filename string) error { cfg := opt.Config() prog, err := loader.LoadProgram(cfg, filename) diff --git a/internal/app/appdev/appdev.go b/internal/app/appdev/appdev.go new file mode 100644 index 0000000..644478d --- /dev/null +++ b/internal/app/appdev/appdev.go @@ -0,0 +1,32 @@ +package appdev + +import ( + "fmt" + "os" + + "wa-lang.org/wa/api" + "wa-lang.org/wa/internal/3rdparty/cli" + "wa-lang.org/wa/internal/config" +) + +var CmdDev = &cli.Command{ + // go run main.go debug + Hidden: true, + Name: "debug", + Usage: "only for dev/debug", + Action: func(c *cli.Context) error { + wat, err := api.BuildFile( + config.DefaultConfig(), + "hello.wa", "func main() { println(123) }", + ) + if err != nil { + if len(wat) != 0 { + fmt.Println(string(wat)) + } + fmt.Println(err) + os.Exit(1) + } + fmt.Println(string(wat)) + return nil + }, +} diff --git a/internal/app/appdoc/cmd.go b/internal/app/appdoc/cmd.go new file mode 100644 index 0000000..c9d0a1a --- /dev/null +++ b/internal/app/appdoc/cmd.go @@ -0,0 +1,17 @@ +package appdoc + +import ( + "fmt" + + "wa-lang.org/wa/internal/3rdparty/cli" +) + +var CmdDoc = &cli.Command{ + Hidden: true, + Name: "doc", + Usage: "show documentation for package or symbol", + Action: func(c *cli.Context) error { + fmt.Println("TODO") + return nil + }, +} diff --git a/internal/app/appfmt/appfmt.go b/internal/app/appfmt/appfmt.go index 261225c..d40c023 100644 --- a/internal/app/appfmt/appfmt.go +++ b/internal/app/appfmt/appfmt.go @@ -9,9 +9,23 @@ import ( "sort" "strings" + "wa-lang.org/wa/internal/3rdparty/cli" "wa-lang.org/wa/internal/format" ) +var CmdFmt = &cli.Command{ + Name: "fmt", + Usage: "format Wa source code file", + Action: func(c *cli.Context) error { + err := Fmt(c.Args().First()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return nil + }, +} + func Fmt(path string) error { if path == "" { if _, err := os.Lstat("wa.mod.json"); err == nil { diff --git a/internal/app/appinit/appinit.go b/internal/app/appinit/appinit.go index a2004a3..91a2a04 100644 --- a/internal/app/appinit/appinit.go +++ b/internal/app/appinit/appinit.go @@ -12,9 +12,43 @@ import ( "time" "unicode" + "wa-lang.org/wa/internal/3rdparty/cli" "wa-lang.org/wa/waroot" ) +var CmdInit = &cli.Command{ + Name: "init", + Usage: "init a sketch Wa module", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "name", + Aliases: []string{"n"}, + Usage: "set app name", + Value: "hello", + }, + &cli.StringFlag{ + Name: "pkgpath", + Aliases: []string{"p"}, + Usage: "set pkgpath file", + Value: "myapp", + }, + &cli.BoolFlag{ + Name: "update", + Aliases: []string{"u"}, + Usage: "update example", + }, + }, + + Action: func(c *cli.Context) error { + err := InitApp(c.String("name"), c.String("pkgpath"), c.Bool("update")) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return nil + }, +} + func InitApp(name, pkgpath string, update bool) error { if name == "" { return fmt.Errorf("init failed: <%s> is empty", name) diff --git a/internal/app/applex/applex.go b/internal/app/applex/applex.go index 7e9ebd8..a0da996 100644 --- a/internal/app/applex/applex.go +++ b/internal/app/applex/applex.go @@ -9,10 +9,30 @@ import ( "io" "os" + "wa-lang.org/wa/internal/3rdparty/cli" "wa-lang.org/wa/internal/scanner" "wa-lang.org/wa/internal/token" ) +var CmdLex = &cli.Command{ + Hidden: true, + Name: "lex", + Usage: "lex Wa source code and print token list", + Action: func(c *cli.Context) error { + if c.NArg() == 0 { + fmt.Fprintf(os.Stderr, "no input file") + os.Exit(1) + } + + err := Lex(c.Args().First()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return nil + }, +} + func Lex(filename string) error { src, err := readSource(filename, nil) if err != nil { diff --git a/internal/app/appllvm/appllvm.go b/internal/app/appllvm/appllvm.go index 30a33e9..b1ba901 100644 --- a/internal/app/appllvm/appllvm.go +++ b/internal/app/appllvm/appllvm.go @@ -9,11 +9,68 @@ import ( "path" "strings" + "wa-lang.org/wa/internal/3rdparty/cli" "wa-lang.org/wa/internal/app/appbase" "wa-lang.org/wa/internal/backends/compiler_llvm" + "wa-lang.org/wa/internal/config" "wa-lang.org/wa/internal/loader" ) +var CmdNative = &cli.Command{ + Hidden: true, + Name: "native", + Usage: "compile Wa source code to native executable", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "output", + Aliases: []string{"o"}, + Usage: "set output file", + Value: "", + }, + &cli.StringFlag{ + Name: "target", + Usage: "set native target", + Value: "", + }, + &cli.StringFlag{ + Name: "tags", + Usage: "set build tags", + }, + &cli.BoolFlag{ + Name: "debug", + Usage: "dump orginal intermediate representation", + }, + &cli.StringFlag{ + Name: "clang", + Usage: "set llvm/clang path", + }, + &cli.StringFlag{ + Name: "llc", + Usage: "set llvm/llc path", + }, + }, + Action: func(c *cli.Context) error { + outfile := c.String("output") + target := c.String("target") + debug := c.Bool("debug") + infile := "" + + if c.NArg() == 0 { + fmt.Fprintf(os.Stderr, "no input file") + os.Exit(1) + } + infile = c.Args().First() + + opt := appbase.BuildOptions(c, config.WaBackend_llvm) + if err := LLVMRun(opt, infile, outfile, target, debug); err != nil { + fmt.Println(err) + os.Exit(1) + } + + return nil + }, +} + func LLVMRun(opt *appbase.Option, infile string, outfile string, target string, debug bool) error { cfg := opt.Config() diff --git a/internal/app/applogo/applogo.go b/internal/app/applogo/applogo.go index 21e2bf4..5bdb1b7 100644 --- a/internal/app/applogo/applogo.go +++ b/internal/app/applogo/applogo.go @@ -1,3 +1,21 @@ // 版权 @2023 凹语言 作者。保留所有权利。 package applogo + +import "wa-lang.org/wa/internal/3rdparty/cli" + +var CmdLogo = &cli.Command{ + Name: "logo", + Usage: "print Wa text format logo", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "more", + Aliases: []string{"m"}, + Usage: "print more logos", + }, + }, + Action: func(c *cli.Context) error { + PrintLogo(c.Bool("more")) + return nil + }, +} diff --git a/internal/app/applsp/cmd.go b/internal/app/applsp/cmd.go new file mode 100644 index 0000000..abc80ff --- /dev/null +++ b/internal/app/applsp/cmd.go @@ -0,0 +1,23 @@ +package applsp + +import ( + "wa-lang.org/wa/internal/3rdparty/cli" + "wa-lang.org/wa/internal/lsp" +) + +var CmdLsp = &cli.Command{ + Hidden: true, + Name: "lsp", + Usage: "run Wa langugage server", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "log-file", + Usage: "set log file", + Value: "", + }, + }, + Action: func(c *cli.Context) error { + lsp.NewLSPServer(&lsp.Option{}).Run() + return nil + }, +} diff --git a/internal/app/appplay/play.go b/internal/app/appplay/play.go index 3e69b3f..590bdd5 100644 --- a/internal/app/appplay/play.go +++ b/internal/app/appplay/play.go @@ -4,12 +4,35 @@ package appplay import ( "fmt" + "os" "os/exec" "runtime" "strings" "time" + + "wa-lang.org/wa/internal/3rdparty/cli" ) +var CmdPlay = &cli.Command{ + Name: "play", + Usage: "start Wa playground", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "http", + Value: ":2023", + Usage: "set http address", + }, + }, + Action: func(c *cli.Context) error { + err := RunPlayground(c.String("http")) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return nil + }, +} + func RunPlayground(addr string) error { if strings.HasPrefix(addr, ":") { addr = "localhost" + addr diff --git a/internal/app/apprun/apprun.go b/internal/app/apprun/apprun.go index ce5fbe6..570e571 100644 --- a/internal/app/apprun/apprun.go +++ b/internal/app/apprun/apprun.go @@ -10,10 +10,31 @@ import ( "wa-lang.org/wa/internal/3rdparty/cli" "wa-lang.org/wa/internal/app/appbase" "wa-lang.org/wa/internal/app/appbuild" + "wa-lang.org/wa/internal/config" "wa-lang.org/wa/internal/wabt" "wa-lang.org/wa/internal/wazero" ) +var CmdRun = &cli.Command{ + Name: "run", + Usage: "compile and run Wa program", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "target", + Usage: fmt.Sprintf("set target os (%s)", strings.Join(config.WaOS_List, "|")), + Value: config.WaOS_Default, + }, + &cli.StringFlag{ + Name: "tags", + Usage: "set build tags", + }, + }, + Action: func(c *cli.Context) error { + Run(c) + return nil + }, +} + func Run(c *cli.Context) { var infile string if c.NArg() > 0 { diff --git a/internal/app/appssa/appssa.go b/internal/app/appssa/appssa.go index 5a6113c..80bd7bf 100644 --- a/internal/app/appssa/appssa.go +++ b/internal/app/appssa/appssa.go @@ -3,14 +3,36 @@ package appssa import ( + "fmt" "os" "sort" + "wa-lang.org/wa/internal/3rdparty/cli" "wa-lang.org/wa/internal/app/appbase" "wa-lang.org/wa/internal/loader" "wa-lang.org/wa/internal/ssa" ) +var CmdSsa = &cli.Command{ + Hidden: true, + Name: "ssa", + Usage: "print Wa ssa code", + Action: func(c *cli.Context) error { + if c.NArg() == 0 { + fmt.Fprintf(os.Stderr, "no input file") + os.Exit(1) + } + + opt := appbase.BuildOptions(c) + err := SSARun(opt, c.Args().First()) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + return nil + }, +} + func SSARun(opt *appbase.Option, filename string) error { cfg := opt.Config() prog, err := loader.LoadProgram(cfg, filename) diff --git a/internal/app/apptest/apptest.go b/internal/app/apptest/apptest.go index 6dd09ce..7f4e534 100644 --- a/internal/app/apptest/apptest.go +++ b/internal/app/apptest/apptest.go @@ -9,6 +9,8 @@ import ( "strings" "time" + "wa-lang.org/wa/internal/3rdparty/cli" + "wa-lang.org/wa/internal/app/appbase" "wa-lang.org/wa/internal/backends/compiler_wat" "wa-lang.org/wa/internal/config" "wa-lang.org/wa/internal/loader" @@ -17,6 +19,31 @@ import ( "wa-lang.org/wa/waroot" ) +var CmdTest = &cli.Command{ + Name: "test", + Usage: "test Wa packages", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: "target", + Usage: fmt.Sprintf("set target os (%s)", strings.Join(config.WaOS_List, "|")), + Value: config.WaOS_Default, + }, + &cli.StringFlag{ + Name: "tags", + Usage: "set build tags", + }, + }, + Action: func(c *cli.Context) error { + if c.NArg() < 1 { + cli.ShowAppHelpAndExit(c, 0) + } + appArgs := c.Args().Slice()[1:] + opt := appbase.BuildOptions(c) + RunTest(opt.Config(), c.Args().First(), appArgs...) + return nil + }, +} + func RunTest(cfg *config.Config, pkgpath string, appArgs ...string) { var pkgList = []string{pkgpath} if pkgpath == "std" { diff --git a/internal/app/appyacc/cmd.go b/internal/app/appyacc/cmd.go new file mode 100644 index 0000000..db058f8 --- /dev/null +++ b/internal/app/appyacc/cmd.go @@ -0,0 +1,58 @@ +package appyacc + +import ( + "os" + + "wa-lang.org/wa/internal/3rdparty/cli" +) + +var CmdYacc = &cli.Command{ + Name: "yacc", + Usage: "generates parsers for LALR(1) grammars", + ArgsUsage: "", + Flags: []cli.Flag{ + &cli.BoolFlag{ + Name: "l", + Usage: "disable line directives", + }, + &cli.StringFlag{ + Name: "o", + Usage: "set parser output file", + Value: "y.wa", + }, + &cli.StringFlag{ + Name: "p", + Usage: "name prefix to use in generated code", + Value: "yy", + }, + &cli.StringFlag{ + Name: "v", + Usage: "create parsing tables", + Value: "y.output", + }, + &cli.StringFlag{ + Name: "c", + Usage: "set copyright file", + Value: "", + }, + }, + Action: func(c *cli.Context) error { + if c.NArg() != 1 { + cli.ShowSubcommandHelpAndExit(c, 1) + } + InitFlags(Flags{ + Oflag: c.String("o"), + Vflag: c.String("v"), + Lflag: c.Bool("l"), + Prefix: c.String("p"), + Copyright: loadCopyright(c.String("c")), + }) + Main(c.Args().First()) + return nil + }, +} + +func loadCopyright(filename string) string { + data, _ := os.ReadFile(filename) + return string(data) +} diff --git a/internal/app/main.go b/internal/app/main.go index 4e29f70..171d4b9 100644 --- a/internal/app/main.go +++ b/internal/app/main.go @@ -7,29 +7,26 @@ package app import ( - "fmt" "os" - "strings" - "wa-lang.org/wa/api" "wa-lang.org/wa/internal/3rdparty/cli" "wa-lang.org/wa/internal/app/appast" - "wa-lang.org/wa/internal/app/appbase" "wa-lang.org/wa/internal/app/appbuild" "wa-lang.org/wa/internal/app/appcir" + "wa-lang.org/wa/internal/app/appdev" + "wa-lang.org/wa/internal/app/appdoc" "wa-lang.org/wa/internal/app/appfmt" "wa-lang.org/wa/internal/app/appinit" "wa-lang.org/wa/internal/app/applex" "wa-lang.org/wa/internal/app/appllvm" "wa-lang.org/wa/internal/app/applogo" + "wa-lang.org/wa/internal/app/applsp" "wa-lang.org/wa/internal/app/appplay" "wa-lang.org/wa/internal/app/apprun" "wa-lang.org/wa/internal/app/appssa" "wa-lang.org/wa/internal/app/apptest" "wa-lang.org/wa/internal/app/appyacc" "wa-lang.org/wa/internal/config" - "wa-lang.org/wa/internal/lsp" - "wa-lang.org/wa/internal/wabt" "wa-lang.org/wa/waroot" ) @@ -40,6 +37,7 @@ func Main() { cliApp.Copyright = "Copyright 2018 The Wa Authors. All rights reserved." cliApp.Version = waroot.GetVersion() cliApp.EnableBashCompletion = true + cliApp.HideHelpCommand = true cliApp.CustomAppHelpTemplate = cli.AppHelpTemplate + "\nSee \"https://wa-lang.org\" for more information.\n" @@ -74,443 +72,30 @@ func Main() { } cliApp.Commands = []*cli.Command{ - { - // go run main.go debug - Hidden: true, - Name: "debug", - Usage: "only for dev/debug", - Action: func(c *cli.Context) error { - wat, err := api.BuildFile( - config.DefaultConfig(), - "hello.wa", "func main() { println(123) }", - ) - if err != nil { - if len(wat) != 0 { - fmt.Println(string(wat)) - } - fmt.Println(err) - os.Exit(1) - } - fmt.Println(string(wat)) - return nil - }, - }, + // 用于调试(隐藏) + appdev.CmdDev, - { - Name: "play", - Usage: "start Wa playground", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "http", - Value: ":2023", - Usage: "set http address", - }, - }, - Action: func(c *cli.Context) error { - err := appplay.RunPlayground(c.String("http")) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - return nil - }, - }, + // 用户可见子命令 + appplay.CmdPlay, + appinit.CmdInit, + appbuild.CmdBuild, + apprun.CmdRun, + appfmt.CmdFmt, + apptest.CmdTest, + appyacc.CmdYacc, + applogo.CmdLogo, - { - Name: "init", - Usage: "init a sketch Wa module", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "name", - Aliases: []string{"n"}, - Usage: "set app name", - Value: "hello", - }, - &cli.StringFlag{ - Name: "pkgpath", - Aliases: []string{"p"}, - Usage: "set pkgpath file", - Value: "myapp", - }, - &cli.BoolFlag{ - Name: "update", - Aliases: []string{"u"}, - Usage: "update example", - }, - }, + // 开发者用于测试(隐藏) + applex.CmdLex, + appast.CmdAst, + appssa.CmdSsa, - Action: func(c *cli.Context) error { - err := appinit.InitApp(c.String("name"), c.String("pkgpath"), c.Bool("update")) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - return nil - }, - }, - { - Name: "build", - Usage: "compile Wa source code", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "output", - Aliases: []string{"o"}, - Usage: "set output file", - Value: "", - }, - &cli.StringFlag{ - Name: "target", - Usage: fmt.Sprintf("set target os (%s)", strings.Join(config.WaOS_List, "|")), - Value: config.WaOS_Default, - }, - &cli.StringFlag{ - Name: "tags", - Usage: "set build tags", - }, - &cli.IntFlag{ - Name: "ld-stack-size", - Usage: "set stack size", - }, - &cli.IntFlag{ - Name: "ld-max-memory", - Usage: "set max memory size", - }, - }, - Action: func(c *cli.Context) error { - var input string - if c.NArg() > 0 { - input = c.Args().First() - } else { - input, _ = os.Getwd() - } - - outfile := c.String("output") - if outfile == "" { - if fi, _ := os.Lstat(input); fi != nil && fi.IsDir() { - // /xxx/yyy/ => /xxx/yyy/output/yyy.wat - } else { - // /xxx/yyy/zzz.wa => /xxx/yyy/zzz.wat - } - outfile = "a.out.wasm" - } - - opt := appbase.BuildOptions(c) - watOutput, err := appbuild.Build(opt, input) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - - if outfile != "" && outfile != "-" { - watFilename := outfile - if !strings.HasSuffix(watFilename, ".wat") { - watFilename += ".wat" - } - err := os.WriteFile(watFilename, []byte(watOutput), 0666) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - if strings.HasSuffix(outfile, ".wasm") { - wasmBytes, err := wabt.Wat2Wasm(watOutput) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - if err := os.WriteFile(outfile, wasmBytes, 0666); err != nil { - fmt.Println(err) - os.Exit(1) - } - os.Remove(watFilename) - } - } else { - fmt.Println(string(watOutput)) - } - - return nil - }, - }, - { - Name: "run", - Usage: "compile and run Wa program", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "target", - Usage: fmt.Sprintf("set target os (%s)", strings.Join(config.WaOS_List, "|")), - Value: config.WaOS_Default, - }, - &cli.StringFlag{ - Name: "tags", - Usage: "set build tags", - }, - }, - Action: func(c *cli.Context) error { - apprun.Run(c) - return nil - }, - }, - { - Name: "fmt", - Usage: "format Wa source code file", - Action: func(c *cli.Context) error { - err := appfmt.Fmt(c.Args().First()) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - return nil - }, - }, - - { - Name: "test", - Usage: "test Wa packages", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "target", - Usage: fmt.Sprintf("set target os (%s)", strings.Join(config.WaOS_List, "|")), - Value: config.WaOS_Default, - }, - &cli.StringFlag{ - Name: "tags", - Usage: "set build tags", - }, - }, - Action: func(c *cli.Context) error { - if c.NArg() < 1 { - cli.ShowAppHelpAndExit(c, 0) - } - appArgs := c.Args().Slice()[1:] - opt := appbase.BuildOptions(c) - apptest.RunTest(opt.Config(), c.Args().First(), appArgs...) - return nil - }, - }, - - { - Hidden: true, - Name: "native", - Usage: "compile Wa source code to native executable", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "output", - Aliases: []string{"o"}, - Usage: "set output file", - Value: "", - }, - &cli.StringFlag{ - Name: "target", - Usage: "set native target", - Value: "", - }, - &cli.StringFlag{ - Name: "tags", - Usage: "set build tags", - }, - &cli.BoolFlag{ - Name: "debug", - Usage: "dump orginal intermediate representation", - }, - &cli.StringFlag{ - Name: "clang", - Usage: "set llvm/clang path", - }, - &cli.StringFlag{ - Name: "llc", - Usage: "set llvm/llc path", - }, - }, - Action: func(c *cli.Context) error { - outfile := c.String("output") - target := c.String("target") - debug := c.Bool("debug") - infile := "" - - if c.NArg() == 0 { - fmt.Fprintf(os.Stderr, "no input file") - os.Exit(1) - } - infile = c.Args().First() - - opt := appbase.BuildOptions(c, config.WaBackend_llvm) - if err := appllvm.LLVMRun(opt, infile, outfile, target, debug); err != nil { - fmt.Println(err) - os.Exit(1) - } - - return nil - }, - }, - - { - Hidden: true, - Name: "lex", - Usage: "lex Wa source code and print token list", - Action: func(c *cli.Context) error { - if c.NArg() == 0 { - fmt.Fprintf(os.Stderr, "no input file") - os.Exit(1) - } - - err := applex.Lex(c.Args().First()) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - return nil - }, - }, - { - Hidden: true, - Name: "ast", - Usage: "parse Wa source code and print ast", - Action: func(c *cli.Context) error { - if c.NArg() == 0 { - fmt.Fprintf(os.Stderr, "no input file") - os.Exit(1) - } - - err := appast.PrintAST(c.Args().First()) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - return nil - }, - }, - { - Hidden: true, - Name: "ssa", - Usage: "print Wa ssa code", - Action: func(c *cli.Context) error { - if c.NArg() == 0 { - fmt.Fprintf(os.Stderr, "no input file") - os.Exit(1) - } - - opt := appbase.BuildOptions(c) - err := appssa.SSARun(opt, c.Args().First()) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - return nil - }, - }, - { - Hidden: true, - Name: "cir", - Usage: "print cir code", - Action: func(c *cli.Context) error { - if c.NArg() == 0 { - fmt.Fprintf(os.Stderr, "no input file") - os.Exit(1) - } - - opt := appbase.BuildOptions(c) - err := appcir.PrintCIR(opt, c.Args().First()) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - return nil - }, - }, - - { - Hidden: true, - Name: "doc", - Usage: "show documentation for package or symbol", - Action: func(c *cli.Context) error { - fmt.Println("TODO") - return nil - }, - }, - - { - Name: "yacc", - Usage: "generates parsers for LALR(1) grammars", - ArgsUsage: "", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "l", - Usage: "disable line directives", - }, - &cli.StringFlag{ - Name: "o", - Usage: "set parser output file", - Value: "y.wa", - }, - &cli.StringFlag{ - Name: "p", - Usage: "name prefix to use in generated code", - Value: "yy", - }, - &cli.StringFlag{ - Name: "v", - Usage: "create parsing tables", - Value: "y.output", - }, - &cli.StringFlag{ - Name: "c", - Usage: "set copyright file", - Value: "", - }, - }, - Action: func(c *cli.Context) error { - if c.NArg() != 1 { - cli.ShowSubcommandHelpAndExit(c, 1) - } - appyacc.InitFlags(appyacc.Flags{ - Oflag: c.String("o"), - Vflag: c.String("v"), - Lflag: c.Bool("l"), - Prefix: c.String("p"), - Copyright: loadCopyright(c.String("c")), - }) - appyacc.Main(c.Args().First()) - return nil - }, - }, - - { - Hidden: true, - Name: "lsp", - Usage: "run Wa langugage server", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "log-file", - Usage: "set log file", - Value: "", - }, - }, - Action: func(c *cli.Context) error { - lsp.NewLSPServer(&lsp.Option{}).Run() - return nil - }, - }, - - { - Name: "logo", - Usage: "print Wa text format logo", - Flags: []cli.Flag{ - &cli.BoolFlag{ - Name: "more", - Aliases: []string{"m"}, - Usage: "print more logos", - }, - }, - Action: func(c *cli.Context) error { - applogo.PrintLogo(c.Bool("more")) - return nil - }, - }, + // 待完善的子命令(隐藏) + appllvm.CmdNative, + appcir.CmdCir, + appdoc.CmdDoc, + applsp.CmdLsp, } cliApp.Run(os.Args) } - -func loadCopyright(filename string) string { - data, _ := os.ReadFile(filename) - return string(data) -} diff --git a/internal/config/all_flags.go b/internal/config/all_flags.go index d73e48b..704b65a 100644 --- a/internal/config/all_flags.go +++ b/internal/config/all_flags.go @@ -43,5 +43,7 @@ func setEnableTrace(parten string) { EnableTrace_app = true EnableTrace_compiler = true EnableTrace_loader = true + default: + panic("unknown trace flag: " + parten) } } diff --git a/internal/config/config.go b/internal/config/config.go index df05667..1520587 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -22,6 +22,7 @@ type PkgVFS struct { // 通用配置信息 type Config struct { + WatOutput string // 输出的 wat 文件路径 WaBackend string // 编译器后端 WaRoot string // 凹 程序根目录, src 目录下是包代码, 为空时用内置标准库实现 WaArch string // 目标 CPU