Skip to content

Commit

Permalink
Merge pull request #1147 from cogentcore/cosh
Browse files Browse the repository at this point in the history
updates to cosh and cli to support cogent author, including cosh transpile command
  • Loading branch information
kkoreilly authored Aug 19, 2024
2 parents ef520c7 + 2e003f4 commit be2a0d3
Show file tree
Hide file tree
Showing 7 changed files with 69 additions and 22 deletions.
29 changes: 18 additions & 11 deletions shell/cmd/cosh/cosh.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,6 @@ type Config struct {
// unless the Interactive mode is flagged.
Input string `posarg:"0" required:"-"`

// Output is the Go file to output the transpiled input file to,
// as an optional second argument for the build command.
// It defaults to the input file with .cosh changed to .go.
Output string `cmd:"build" posarg:"1" required:"-"`

// Expr is an optional expression to evaluate, which can be used
// in addition to the Input file to run, to execute commands
// defined within that file for example, or as a command to run
Expand Down Expand Up @@ -104,13 +99,25 @@ func Interactive(c *Config, in *interpreter.Interpreter) error {
return nil
}

// Build builds the specified input cosh file to the specified output Go file.
// Build builds the specified input cosh file, or all .cosh files in the current
// directory if no input is specified, to corresponding .go file name(s).
// If the file does not already contain a "package" specification, then
// "package main; func main()..." wrappers are added, which allows the same
// code to be used in interactive and Go compiled modes.
func Build(c *Config) error {
if c.Input == "" {
return fmt.Errorf("need input file")
var fns []string
if c.Input != "" {
fns = []string{c.Input}
} else {
fns = fsx.Filenames(".", ".cosh")
}
if c.Output == "" {
c.Output = strings.TrimSuffix(c.Input, filepath.Ext(c.Input)) + ".go"
var errs []error
for _, fn := range fns {
ofn := strings.TrimSuffix(fn, filepath.Ext(fn)) + ".go"
err := shell.NewShell().TranspileFile(fn, ofn)
if err != nil {
errs = append(errs, err)
}
}
return shell.NewShell().TranspileFile(c.Input, c.Output)
return errors.Join(errs...)
}
1 change: 1 addition & 0 deletions shell/cmd/cosh/test.cosh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// test file for cosh cli

// todo: doesn't work: #1152
echo {args}

for i, fn := range cosh.SplitLines(`/bin/ls -1`) {
Expand Down
4 changes: 2 additions & 2 deletions shell/cmd/cosh/typegen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

44 changes: 38 additions & 6 deletions shell/shell.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"cogentcore.org/core/base/reflectx"
"cogentcore.org/core/base/sshclient"
"cogentcore.org/core/base/stack"
"cogentcore.org/core/base/stringsx"
"github.com/mitchellh/go-homedir"
"golang.org/x/tools/imports"
)
Expand Down Expand Up @@ -94,6 +95,13 @@ type Shell struct {
// and saved / restored from ~/.coshhist file
Hist []string

// FuncToVar translates function definitions into variable definitions,
// which is the default for interactive use of random code fragments
// without the complete go formatting.
// For pure transpiling of a complete codebase with full proper Go formatting
// this should be turned off.
FuncToVar bool

// commandArgs is a stack of args passed to a command, used for simplified
// processing of args expressions.
commandArgs stack.Stack[[]string]
Expand All @@ -116,6 +124,7 @@ func NewShell() *Shell {
Buffer: false,
},
}
sh.FuncToVar = true
sh.Config.StdIO.SetFromOS()
sh.SSH = sshclient.NewConfig(&sh.Config)
sh.SSHClients = make(map[string]*sshclient.Client)
Expand Down Expand Up @@ -315,17 +324,40 @@ func (sh *Shell) TranspileCodeFromFile(file string) error {
return nil
}

// TranspileFile transpiles the given input cosh file to the given output Go file,
// adding package main and func main declarations.
// TranspileFile transpiles the given input cosh file to the
// given output Go file. If no existing package declaration
// is found, then package main and func main declarations are
// added. This also affects how functions are interpreted.
func (sh *Shell) TranspileFile(in string, out string) error {
err := sh.TranspileCodeFromFile(in)
b, err := os.ReadFile(in)
if err != nil {
return err
}
code := string(b)
lns := stringsx.SplitLines(code)
hasPackage := false
for _, ln := range lns {
if strings.HasPrefix(ln, "package ") {
hasPackage = true
break
}
}
if hasPackage {
sh.FuncToVar = false // use raw functions
}
sh.TranspileCode(code)
sh.FuncToVar = true
if err != nil {
return err
}
sh.Lines = slices.Insert(sh.Lines, 0, "package main", "", "func main() {", "shell := shell.NewShell()")
sh.Lines = append(sh.Lines, "}")
gen := "// Code generated by \"cosh build\"; DO NOT EDIT.\n\n"
if hasPackage {
sh.Lines = slices.Insert(sh.Lines, 0, gen)
} else {
sh.Lines = slices.Insert(sh.Lines, 0, gen, "package main", "", "func main() {", "shell := shell.NewShell()")
sh.Lines = append(sh.Lines, "}")
}
src := []byte(sh.Code())
// fmt.Println(string(src))
res, err := imports.Process(out, src, nil)
if err != nil {
res = src
Expand Down
10 changes: 8 additions & 2 deletions shell/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,9 +173,15 @@ func (tk Tokens) Code() string {
str += " "
}
str += tok.String()
prvIdent = false
prvIdent = true
case tok.IsGo():
str += tok.String() + " "
if prvIdent {
str += " "
}
str += tok.String()
if tok.Tok != token.MAP {
str += " "
}
prvIdent = false
case tok.Tok == token.IDENT || tok.Tok == token.STRING:
if prvIdent {
Expand Down
2 changes: 1 addition & 1 deletion shell/transpile.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func (sh *Shell) TranspileGo(toks Tokens) Tokens {
if n == 0 {
return toks
}
if toks[0].Tok == token.FUNC { // reorder as an assignment
if sh.FuncToVar && toks[0].Tok == token.FUNC { // reorder as an assignment
if len(toks) > 1 && toks[1].Tok == token.IDENT {
toks[0] = toks[1]
toks.Insert(1, token.DEFINE)
Expand Down
1 change: 1 addition & 0 deletions shell/transpile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ func TestTranspile(t *testing.T) {
{"ctr++", "ctr++"},
{"stru.ctr++", "stru.ctr++"},
{"meta += ln", "meta += ln"},
{"var data map[string]any", "var data map[string]any"},
}

sh := NewShell()
Expand Down

0 comments on commit be2a0d3

Please sign in to comment.