Restructure the source tree to get around circular dep issue

This commit is contained in:
Sameer Rahmani 2020-11-15 22:16:48 +00:00
parent cba74e29af
commit ad37f02742
17 changed files with 76 additions and 135 deletions

View File

@ -16,7 +16,7 @@ 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 types
package core
type ISeq interface {
First() IExpr

View File

@ -23,10 +23,9 @@ import (
"fmt"
"github.com/chzyer/readline"
"serene-lang.org/bootstrap/pkg/runtime"
)
func rep(rt *runtime.Runtime, line string) {
func rep(rt *Runtime, line string) {
ast, err := ReadString(line)
if err != nil {
@ -53,7 +52,7 @@ Replace the readline implementation with go-prompt.
*/
func REPL(debug bool) {
rt := runtime.MakeRuntime(debug)
rt := MakeRuntime(debug)
rt.CreateNS("user", "REPL", true)
rl, err := readline.New("> ")

View File

@ -22,9 +22,6 @@ import (
"errors"
"serene-lang.org/bootstrap/pkg/ast"
"serene-lang.org/bootstrap/pkg/runtime"
"serene-lang.org/bootstrap/pkg/scope"
"serene-lang.org/bootstrap/pkg/types"
)
/** TODO:
@ -36,7 +33,7 @@ type def struct{}
var Def = def{}
func (d def) Apply(rt *runtime.Runtime, scope scope.IScope, args *types.List) (types.IExpr, error) {
func (d def) Apply(rt *Runtime, scope IScope, args *List) (IExpr, error) {
switch args.Count() {
case 2:
name := args.First()
@ -45,9 +42,9 @@ func (d def) Apply(rt *runtime.Runtime, scope scope.IScope, args *types.List) (t
return nil, errors.New("The first argument of 'def' has to be a symbol")
}
sym := name.(*types.Symbol)
sym := name.(*Symbol)
//value = args.Rest().(*types.List).First()
//value = args.Rest().(*List).First()
valueExpr := args.Rest().First()
value, err := EvalForm(rt, scope, valueExpr)

View File

@ -23,20 +23,19 @@ import (
"fmt"
"serene-lang.org/bootstrap/pkg/ast"
"serene-lang.org/bootstrap/pkg/runtime"
"serene-lang.org/bootstrap/pkg/scope"
"serene-lang.org/bootstrap/pkg/types"
)
var sFormsTable = map[string]types.ICallable{
var sFormsTable map[string]ICallable = map[string]ICallable{
"def": Def,
}
func GetBuildIn(s *types.Symbol) (types.ICallable, bool) {
return sFormsTable[s.GetName()]
func GetBuiltIn(s *Symbol) (ICallable, bool) {
// Go can't differntiate between returning a tupe directly or indirectly
v, ok := sFormsTable[s.GetName()]
return v, ok
}
func EvalForm(rt *runtime.Runtime, scope scope.IScope, form types.IExpr) (types.IExpr, error) {
func EvalForm(rt *Runtime, scope IScope, form IExpr) (IExpr, error) {
switch form.GetType() {
case ast.Nil:
case ast.Number:
@ -48,7 +47,7 @@ func EvalForm(rt *runtime.Runtime, scope scope.IScope, form types.IExpr) (types.
// * If it's not a NSQS Look up the name in the current scope.
// * Otherwise throw an error
case ast.Symbol:
symbolName := form.(*types.Symbol).GetName()
symbolName := form.(*Symbol).GetName()
expr := scope.Lookup(symbolName)
if expr == nil {
@ -63,14 +62,14 @@ func EvalForm(rt *runtime.Runtime, scope scope.IScope, form types.IExpr) (types.
// first element is `ICallable` and it's not a macro or special form.
// * An empty list evaluates to itself.
case ast.List:
list := form.(*types.List)
list := form.(*List)
if list.Count() == 0 {
return list, nil
}
first := form.(*types.List).First()
first := form.(*List).First()
if first.GetType() == ast.Symbol {
sform, ok := GetBuiltIn(first.(*types.Symbol))
sform, ok := GetBuiltIn(first.(*Symbol))
if ok {
return sform.Apply(rt, scope, list.Rest())
}
@ -84,12 +83,12 @@ func EvalForm(rt *runtime.Runtime, scope scope.IScope, form types.IExpr) (types.
return nil, errors.New("not implemented")
}
func Eval(rt *runtime.Runtime, forms types.ASTree) (types.IExpr, error) {
func Eval(rt *Runtime, forms ASTree) (IExpr, error) {
if len(forms) == 0 {
return &types.Nil, nil
return &Nil, nil
}
var ret types.IExpr
var ret IExpr
for _, form := range forms {
// v is here to shut up the linter

View File

@ -16,13 +16,8 @@ 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 types
import (
"serene-lang.org/bootstrap/pkg/runtime"
"serene-lang.org/bootstrap/pkg/scope"
)
package core
type ICallable interface {
Apply(rt *runtime.Runtime, scope scope.IScope, args *List) (IExpr, error)
Apply(rt *Runtime, scope IScope, args *List) (IExpr, error)
}

View File

@ -16,7 +16,7 @@ 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 types
package core
import (
"fmt"

View File

@ -16,37 +16,30 @@ 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"
"serene-lang.org/bootstrap/pkg/types"
)
package core
type INamespace interface {
DefineGlobal()
LookupGlobal()
GetRootScope() scope.IScope
GetRootScope() IScope
// return the fully qualified name of the namespace
GetName() string
}
type Namespace struct {
name string
rootScope scope.Scope
rootScope Scope
source string
externals map[string]Namespace
}
func (n *Namespace) DefineGlobal(k string, v types.IExpr, public bool) {
func (n *Namespace) DefineGlobal(k string, v IExpr, public bool) {
n.rootScope.Insert(k, v, public)
}
func (n *Namespace) LookupGlobal() {}
func (n *Namespace) GetRootScope() scope.IScope {
func (n *Namespace) GetRootScope() IScope {
return &n.rootScope
}
@ -57,7 +50,7 @@ func (n *Namespace) GetName() string {
func MakeNS(name string, source string) Namespace {
return Namespace{
name: name,
rootScope: scope.MakeScope(nil),
rootScope: MakeScope(nil),
source: source,
externals: map[string]Namespace{},
}

View File

@ -16,7 +16,7 @@ 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 types
package core
import "serene-lang.org/bootstrap/pkg/ast"

View File

@ -16,7 +16,7 @@ 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 types
package core
import (
"fmt"

View File

@ -16,21 +16,24 @@ 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 parser provides necessary functions to generate an AST
// from an input
package parser
package core
import (
"errors"
"fmt"
"strings"
"unicode"
"serene-lang.org/bootstrap/pkg/types"
)
var validChars = []rune{'!', '$', '%', '&', '*', '+', '-', '.', '~', '/', ':', '<', '=', '>', '?', '@', '^', '_'}
type IParsable interface {
next(skipWhitespace bool) *string
peek(skipWhitespace bool) *string
back()
GetLocation() int
}
type StringParser struct {
buffer []string
pos int
@ -90,7 +93,7 @@ func isValidForSymbol(char string) bool {
return contains(validChars, c) || unicode.IsLetter(c) || unicode.IsDigit(c)
}
func readRawSymbol(parser IParsable) (types.IExpr, error) {
func readRawSymbol(parser IParsable) (IExpr, error) {
c := parser.peek(false)
var symbol string
@ -124,10 +127,10 @@ func readRawSymbol(parser IParsable) (types.IExpr, error) {
}
// TODO: Add support for ns qualified symbols
return types.MakeSymbol(symbol), nil
return MakeSymbol(symbol), nil
}
func readNumber(parser IParsable, neg bool) (types.IExpr, error) {
func readNumber(parser IParsable, neg bool) (IExpr, error) {
isDouble := false
result := ""
@ -163,10 +166,10 @@ func readNumber(parser IParsable, neg bool) (types.IExpr, error) {
}
}
return types.MakeNumberFromStr(result, isDouble)
return MakeNumberFromStr(result, isDouble)
}
func readSymbol(parser IParsable) (types.IExpr, error) {
func readSymbol(parser IParsable) (IExpr, error) {
c := parser.peek(false)
if c == nil {
@ -204,8 +207,8 @@ func readSymbol(parser IParsable) (types.IExpr, error) {
return readRawSymbol(parser)
}
func readList(parser IParsable) (types.IExpr, error) {
list := []types.IExpr{}
func readList(parser IParsable) (IExpr, error) {
list := []IExpr{}
for {
c := parser.peek(true)
@ -226,10 +229,10 @@ func readList(parser IParsable) (types.IExpr, error) {
}
}
return types.MakeList(list), nil
return MakeList(list), nil
}
func readComment(parser IParsable) (types.IExpr, error) {
func readComment(parser IParsable) (IExpr, error) {
for {
c := parser.next(false)
if c == nil || *c == "\n" {
@ -238,36 +241,36 @@ func readComment(parser IParsable) (types.IExpr, error) {
}
}
func readQuotedExpr(parser IParsable) (types.IExpr, error) {
func readQuotedExpr(parser IParsable) (IExpr, error) {
expr, err := readExpr(parser)
if err != nil {
return nil, err
}
return types.MakeList([]types.IExpr{
types.MakeSymbol("quote"),
return MakeList([]IExpr{
MakeSymbol("quote"),
expr,
}), nil
}
func readUnquotedExpr(parser IParsable) (types.IExpr, error) {
func readUnquotedExpr(parser IParsable) (IExpr, error) {
c := parser.peek(true)
if c == nil {
return nil, errors.New("end of file while reading an unquoted expression")
}
var sym types.IExpr
var sym IExpr
var err error
var expr types.IExpr
var expr IExpr
if *c == "@" {
parser.next(true)
sym = types.MakeSymbol("unquote-splicing")
sym = MakeSymbol("unquote-splicing")
expr, err = readExpr(parser)
} else {
sym = types.MakeSymbol("unquote")
sym = MakeSymbol("unquote")
expr, err = readExpr(parser)
}
@ -275,22 +278,22 @@ func readUnquotedExpr(parser IParsable) (types.IExpr, error) {
return nil, err
}
return types.MakeList([]types.IExpr{sym, expr}), nil
return MakeList([]IExpr{sym, expr}), nil
}
func readQuasiquotedExpr(parser IParsable) (types.IExpr, error) {
func readQuasiquotedExpr(parser IParsable) (IExpr, error) {
expr, err := readExpr(parser)
if err != nil {
return nil, err
}
return types.MakeList([]types.IExpr{
types.MakeSymbol("quasiquote"),
return MakeList([]IExpr{
MakeSymbol("quasiquote"),
expr,
}), nil
}
func readExpr(parser IParsable) (types.IExpr, error) {
func readExpr(parser IParsable) (IExpr, error) {
loop:
c := parser.next(true)
@ -329,9 +332,9 @@ loop:
}
func ParseToAST(input string) (types.ASTree, error) {
func ParseToAST(input string) (ASTree, error) {
var ast types.ASTree
var ast ASTree
parser := StringParser{
buffer: strings.Split(input, ""),
pos: 0,

View File

@ -20,11 +20,8 @@ package core
import (
"fmt"
"serene-lang.org/bootstrap/pkg/runtime"
"serene-lang.org/bootstrap/pkg/types"
)
func Print(rt *runtime.Runtime, ast types.IPrintable) {
func Print(rt *Runtime, ast IPrintable) {
fmt.Println(ast.String())
}

View File

@ -18,11 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package core
import (
"serene-lang.org/bootstrap/pkg/parser"
"serene-lang.org/bootstrap/pkg/types"
)
func ReadString(input string) (types.ASTree, error) {
return parser.ParseToAST(input)
func ReadString(input string) (ASTree, error) {
return ParseToAST(input)
}

View File

@ -16,15 +16,10 @@ 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
package core
import (
"fmt"
"serene-lang.org/bootstrap/pkg/namespace"
)
/** TODO:
@ -36,7 +31,7 @@ Handle concurrency on the runtime level
*/
type Runtime struct {
namespaces map[string]namespace.Namespace
namespaces map[string]Namespace
currentNS string
debugMode bool
}
@ -45,7 +40,7 @@ func (r *Runtime) IsDebugMode() bool {
return r.debugMode
}
func (r *Runtime) CurrentNS() *namespace.Namespace {
func (r *Runtime) CurrentNS() *Namespace {
if r.currentNS == "" {
panic("current ns is not set on the runtime.")
}
@ -60,7 +55,7 @@ func (r *Runtime) CurrentNS() *namespace.Namespace {
}
func (r *Runtime) CreateNS(name string, source string, setAsCurrent bool) {
ns := namespace.MakeNS(name, source)
ns := MakeNS(name, source)
if setAsCurrent {
r.currentNS = name
@ -70,7 +65,7 @@ func (r *Runtime) CreateNS(name string, source string, setAsCurrent bool) {
func MakeRuntime(debug bool) *Runtime {
return &Runtime{
namespaces: map[string]namespace.Namespace{},
namespaces: map[string]Namespace{},
currentNS: "",
debugMode: debug,
}

View File

@ -16,21 +16,15 @@ 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 (
"serene-lang.org/bootstrap/pkg/types"
)
package core
type IScope interface {
Lookup(k string) *Binding
Insert(k string, v types.IExpr, public bool)
Insert(k string, v IExpr, public bool)
}
type Binding struct {
Value types.IExpr
Value IExpr
Public bool
}
@ -52,7 +46,7 @@ func (s *Scope) Lookup(k string) *Binding {
return nil
}
func (s *Scope) Insert(k string, v types.IExpr, public bool) {
func (s *Scope) Insert(k string, v IExpr, public bool) {
s.bindings[k] = Binding{Value: v, Public: public}
}

View File

@ -16,7 +16,7 @@ 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 types
package core
import "serene-lang.org/bootstrap/pkg/ast"

View File

@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
// Package types provides the type interface of Serene. All the types
// in Serene are directly AST Nodes as well.
package types
package core
import (
"fmt"

View File

@ -1,26 +0,0 @@
/*
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 parser
type IParsable interface {
next(skipWhitespace bool) *string
peek(skipWhitespace bool) *string
back()
GetLocation() int
}