go.starlark.net@v0.0.0-20231101134539-556fd59b42f6/cmd/starlark/starlark.go (about) 1 // Copyright 2017 The Bazel Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // The starlark command interprets a Starlark file. 6 // With no arguments, it starts a read-eval-print loop (REPL). 7 package main // import "go.starlark.net/cmd/starlark" 8 9 import ( 10 "flag" 11 "fmt" 12 "log" 13 "os" 14 "runtime" 15 "runtime/pprof" 16 "strings" 17 18 "go.starlark.net/internal/compile" 19 "go.starlark.net/lib/json" 20 "go.starlark.net/lib/math" 21 "go.starlark.net/lib/time" 22 "go.starlark.net/repl" 23 "go.starlark.net/resolve" 24 "go.starlark.net/starlark" 25 "golang.org/x/term" 26 ) 27 28 // flags 29 var ( 30 cpuprofile = flag.String("cpuprofile", "", "gather Go CPU profile in this file") 31 memprofile = flag.String("memprofile", "", "gather Go memory profile in this file") 32 profile = flag.String("profile", "", "gather Starlark time profile in this file") 33 showenv = flag.Bool("showenv", false, "on success, print final global environment") 34 execprog = flag.String("c", "", "execute program `prog`") 35 ) 36 37 func init() { 38 flag.BoolVar(&compile.Disassemble, "disassemble", compile.Disassemble, "show disassembly during compilation of each function") 39 40 // non-standard dialect flags 41 flag.BoolVar(&resolve.AllowSet, "set", resolve.AllowSet, "allow set data type") 42 flag.BoolVar(&resolve.AllowRecursion, "recursion", resolve.AllowRecursion, "allow while statements and recursive functions") 43 flag.BoolVar(&resolve.AllowGlobalReassign, "globalreassign", resolve.AllowGlobalReassign, "allow reassignment of globals, and if/for/while statements at top level") 44 45 // flags that are now standard 46 flag.BoolVar(&resolve.AllowFloat, "float", resolve.AllowFloat, "obsolete; no effect") 47 flag.BoolVar(&resolve.AllowLambda, "lambda", resolve.AllowLambda, "obsolete; no effect") 48 } 49 50 func main() { 51 os.Exit(doMain()) 52 } 53 54 func doMain() int { 55 log.SetPrefix("starlark: ") 56 log.SetFlags(0) 57 flag.Parse() 58 59 if *cpuprofile != "" { 60 f, err := os.Create(*cpuprofile) 61 check(err) 62 err = pprof.StartCPUProfile(f) 63 check(err) 64 defer func() { 65 pprof.StopCPUProfile() 66 err := f.Close() 67 check(err) 68 }() 69 } 70 if *memprofile != "" { 71 f, err := os.Create(*memprofile) 72 check(err) 73 defer func() { 74 runtime.GC() 75 err := pprof.Lookup("heap").WriteTo(f, 0) 76 check(err) 77 err = f.Close() 78 check(err) 79 }() 80 } 81 82 if *profile != "" { 83 f, err := os.Create(*profile) 84 check(err) 85 err = starlark.StartProfile(f) 86 check(err) 87 defer func() { 88 err := starlark.StopProfile() 89 check(err) 90 }() 91 } 92 93 thread := &starlark.Thread{Load: repl.MakeLoad()} 94 globals := make(starlark.StringDict) 95 96 // Ideally this statement would update the predeclared environment. 97 // TODO(adonovan): plumb predeclared env through to the REPL. 98 starlark.Universe["json"] = json.Module 99 starlark.Universe["time"] = time.Module 100 starlark.Universe["math"] = math.Module 101 102 switch { 103 case flag.NArg() == 1 || *execprog != "": 104 var ( 105 filename string 106 src interface{} 107 err error 108 ) 109 if *execprog != "" { 110 // Execute provided program. 111 filename = "cmdline" 112 src = *execprog 113 } else { 114 // Execute specified file. 115 filename = flag.Arg(0) 116 } 117 thread.Name = "exec " + filename 118 globals, err = starlark.ExecFile(thread, filename, src, nil) 119 if err != nil { 120 repl.PrintError(err) 121 return 1 122 } 123 case flag.NArg() == 0: 124 stdinIsTerminal := term.IsTerminal(int(os.Stdin.Fd())) 125 if stdinIsTerminal { 126 fmt.Println("Welcome to Starlark (go.starlark.net)") 127 } 128 thread.Name = "REPL" 129 repl.REPL(thread, globals) 130 if stdinIsTerminal { 131 fmt.Println() 132 } 133 default: 134 log.Print("want at most one Starlark file name") 135 return 1 136 } 137 138 // Print the global environment. 139 if *showenv { 140 for _, name := range globals.Keys() { 141 if !strings.HasPrefix(name, "_") { 142 fmt.Fprintf(os.Stderr, "%s = %s\n", name, globals[name]) 143 } 144 } 145 } 146 147 return 0 148 } 149 150 func check(err error) { 151 if err != nil { 152 log.Fatal(err) 153 } 154 }