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). 7package main // import "go.starlark.net/cmd/starlark" 8 9import ( 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/time" 20 "go.starlark.net/repl" 21 "go.starlark.net/resolve" 22 "go.starlark.net/starlark" 23 "go.starlark.net/starlarkjson" 24) 25 26// flags 27var ( 28 cpuprofile = flag.String("cpuprofile", "", "gather Go CPU profile in this file") 29 memprofile = flag.String("memprofile", "", "gather Go memory profile in this file") 30 profile = flag.String("profile", "", "gather Starlark time profile in this file") 31 showenv = flag.Bool("showenv", false, "on success, print final global environment") 32 execprog = flag.String("c", "", "execute program `prog`") 33) 34 35func init() { 36 flag.BoolVar(&compile.Disassemble, "disassemble", compile.Disassemble, "show disassembly during compilation of each function") 37 38 // non-standard dialect flags 39 flag.BoolVar(&resolve.AllowFloat, "float", resolve.AllowFloat, "obsolete; no effect") 40 flag.BoolVar(&resolve.AllowSet, "set", resolve.AllowSet, "allow set data type") 41 flag.BoolVar(&resolve.AllowLambda, "lambda", resolve.AllowLambda, "allow lambda expressions") 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 46func main() { 47 os.Exit(doMain()) 48} 49 50func doMain() int { 51 log.SetPrefix("starlark: ") 52 log.SetFlags(0) 53 flag.Parse() 54 55 if *cpuprofile != "" { 56 f, err := os.Create(*cpuprofile) 57 check(err) 58 err = pprof.StartCPUProfile(f) 59 check(err) 60 defer func() { 61 pprof.StopCPUProfile() 62 err := f.Close() 63 check(err) 64 }() 65 } 66 if *memprofile != "" { 67 f, err := os.Create(*memprofile) 68 check(err) 69 defer func() { 70 runtime.GC() 71 err := pprof.Lookup("heap").WriteTo(f, 0) 72 check(err) 73 err = f.Close() 74 check(err) 75 }() 76 } 77 78 if *profile != "" { 79 f, err := os.Create(*profile) 80 check(err) 81 err = starlark.StartProfile(f) 82 check(err) 83 defer func() { 84 err := starlark.StopProfile() 85 check(err) 86 }() 87 } 88 89 thread := &starlark.Thread{Load: repl.MakeLoad()} 90 globals := make(starlark.StringDict) 91 92 // Ideally this statement would update the predeclared environment. 93 // TODO(adonovan): plumb predeclared env through to the REPL. 94 starlark.Universe["json"] = starlarkjson.Module 95 starlark.Universe["time"] = time.Module 96 97 switch { 98 case flag.NArg() == 1 || *execprog != "": 99 var ( 100 filename string 101 src interface{} 102 err error 103 ) 104 if *execprog != "" { 105 // Execute provided program. 106 filename = "cmdline" 107 src = *execprog 108 } else { 109 // Execute specified file. 110 filename = flag.Arg(0) 111 } 112 thread.Name = "exec " + filename 113 globals, err = starlark.ExecFile(thread, filename, src, nil) 114 if err != nil { 115 repl.PrintError(err) 116 return 1 117 } 118 case flag.NArg() == 0: 119 fmt.Println("Welcome to Starlark (go.starlark.net)") 120 thread.Name = "REPL" 121 repl.REPL(thread, globals) 122 default: 123 log.Print("want at most one Starlark file name") 124 return 1 125 } 126 127 // Print the global environment. 128 if *showenv { 129 for _, name := range globals.Keys() { 130 if !strings.HasPrefix(name, "_") { 131 fmt.Fprintf(os.Stderr, "%s = %s\n", name, globals[name]) 132 } 133 } 134 } 135 136 return 0 137} 138 139func check(err error) { 140 if err != nil { 141 log.Fatal(err) 142 } 143} 144