Add 'paths' support alongside with namespace loading to the Runtime

This commit is contained in:
Sameer Rahmani 2020-12-12 20:27:53 +00:00
parent 17e35aa2e9
commit aa1079c6b6
2 changed files with 104 additions and 5 deletions

View File

@ -37,9 +37,7 @@ func rep(rt *Runtime, line string) {
// Debug data, ugly right ? :))
if rt.IsDebugMode() {
fmt.Println("\n### DEBUG ###")
Print(rt, ast)
fmt.Print("#############\n\n")
fmt.Printf("[DEBUG] Parsed AST: %s\n", ast.String())
}
result, e := Eval(rt, ast)
@ -57,7 +55,13 @@ Replace the readline implementation with go-prompt.
// REPL executes a Read Eval Print Loop locally reading from stdin and
// writing to stdout
func REPL(debug bool) {
rt := MakeRuntime(debug)
cwd, err := os.Getwd()
if err != nil {
panic(err)
}
rt := MakeRuntime([]string{cwd}, debug)
rt.CreateNS("user", "REPL", true)
rl, err := readline.NewEx(&readline.Config{

View File

@ -20,6 +20,10 @@ package core
import (
"fmt"
"io/ioutil"
"os"
"path"
"strings"
)
/** TODO:
@ -29,10 +33,15 @@ Create an IRuntime interface to avoid using INamespace directly
/** TODO:
Handle concurrency on the runtime level
*/
type loadedForms struct {
source string
forms *Block
}
type Runtime struct {
namespaces map[string]Namespace
currentNS string
paths []string
debugMode bool
}
@ -54,6 +63,21 @@ func (r *Runtime) CurrentNS() *Namespace {
return &ns
}
func (r *Runtime) setCurrentNS(nsName string) bool {
_, ok := r.namespaces[nsName]
if ok {
r.currentNS = nsName
return true
}
return false
}
func (r *Runtime) GetNS(ns string) (*Namespace, bool) {
namespace, ok := r.namespaces[ns]
return &namespace, ok
}
func (r *Runtime) CreateNS(name string, source string, setAsCurrent bool) {
ns := MakeNS(name, source)
@ -69,10 +93,81 @@ func (r *Runtime) IsQQSimplificationEnabled() bool {
return false
}
func MakeRuntime(debug bool) *Runtime {
func nsNameToPath(ns string) string {
replacer := strings.NewReplacer(
".", "/",
//"-", "_",
)
return replacer.Replace(ns)
}
func (r *Runtime) LoadNS(ns string) (*loadedForms, IError) {
nsFile := nsNameToPath(ns)
for _, loadPath := range r.paths {
// TODO: Hardcoding the suffix??? ewwww, fix it.
possibleFile := path.Join(loadPath, nsFile+".srn")
_, err := os.Stat(possibleFile)
if err != nil {
continue
}
data, err := ioutil.ReadFile(possibleFile)
if err != nil {
readError := MakeError(
r,
fmt.Sprintf("error while reading the file at %s", possibleFile),
)
readError.WithError(err)
return nil, readError
}
body, e := ReadString(string(data))
if e != nil {
return nil, e
}
return &loadedForms{possibleFile, body}, nil
}
// TODO: Add the load paths to the error message here
return nil, MakeError(r, fmt.Sprintf("Can't find the namespace '%s' in any of load paths.", ns))
}
func (r *Runtime) RequireNS(ns string) (*Namespace, IError) {
// TODO: use a hashing algorithm to avoid reloading an unchanged namespace
loadedForms, err := r.LoadNS(ns)
if err != nil {
return nil, err
}
body := loadedForms.forms
source := loadedForms.source
if body.Count() == 0 {
return nil, MakeError(
r,
fmt.Sprintf("The '%s' ns source code doesn't start with an 'ns' form.", ns),
)
}
namespace := MakeNS(ns, source)
namespace.setForms(body)
return &namespace, nil
}
func (r *Runtime) InsertNS(nsName string, ns *Namespace) {
r.namespaces[nsName] = *ns
}
func MakeRuntime(paths []string, debug bool) *Runtime {
return &Runtime{
namespaces: map[string]Namespace{},
currentNS: "",
debugMode: debug,
paths: paths,
}
}