Create the Block struct to accommodate function bodies

This commit is contained in:
Sameer Rahmani 2020-11-19 22:17:50 +00:00
parent 680017f0ce
commit 28d7be6efd
10 changed files with 218 additions and 86 deletions

View File

@ -24,10 +24,12 @@ type NodeType int
const (
Nil NodeType = iota
Nothing
Symbol
Number
List
Fn
Block // Dont' mistake it with block from other programming languages
)
type ILocatable interface {

View File

@ -0,0 +1,79 @@
/*
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
import (
"fmt"
"strings"
"serene-lang.org/bootstrap/pkg/ast"
)
type Block struct {
body []IExpr
}
func (b *Block) GetType() ast.NodeType {
return ast.Block
}
func (b *Block) String() string {
var strs []string
for _, e := range b.body {
strs = append(strs, e.String())
}
return strings.Join(strs, " ")
}
func (b *Block) ToDebugStr() string {
return fmt.Sprintf("%#v", b)
}
func (b *Block) GetLocation() int {
if len(b.body) > 0 {
return b.body[0].GetLocation()
}
return -1
}
func (b *Block) ToSlice() []IExpr {
return b.body
}
func (b *Block) SetContent(body []IExpr) {
b.body = body
}
func (b *Block) Append(form IExpr) {
b.body = append(b.body, form)
}
func (b *Block) Count() int {
return len(b.body)
}
func MakeEmptyBlock() *Block {
return &Block{}
}
func MakeBlock(body []IExpr) *Block {
return &Block{
body: body,
}
}

View File

@ -78,82 +78,110 @@ func EvalForm(rt *Runtime, scope IScope, form IExpr) (IExpr, error) {
}
func EvalForms(rt *Runtime, scope IScope, forms IExpr) (IExpr, error) {
func EvalForms(rt *Runtime, scope IScope, expressions IExpr) (IExpr, error) {
var ret IExpr
var err error
tco:
for {
if forms.GetType() != ast.List {
return EvalForm(rt, scope, forms)
}
var exprs []IExpr
list := forms.(*List)
if list.Count() == 0 {
return &Nil, nil
}
fmt.Printf("EVAL: %s\n", list)
rawFirst := list.First()
sform := ""
// Handling special forms
if rawFirst.GetType() == ast.Symbol {
sform = rawFirst.(*Symbol).GetName()
}
fmt.Printf("sform: %s\n", sform)
switch sform {
case "def":
return Def(rt, scope, list.Rest().(*List))
case "fn":
return Fn(rt, scope, list.Rest().(*List))
default:
exprs, err := EvalForm(rt, scope, list)
if err != nil {
return nil, err
if expressions.GetType() == ast.Block {
if expressions.(*Block).Count() == 0 {
return &Nothing, nil
}
f := exprs.(*List).First()
exprs = expressions.(*Block).ToSlice()
} else {
exprs = []IExpr{expressions}
}
body:
for _, forms := range exprs {
switch f.GetType() {
case ast.Fn:
fn := f.(*Function)
// Since we're passing a List to evaluate the
// result has to be a list. ( Rest returns a List )
args, e := EvalForm(rt, scope, list.Rest().(*List))
if e != nil {
return nil, e
}
argList, _ := args.(*List)
switch forms.GetType() {
case ast.List:
scope, err = MakeFnScope(fn.GetScope(), fn.GetParams(), argList)
if err != nil {
return nil, err
}
forms = MakeList(fn.GetBody().ToSlice())
// case ast.InteropFn:
default:
lst := exprs.(*List)
return lst.ToSlice()[lst.Count()-1], nil
// TODO: Fix this ugly error msg
//return nil, fmt.Errorf("can't call anything beside functions yet")
ret, err = EvalForm(rt, scope, forms)
break tco // return
}
if forms.(*List).Count() == 0 {
ret = &Nil
break tco // return
}
list := forms.(*List)
rawFirst := list.First()
sform := ""
// Handling special forms
if rawFirst.GetType() == ast.Symbol {
sform = rawFirst.(*Symbol).GetName()
}
switch sform {
case "def":
ret, err = Def(rt, scope, list.Rest().(*List))
break tco // return
case "fn":
ret, err = Fn(rt, scope, list.Rest().(*List))
break tco // return
default:
exprs, e := EvalForm(rt, scope, list)
if e != nil {
err = e
ret = nil
break tco //return
}
fmt.Printf("<<< %s\n", list)
f := exprs.(*List).First()
switch f.GetType() {
case ast.Fn:
fn := f.(*Function)
if e != nil {
err = e
ret = nil
break body //return
}
//argList, _ := args.(*List)
argList := exprs.(*List).Rest().(*List)
scope, e = MakeFnScope(fn.GetScope(), fn.GetParams(), argList)
if e != nil {
err = e
ret = nil
break body //return
}
expressions = fn.GetBody()
continue tco
default:
err = errors.New("don't know how to execute anything beside function")
ret = nil
break tco
}
}
}
}
return ret, err
}
func Eval(rt *Runtime, forms ASTree) (IExpr, error) {
if len(forms) == 0 {
return &Nil, nil
func Eval(rt *Runtime, forms *Block) (IExpr, error) {
if forms.Count() == 0 {
return &Nothing, nil
}
v, err := EvalForm(rt, rt.CurrentNS().GetRootScope(), MakeList(forms))
v, err := EvalForms(rt, rt.CurrentNS().GetRootScope(), forms)
if err != nil {
return nil, err
}
return v.(*List).First(), nil
return v, nil
}

View File

@ -34,7 +34,7 @@ type Function struct {
name string
scope IScope
params IColl
body IColl
body *Block
}
func (f *Function) GetType() ast.NodeType {
@ -62,11 +62,11 @@ func (f *Function) ToDebugStr() string {
return fmt.Sprintf("<Fn: %s at %p", f.name, f)
}
func (f *Function) GetBody() IColl {
func (f *Function) GetBody() *Block {
return f.body
}
func MakeFunction(scope IScope, params IColl, body IColl) *Function {
func MakeFunction(scope IScope, params IColl, body *Block) *Function {
return &Function{
scope: scope,
params: params,

View File

@ -24,10 +24,6 @@ type NilType struct{}
var Nil = NilType{}
func (n NilType) Eval() IExpr {
return &Nil
}
func (n NilType) GetType() ast.NodeType {
return ast.Nil
}

View File

@ -0,0 +1,41 @@
/*
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
import "serene-lang.org/bootstrap/pkg/ast"
type NothingType struct{}
var Nothing = NothingType{}
func (n NothingType) GetType() ast.NodeType {
return ast.Nothing
}
func (n NothingType) GetLocation() int {
return -1
}
func (n NothingType) String() string {
return ""
}
func (n NothingType) ToDebugStr() string {
return ""
}

View File

@ -332,9 +332,9 @@ loop:
}
func ParseToAST(input string) (ASTree, error) {
func ParseToAST(input string) (*Block, error) {
var ast ASTree
var ast Block
parser := StringParser{
buffer: strings.Split(input, ""),
pos: 0,
@ -350,8 +350,8 @@ func ParseToAST(input string) (ASTree, error) {
break
}
ast = append(ast, expr)
ast.Append(expr)
}
return ast, nil
return &ast, nil
}

View File

@ -18,6 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package core
func ReadString(input string) (ASTree, error) {
func ReadString(input string) (*Block, error) {
return ParseToAST(input)
}

View File

@ -31,7 +31,7 @@ func Fn(rt *Runtime, scope IScope, args *List) (IExpr, error) {
}
var params IColl
body := MakeEmptyList()
body := MakeEmptyBlock()
arguments := args.First()
@ -42,7 +42,7 @@ func Fn(rt *Runtime, scope IScope, args *List) (IExpr, error) {
}
if args.Count() > 1 {
body = args.Rest().(*List)
body.SetContent(args.Rest().(*List).ToSlice())
}
return MakeFunction(scope, params, body), nil

View File

@ -22,7 +22,6 @@ package core
import (
"fmt"
"strings"
"serene-lang.org/bootstrap/pkg/ast"
)
@ -49,16 +48,3 @@ type Node struct {
func (n Node) GetLocation() int {
return n.location
}
type ASTree []IExpr
func (t ASTree) String() string {
var result []string
result = append(result, "AST[")
for _, node := range t {
result = append(result, node.String())
}
result = append(result, "]")
return strings.Join(result, " ")
}