blob: 3825f003422fd7421e996f851d1d4b1602938334 [file] [log] [blame]
Alan Donovan312d1a52017-10-02 10:10:28 -04001// 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
Alan Donovane3deafe2018-10-23 11:05:09 -04005// The starlark command interprets a Starlark file.
Alan Donovan312d1a52017-10-02 10:10:28 -04006// With no arguments, it starts a read-eval-print loop (REPL).
Alan Donovan551f3002018-11-01 09:44:00 -04007package main // import "go.starlark.net/cmd/starlark"
Alan Donovan312d1a52017-10-02 10:10:28 -04008
9import (
Alan Donovan312d1a52017-10-02 10:10:28 -040010 "flag"
11 "fmt"
12 "log"
13 "os"
Josh Bleecher Snyderfab11d52019-04-11 11:35:16 -070014 "runtime"
Alan Donovan312d1a52017-10-02 10:10:28 -040015 "runtime/pprof"
Alan Donovan312d1a52017-10-02 10:10:28 -040016 "strings"
17
alandonovand6561f82019-07-12 10:19:25 -040018 "go.starlark.net/internal/compile"
Alan Donovan6beab7e2018-10-31 17:53:09 -040019 "go.starlark.net/repl"
20 "go.starlark.net/resolve"
Alan Donovan551f3002018-11-01 09:44:00 -040021 "go.starlark.net/starlark"
alandonovanac23acb2020-06-11 17:56:15 -040022 "go.starlark.net/starlarkjson"
Alan Donovan312d1a52017-10-02 10:10:28 -040023)
24
25// flags
26var (
alandonovan40b4ab62019-04-03 16:41:37 -040027 cpuprofile = flag.String("cpuprofile", "", "gather Go CPU profile in this file")
Josh Bleecher Snyderfab11d52019-04-11 11:35:16 -070028 memprofile = flag.String("memprofile", "", "gather Go memory profile in this file")
alandonovan40b4ab62019-04-03 16:41:37 -040029 profile = flag.String("profile", "", "gather Starlark time profile in this file")
Alan Donovan312d1a52017-10-02 10:10:28 -040030 showenv = flag.Bool("showenv", false, "on success, print final global environment")
Josh Bleecher Snyderd1cdecf2018-12-07 14:21:37 -080031 execprog = flag.String("c", "", "execute program `prog`")
Alan Donovan312d1a52017-10-02 10:10:28 -040032)
33
Alan Donovan312d1a52017-10-02 10:10:28 -040034func init() {
alandonovand6561f82019-07-12 10:19:25 -040035 flag.BoolVar(&compile.Disassemble, "disassemble", compile.Disassemble, "show disassembly during compilation of each function")
36
37 // non-standard dialect flags
alandonovan3b7e02e2020-11-11 12:03:41 -050038 flag.BoolVar(&resolve.AllowFloat, "float", resolve.AllowFloat, "obsolete; no effect")
Alan Donovan312d1a52017-10-02 10:10:28 -040039 flag.BoolVar(&resolve.AllowSet, "set", resolve.AllowSet, "allow set data type")
40 flag.BoolVar(&resolve.AllowLambda, "lambda", resolve.AllowLambda, "allow lambda expressions")
Alessandro Arzilli678bafe2018-12-07 17:28:35 +010041 flag.BoolVar(&resolve.AllowRecursion, "recursion", resolve.AllowRecursion, "allow while statements and recursive functions")
Alan Donovanc0b6b762018-12-18 13:09:56 -050042 flag.BoolVar(&resolve.AllowGlobalReassign, "globalreassign", resolve.AllowGlobalReassign, "allow reassignment of globals, and if/for/while statements at top level")
Alan Donovan312d1a52017-10-02 10:10:28 -040043}
44
45func main() {
alandonovan40b4ab62019-04-03 16:41:37 -040046 os.Exit(doMain())
47}
48
49func doMain() int {
Alan Donovane3deafe2018-10-23 11:05:09 -040050 log.SetPrefix("starlark: ")
Alan Donovan312d1a52017-10-02 10:10:28 -040051 log.SetFlags(0)
52 flag.Parse()
53
54 if *cpuprofile != "" {
55 f, err := os.Create(*cpuprofile)
Josh Bleecher Snyderfab11d52019-04-11 11:35:16 -070056 check(err)
57 err = pprof.StartCPUProfile(f)
58 check(err)
59 defer func() {
60 pprof.StopCPUProfile()
61 err := f.Close()
62 check(err)
63 }()
64 }
65 if *memprofile != "" {
66 f, err := os.Create(*memprofile)
67 check(err)
68 defer func() {
69 runtime.GC()
70 err := pprof.Lookup("heap").WriteTo(f, 0)
71 check(err)
72 err = f.Close()
73 check(err)
74 }()
Alan Donovan312d1a52017-10-02 10:10:28 -040075 }
76
alandonovan40b4ab62019-04-03 16:41:37 -040077 if *profile != "" {
78 f, err := os.Create(*profile)
Josh Bleecher Snyderfab11d52019-04-11 11:35:16 -070079 check(err)
80 err = starlark.StartProfile(f)
81 check(err)
alandonovan40b4ab62019-04-03 16:41:37 -040082 defer func() {
Josh Bleecher Snyderfab11d52019-04-11 11:35:16 -070083 err := starlark.StopProfile()
84 check(err)
alandonovan40b4ab62019-04-03 16:41:37 -040085 }()
86 }
87
Alan Donovane3deafe2018-10-23 11:05:09 -040088 thread := &starlark.Thread{Load: repl.MakeLoad()}
89 globals := make(starlark.StringDict)
alandonovan55968252017-12-22 15:50:31 -050090
alandonovanac23acb2020-06-11 17:56:15 -040091 // Ideally this statement would update the predeclared environment.
92 // TODO(adonovan): plumb predeclared env through to the REPL.
93 starlark.Universe["json"] = starlarkjson.Module
94
Josh Bleecher Snyderd1cdecf2018-12-07 14:21:37 -080095 switch {
96 case flag.NArg() == 1 || *execprog != "":
97 var (
98 filename string
99 src interface{}
100 err error
101 )
102 if *execprog != "" {
103 // Execute provided program.
104 filename = "cmdline"
105 src = *execprog
106 } else {
107 // Execute specified file.
108 filename = flag.Arg(0)
109 }
alandonovan2c1f3622018-12-17 13:10:16 -0500110 thread.Name = "exec " + filename
Josh Bleecher Snyderd1cdecf2018-12-07 14:21:37 -0800111 globals, err = starlark.ExecFile(thread, filename, src, nil)
alandonovana1b28d82018-03-13 10:59:24 -0400112 if err != nil {
alandonovan55968252017-12-22 15:50:31 -0500113 repl.PrintError(err)
alandonovan40b4ab62019-04-03 16:41:37 -0400114 return 1
alandonovan55968252017-12-22 15:50:31 -0500115 }
Josh Bleecher Snyderd1cdecf2018-12-07 14:21:37 -0800116 case flag.NArg() == 0:
117 fmt.Println("Welcome to Starlark (go.starlark.net)")
alandonovan2c1f3622018-12-17 13:10:16 -0500118 thread.Name = "REPL"
Josh Bleecher Snyderd1cdecf2018-12-07 14:21:37 -0800119 repl.REPL(thread, globals)
Alan Donovan312d1a52017-10-02 10:10:28 -0400120 default:
alandonovan40b4ab62019-04-03 16:41:37 -0400121 log.Print("want at most one Starlark file name")
122 return 1
Alan Donovan312d1a52017-10-02 10:10:28 -0400123 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400124
125 // Print the global environment.
126 if *showenv {
alandonovan0ed7e5b2019-01-03 16:11:58 -0500127 for _, name := range globals.Keys() {
Alan Donovan07c77022019-01-23 10:31:45 -0500128 if !strings.HasPrefix(name, "_") {
alandonovan0ed7e5b2019-01-03 16:11:58 -0500129 fmt.Fprintf(os.Stderr, "%s = %s\n", name, globals[name])
Alan Donovan312d1a52017-10-02 10:10:28 -0400130 }
131 }
Alan Donovan312d1a52017-10-02 10:10:28 -0400132 }
alandonovan40b4ab62019-04-03 16:41:37 -0400133
134 return 0
Alan Donovan312d1a52017-10-02 10:10:28 -0400135}
Josh Bleecher Snyderfab11d52019-04-11 11:35:16 -0700136
137func check(err error) {
138 if err != nil {
139 log.Fatal(err)
140 }
141}