Create a very basic runtime/ns/scope with a basic repl
This commit is contained in:
parent
c0fc5b152e
commit
a7457fceb6
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
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 replCmd = &cobra.Command{
|
||||
Use: "repl",
|
||||
Short: "Runs the local Serene's REPL",
|
||||
Long: `Runs the local Serene's REPL to interact with Serene`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// TODO: Get the debug value from a CLI flag
|
||||
core.REPL(false)
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(replCmd)
|
||||
}
|
|
@ -22,12 +22,8 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"serene-lang.org/bootstrap/pkg/parser"
|
||||
"serene-lang.org/bootstrap/pkg/reader"
|
||||
)
|
||||
|
||||
var cfgFile string
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "Serene",
|
||||
|
@ -43,9 +39,7 @@ to redistribute it under certain conditions;
|
|||
for details take a look at the LICENSE file.
|
||||
`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
reader.ReadString("sameer mary")
|
||||
ast, _ := parser.ParseToAST("(asd 'mary '(1 2 3.4 -4 -0.3) `(asd ~asd ~@zxc))")
|
||||
fmt.Printf("%s\n", ast.String())
|
||||
fmt.Println("Fix me!!!! I don't do anything !!!")
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ module serene-lang.org/bootstrap
|
|||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
||||
github.com/spf13/cobra v1.1.1
|
||||
github.com/spf13/viper v1.7.1
|
||||
)
|
||||
|
|
|
@ -26,6 +26,8 @@ github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+Ce
|
|||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
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 core contains the high level internal function of Serene
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/chzyer/readline"
|
||||
"serene-lang.org/bootstrap/pkg/printer"
|
||||
"serene-lang.org/bootstrap/pkg/reader"
|
||||
"serene-lang.org/bootstrap/pkg/runtime"
|
||||
)
|
||||
|
||||
func rep(rt *runtime.Runtime, line string) {
|
||||
ast, err := reader.ReadString(line)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: %s", err)
|
||||
return
|
||||
}
|
||||
//eval.Eval(rt, ast)
|
||||
printer.Print(rt, ast)
|
||||
}
|
||||
|
||||
/** TODO:
|
||||
Replace the readline implementation with go-prompt.
|
||||
*/
|
||||
|
||||
func REPL(debug bool) {
|
||||
rt := runtime.MakeRuntime(debug)
|
||||
|
||||
rt.CreateNS("user", "REPL", true)
|
||||
rl, err := readline.New("> ")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer rl.Close()
|
||||
|
||||
fmt.Println(`Serene's bootstrap interpreter is used to
|
||||
bootstrap the Serene's compiler.'
|
||||
|
||||
It comes with ABSOLUTELY NO WARRANTY;
|
||||
This is free software, and you are welcome
|
||||
to redistribute it under certain conditions;
|
||||
for details take a look at the LICENSE file.
|
||||
`)
|
||||
for {
|
||||
rl.SetPrompt(fmt.Sprintf("%s> ", rt.CurrentNS().GetName()))
|
||||
line, err := rl.Readline()
|
||||
if err != nil { // io.EOF
|
||||
break
|
||||
}
|
||||
rep(rt, line)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
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 eval provides all the necessary functions to eval expressions
|
||||
package eval
|
||||
|
||||
import (
|
||||
"serene-lang.org/bootstrap/pkg/runtime"
|
||||
"serene-lang.org/bootstrap/pkg/types"
|
||||
)
|
||||
|
||||
func eval(rt *runtime.Runtime, forms types.ASTree) types.IExpr {
|
||||
if len(forms) == 0 {
|
||||
return &types.Nil
|
||||
}
|
||||
|
||||
var ret types.IExpr
|
||||
|
||||
for _, form := range forms {
|
||||
ret = eval_form(rt, rt.CurrentNS().GetRootScope(), form)
|
||||
}
|
||||
|
||||
ret
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
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 namespace provides an INamespace interface and one implementation
|
||||
// of it to be used as the basic blocks of Serene's namespaces.
|
||||
package namespace
|
||||
|
||||
import "serene-lang.org/bootstrap/pkg/scope"
|
||||
|
||||
type INamespace interface {
|
||||
DefineGlobal()
|
||||
LookupGlobal()
|
||||
GetRootScope() scope.IScope
|
||||
// return the fully qualified name of the namespace
|
||||
GetName() string
|
||||
}
|
||||
|
||||
type Namespace struct {
|
||||
name string
|
||||
rootScope scope.Scope
|
||||
source string
|
||||
externals map[string]Namespace
|
||||
}
|
||||
|
||||
func (n *Namespace) DefineGlobal() {}
|
||||
|
||||
func (n *Namespace) LookupGlobal() {}
|
||||
|
||||
func (n *Namespace) GetRootScope() scope.IScope {
|
||||
return &n.rootScope
|
||||
}
|
||||
|
||||
func (n *Namespace) GetName() string {
|
||||
return n.name
|
||||
}
|
||||
|
||||
func MakeNS(name string, source string) Namespace {
|
||||
return Namespace{
|
||||
name: name,
|
||||
rootScope: scope.MakeScope(nil),
|
||||
source: source,
|
||||
externals: map[string]Namespace{},
|
||||
}
|
||||
}
|
|
@ -95,14 +95,15 @@ func readRawSymbol(parser IParsable) (types.IExpr, error) {
|
|||
var symbol string
|
||||
|
||||
if c == nil {
|
||||
return nil, errors.New("Unexpected EOF while parsing a symbol")
|
||||
return nil, errors.New("unexpected EOF while parsing a symbol")
|
||||
}
|
||||
|
||||
if isValidForSymbol(*c) {
|
||||
parser.next(false)
|
||||
symbol = *c
|
||||
} else {
|
||||
|
||||
return nil, fmt.Errorf("Unexpected character: got '%s', expected a symbol at %s",
|
||||
return nil, fmt.Errorf("unexpected character: got '%s', expected a symbol at %s",
|
||||
*c,
|
||||
parser.GetLocation(),
|
||||
)
|
||||
|
@ -143,7 +144,6 @@ func readNumber(parser IParsable, neg bool) (types.IExpr, error) {
|
|||
}
|
||||
|
||||
if *c == "." && isDouble {
|
||||
fmt.Println(result)
|
||||
return nil, errors.New("a double with more that one '.' ???")
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ func readNumber(parser IParsable, neg bool) (types.IExpr, error) {
|
|||
break
|
||||
}
|
||||
}
|
||||
fmt.Println(result)
|
||||
|
||||
return types.MakeNumberFromStr(result, isDouble)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
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 printer contains helper functions to printout AST and exprs
|
||||
package printer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"serene-lang.org/bootstrap/pkg/runtime"
|
||||
"serene-lang.org/bootstrap/pkg/types"
|
||||
)
|
||||
|
||||
func Print(rt *runtime.Runtime, ast types.ASTree) {
|
||||
fmt.Println(ast.String())
|
||||
}
|
|
@ -15,7 +15,16 @@ 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 reader provides a set of functions to read forms from several
|
||||
// different mediums
|
||||
package reader
|
||||
|
||||
func ReadString(input string) {
|
||||
import (
|
||||
"serene-lang.org/bootstrap/pkg/parser"
|
||||
"serene-lang.org/bootstrap/pkg/types"
|
||||
)
|
||||
|
||||
func ReadString(input string) (types.ASTree, error) {
|
||||
return parser.ParseToAST(input)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
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 runtime provides all the necessary functionality and data
|
||||
// structures of Serene at runtime. You can think of the run time as
|
||||
// Serene's state.
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"serene-lang.org/bootstrap/pkg/namespace"
|
||||
)
|
||||
|
||||
/** TODO:
|
||||
Create an IRuntime interface to avoid using INamespace directly
|
||||
*/
|
||||
|
||||
/** TODO:
|
||||
Handle concurrency on the runtime level
|
||||
*/
|
||||
|
||||
type Runtime struct {
|
||||
namespaces map[string]namespace.Namespace
|
||||
currentNS string
|
||||
debugMode bool
|
||||
}
|
||||
|
||||
func (r *Runtime) CurrentNS() *namespace.Namespace {
|
||||
if r.currentNS == "" {
|
||||
panic("current ns is not set on the runtime.")
|
||||
}
|
||||
|
||||
ns, ok := r.namespaces[r.currentNS]
|
||||
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("namespace '%s' doesn't exist in the runtime.", r.currentNS))
|
||||
}
|
||||
|
||||
return &ns
|
||||
}
|
||||
|
||||
func (r *Runtime) CreateNS(name string, source string, setAsCurrent bool) {
|
||||
ns := namespace.MakeNS(name, source)
|
||||
|
||||
if setAsCurrent {
|
||||
r.currentNS = name
|
||||
}
|
||||
r.namespaces[name] = ns
|
||||
}
|
||||
|
||||
func MakeRuntime(debug bool) *Runtime {
|
||||
return &Runtime{
|
||||
namespaces: map[string]namespace.Namespace{},
|
||||
currentNS: "",
|
||||
debugMode: debug,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
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 scope provides several interfaces and their implementations
|
||||
// such `Scope` which acts as the environment in the Lisp literature.
|
||||
package scope
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"serene-lang.org/bootstrap/pkg/types"
|
||||
)
|
||||
|
||||
type IScope interface {
|
||||
Lookup(k string) (*Binding, error)
|
||||
Insert(k string, v types.IExpr, public bool)
|
||||
}
|
||||
|
||||
type Binding struct {
|
||||
value types.IExpr
|
||||
public bool
|
||||
}
|
||||
|
||||
type Scope struct {
|
||||
bindings map[string]*Binding
|
||||
parent IScope
|
||||
}
|
||||
|
||||
func (s *Scope) Lookup(k string) (*Binding, error) {
|
||||
v, ok := s.bindings[k]
|
||||
if ok {
|
||||
return v, nil
|
||||
}
|
||||
|
||||
if s.parent != nil {
|
||||
return s.parent.Lookup(k)
|
||||
} else {
|
||||
return nil, fmt.Errorf("can't resolve symbol '%s'", k)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scope) Insert(k string, v types.IExpr, public bool) {
|
||||
s.bindings[k] = &Binding{value: v, public: public}
|
||||
}
|
||||
|
||||
func MakeScope(parent *Scope) Scope {
|
||||
return Scope{
|
||||
parent: parent,
|
||||
bindings: map[string]*Binding{},
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue