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