Create the Block struct to accommodate function bodies
This commit is contained in:
parent
680017f0ce
commit
28d7be6efd
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 ""
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, " ")
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue