Add 'run' subcommand to Serene binary

This commit is contained in:
Sameer Rahmani 2020-12-24 16:27:46 +00:00
parent 69d30dd04e
commit fb6c1b3ba3
2 changed files with 114 additions and 1 deletions

37
bootstrap/cmd/run.go Normal file
View File

@ -0,0 +1,37 @@
/*
Serene --- Yet an other Lisp
Copyright (c) 2020 Sameer Rahmani <lxsameer@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package cmd
import (
"github.com/spf13/cobra"
"serene-lang.org/bootstrap/pkg/core"
)
// replCmd represents the base command when called without any subcommands
var runCmd = &cobra.Command{
Use: "run NS",
Short: "Evaluates the given NS and runs the main function of it",
Long: `Evaluates the given NS and runs the main function`,
Run: func(cmd *cobra.Command, args []string) {
core.Run(debugMode, args)
},
}
func init() {
rootCmd.AddCommand(runCmd)
}

View File

@ -25,6 +25,7 @@ import (
"path/filepath"
"github.com/chzyer/readline"
"serene-lang.org/bootstrap/pkg/ast"
)
func rep(rt *Runtime, line string) {
@ -45,7 +46,7 @@ func rep(rt *Runtime, line string) {
PrintError(rt, e)
return
}
Print(rt, result)
Prn(rt, result)
}
/** TODO:
@ -95,3 +96,78 @@ for details take a look at the LICENSE file.
}
}
func Run(debug bool, args []string) {
cwd, e := os.Getwd()
if e != nil {
panic(e)
}
rt := MakeRuntime([]string{cwd}, debug)
if len(args) == 0 {
PrintError(rt, MakePlainError("'run' command needs at least one argument"))
os.Exit(1)
}
ns := args[0]
loadedNS, err := requireNS(rt, ns)
if err != nil {
PrintError(rt, err)
os.Exit(1)
}
rt.InsertNS(ns, loadedNS)
inserted := rt.setCurrentNS(loadedNS.GetName())
if !inserted {
err := MakeError(
rt,
fmt.Sprintf(
"the namespace '%s' didn't get inserted in the runtime.",
loadedNS.GetName()),
)
PrintError(rt, err)
os.Exit(1)
}
// Evaluating the body of the loaded ns (Check for ns validation happens here)
loadedNS, err = EvalNSBody(rt, loadedNS)
if err != nil {
PrintError(rt, err)
os.Exit(1)
}
mainBinding := loadedNS.GetRootScope().Lookup(rt, "main")
if mainBinding == nil {
fmt.Printf(">>> %w\n", loadedNS.GetRootScope())
PrintError(rt, MakePlainError(fmt.Sprintf("can't find the 'main' function in '%s' namespace", ns)))
os.Exit(1)
}
if mainBinding.Value.GetType() != ast.Fn {
PrintError(rt, MakePlainError("'main' is not a function"))
os.Exit(1)
}
mainFn := mainBinding.Value.(*Function)
var fnArgs []IExpr
if len(args) > 1 {
for _, arg := range args[1:] {
node := MakeNodeFromExpr(mainFn)
fnArgs = append(fnArgs, MakeString(node, arg))
}
}
_, err = mainFn.Apply(rt, loadedNS.GetRootScope(), mainFn.Node, MakeList(fnArgs))
if err != nil {
PrintError(rt, err)
os.Exit(1)
}
}