From 28d7be6efdbccbe4e521804d3f2a59c0813ce8b0 Mon Sep 17 00:00:00 2001 From: Sameer Rahmani Date: Thu, 19 Nov 2020 22:17:50 +0000 Subject: [PATCH] Create the Block struct to accommodate function bodies --- bootstrap/pkg/ast/ast.go | 2 + bootstrap/pkg/core/block.go | 79 ++++++++++++++++++ bootstrap/pkg/core/eval.go | 144 ++++++++++++++++++++------------- bootstrap/pkg/core/function.go | 6 +- bootstrap/pkg/core/nil.go | 4 - bootstrap/pkg/core/nothing.go | 41 ++++++++++ bootstrap/pkg/core/parser.go | 8 +- bootstrap/pkg/core/reader.go | 2 +- bootstrap/pkg/core/sforms.go | 4 +- bootstrap/pkg/core/types.go | 14 ---- 10 files changed, 218 insertions(+), 86 deletions(-) create mode 100644 bootstrap/pkg/core/block.go create mode 100644 bootstrap/pkg/core/nothing.go diff --git a/bootstrap/pkg/ast/ast.go b/bootstrap/pkg/ast/ast.go index 1913786..b930ac4 100644 --- a/bootstrap/pkg/ast/ast.go +++ b/bootstrap/pkg/ast/ast.go @@ -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 { diff --git a/bootstrap/pkg/core/block.go b/bootstrap/pkg/core/block.go new file mode 100644 index 0000000..0a93723 --- /dev/null +++ b/bootstrap/pkg/core/block.go @@ -0,0 +1,79 @@ +/* + Serene --- Yet an other Lisp + +Copyright (c) 2020 Sameer Rahmani + +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 . +*/ + +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, + } +} diff --git a/bootstrap/pkg/core/eval.go b/bootstrap/pkg/core/eval.go index c32f3ac..fed1cff 100644 --- a/bootstrap/pkg/core/eval.go +++ b/bootstrap/pkg/core/eval.go @@ -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 } diff --git a/bootstrap/pkg/core/function.go b/bootstrap/pkg/core/function.go index c6912f1..d2ca82b 100644 --- a/bootstrap/pkg/core/function.go +++ b/bootstrap/pkg/core/function.go @@ -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(" + +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 . +*/ + +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 "" +} diff --git a/bootstrap/pkg/core/parser.go b/bootstrap/pkg/core/parser.go index 3cb395c..143632f 100644 --- a/bootstrap/pkg/core/parser.go +++ b/bootstrap/pkg/core/parser.go @@ -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 } diff --git a/bootstrap/pkg/core/reader.go b/bootstrap/pkg/core/reader.go index b695ae3..2217fa3 100644 --- a/bootstrap/pkg/core/reader.go +++ b/bootstrap/pkg/core/reader.go @@ -18,6 +18,6 @@ along with this program. If not, see . package core -func ReadString(input string) (ASTree, error) { +func ReadString(input string) (*Block, error) { return ParseToAST(input) } diff --git a/bootstrap/pkg/core/sforms.go b/bootstrap/pkg/core/sforms.go index a920ad4..dd8c387 100644 --- a/bootstrap/pkg/core/sforms.go +++ b/bootstrap/pkg/core/sforms.go @@ -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 diff --git a/bootstrap/pkg/core/types.go b/bootstrap/pkg/core/types.go index 0731171..cde07bf 100644 --- a/bootstrap/pkg/core/types.go +++ b/bootstrap/pkg/core/types.go @@ -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, " ") -}