Restructure the source tree to get around circular dep issue
This commit is contained in:
parent
cba74e29af
commit
ad37f02742
|
@ -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
|
|
@ -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("> ")
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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"
|
|
@ -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{},
|
||||
}
|
|
@ -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"
|
||||
|
|
@ -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"
|
|
@ -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,
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
|
@ -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}
|
||||
}
|
||||
|
|
@ -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"
|
||||
|
|
@ -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"
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue