github.com/lab47/exprcore@v0.0.0-20210525052339-fb7d6bd9331e/cmd/exprcore/exprcore.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 exprcore command interprets a exprcore file.
     6  // With no arguments, it starts a read-eval-print loop (REPL).
     7  package main // import "github.com/lab47/exprcore/cmd/exprcore"
     8  
     9  import (
    10  	"flag"
    11  	"fmt"
    12  	"log"
    13  	"os"
    14  	"runtime"
    15  	"runtime/pprof"
    16  	"strings"
    17  
    18  	"github.com/lab47/exprcore/exprcore"
    19  	"github.com/lab47/exprcore/internal/compile"
    20  	"github.com/lab47/exprcore/repl"
    21  	"github.com/lab47/exprcore/resolve"
    22  )
    23  
    24  // flags
    25  var (
    26  	cpuprofile = flag.String("cpuprofile", "", "gather Go CPU profile in this file")
    27  	memprofile = flag.String("memprofile", "", "gather Go memory profile in this file")
    28  	profile    = flag.String("profile", "", "gather exprcore time profile in this file")
    29  	showenv    = flag.Bool("showenv", false, "on success, print final global environment")
    30  	execprog   = flag.String("c", "", "execute program `prog`")
    31  )
    32  
    33  func init() {
    34  	flag.BoolVar(&compile.Disassemble, "disassemble", compile.Disassemble, "show disassembly during compilation of each function")
    35  
    36  	// non-standard dialect flags
    37  	flag.BoolVar(&resolve.AllowFloat, "float", resolve.AllowFloat, "allow floating-point numbers")
    38  	flag.BoolVar(&resolve.AllowSet, "set", resolve.AllowSet, "allow set data type")
    39  	flag.BoolVar(&resolve.AllowLambda, "lambda", resolve.AllowLambda, "allow lambda expressions")
    40  	flag.BoolVar(&resolve.AllowNestedDef, "nesteddef", resolve.AllowNestedDef, "allow nested def statements")
    41  	flag.BoolVar(&resolve.AllowRecursion, "recursion", resolve.AllowRecursion, "allow while statements and recursive functions")
    42  	flag.BoolVar(&resolve.AllowGlobalReassign, "globalreassign", resolve.AllowGlobalReassign, "allow reassignment of globals, and if/for/while statements at top level")
    43  }
    44  
    45  func main() {
    46  	os.Exit(doMain())
    47  }
    48  
    49  func doMain() int {
    50  	log.SetPrefix("exprcore: ")
    51  	log.SetFlags(0)
    52  	flag.Parse()
    53  
    54  	if *cpuprofile != "" {
    55  		f, err := os.Create(*cpuprofile)
    56  		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  		}()
    75  	}
    76  
    77  	if *profile != "" {
    78  		f, err := os.Create(*profile)
    79  		check(err)
    80  		err = exprcore.StartProfile(f)
    81  		check(err)
    82  		defer func() {
    83  			err := exprcore.StopProfile()
    84  			check(err)
    85  		}()
    86  	}
    87  
    88  	thread := &exprcore.Thread{Load: repl.MakeLoad()}
    89  	globals := make(exprcore.StringDict)
    90  
    91  	switch {
    92  	case flag.NArg() == 1 || *execprog != "":
    93  		var (
    94  			filename string
    95  			src      interface{}
    96  			err      error
    97  		)
    98  		if *execprog != "" {
    99  			// Execute provided program.
   100  			filename = "cmdline"
   101  			src = *execprog
   102  		} else {
   103  			// Execute specified file.
   104  			filename = flag.Arg(0)
   105  		}
   106  		thread.Name = "exec " + filename
   107  		globals, err = exprcore.ExecFile(thread, filename, src, nil)
   108  		if err != nil {
   109  			repl.PrintError(err)
   110  			return 1
   111  		}
   112  	case flag.NArg() == 0:
   113  		fmt.Println("Welcome to exprcore (github.com/lab47/exprcore)")
   114  		thread.Name = "REPL"
   115  		repl.REPL(thread, globals)
   116  		return 0
   117  	default:
   118  		log.Print("want at most one exprcore file name")
   119  		return 1
   120  	}
   121  
   122  	// Print the global environment.
   123  	if *showenv {
   124  		for _, name := range globals.Keys() {
   125  			if !strings.HasPrefix(name, "_") {
   126  				fmt.Fprintf(os.Stderr, "%s = %s\n", name, globals[name])
   127  			}
   128  		}
   129  	}
   130  
   131  	return 0
   132  }
   133  
   134  func check(err error) {
   135  	if err != nil {
   136  		log.Fatal(err)
   137  	}
   138  }