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 (
|
const (
|
||||||
Nil NodeType = iota
|
Nil NodeType = iota
|
||||||
|
Nothing
|
||||||
Symbol
|
Symbol
|
||||||
Number
|
Number
|
||||||
List
|
List
|
||||||
Fn
|
Fn
|
||||||
|
Block // Dont' mistake it with block from other programming languages
|
||||||
)
|
)
|
||||||
|
|
||||||
type ILocatable interface {
|
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,19 +78,39 @@ 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 {
|
for {
|
||||||
if forms.GetType() != ast.List {
|
var exprs []IExpr
|
||||||
return EvalForm(rt, scope, forms)
|
|
||||||
|
if expressions.GetType() == ast.Block {
|
||||||
|
if expressions.(*Block).Count() == 0 {
|
||||||
|
return &Nothing, nil
|
||||||
|
}
|
||||||
|
exprs = expressions.(*Block).ToSlice()
|
||||||
|
} else {
|
||||||
|
exprs = []IExpr{expressions}
|
||||||
|
}
|
||||||
|
body:
|
||||||
|
for _, forms := range exprs {
|
||||||
|
|
||||||
|
switch forms.GetType() {
|
||||||
|
case ast.List:
|
||||||
|
|
||||||
|
default:
|
||||||
|
ret, err = EvalForm(rt, scope, forms)
|
||||||
|
break tco // return
|
||||||
|
}
|
||||||
|
|
||||||
|
if forms.(*List).Count() == 0 {
|
||||||
|
ret = &Nil
|
||||||
|
break tco // return
|
||||||
}
|
}
|
||||||
|
|
||||||
list := forms.(*List)
|
list := forms.(*List)
|
||||||
|
|
||||||
if list.Count() == 0 {
|
|
||||||
return &Nil, nil
|
|
||||||
}
|
|
||||||
fmt.Printf("EVAL: %s\n", list)
|
|
||||||
|
|
||||||
rawFirst := list.First()
|
rawFirst := list.First()
|
||||||
sform := ""
|
sform := ""
|
||||||
|
|
||||||
|
@ -99,61 +119,69 @@ func EvalForms(rt *Runtime, scope IScope, forms IExpr) (IExpr, error) {
|
||||||
sform = rawFirst.(*Symbol).GetName()
|
sform = rawFirst.(*Symbol).GetName()
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("sform: %s\n", sform)
|
|
||||||
switch sform {
|
switch sform {
|
||||||
|
|
||||||
case "def":
|
case "def":
|
||||||
return Def(rt, scope, list.Rest().(*List))
|
ret, err = Def(rt, scope, list.Rest().(*List))
|
||||||
|
break tco // return
|
||||||
|
|
||||||
case "fn":
|
case "fn":
|
||||||
return Fn(rt, scope, list.Rest().(*List))
|
ret, err = Fn(rt, scope, list.Rest().(*List))
|
||||||
|
break tco // return
|
||||||
default:
|
default:
|
||||||
exprs, err := EvalForm(rt, scope, list)
|
exprs, e := EvalForm(rt, scope, list)
|
||||||
if err != nil {
|
if e != nil {
|
||||||
return nil, err
|
err = e
|
||||||
|
ret = nil
|
||||||
|
break tco //return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fmt.Printf("<<< %s\n", list)
|
||||||
f := exprs.(*List).First()
|
f := exprs.(*List).First()
|
||||||
|
|
||||||
switch f.GetType() {
|
switch f.GetType() {
|
||||||
case ast.Fn:
|
case ast.Fn:
|
||||||
fn := f.(*Function)
|
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 {
|
if e != nil {
|
||||||
return nil, e
|
err = e
|
||||||
}
|
ret = nil
|
||||||
argList, _ := args.(*List)
|
break body //return
|
||||||
|
|
||||||
scope, err = MakeFnScope(fn.GetScope(), fn.GetParams(), argList)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
}
|
||||||
forms = MakeList(fn.GetBody().ToSlice())
|
//argList, _ := args.(*List)
|
||||||
// case ast.InteropFn:
|
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:
|
default:
|
||||||
lst := exprs.(*List)
|
err = errors.New("don't know how to execute anything beside function")
|
||||||
return lst.ToSlice()[lst.Count()-1], nil
|
ret = nil
|
||||||
// TODO: Fix this ugly error msg
|
break tco
|
||||||
//return nil, fmt.Errorf("can't call anything beside functions yet")
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func Eval(rt *Runtime, forms ASTree) (IExpr, error) {
|
func Eval(rt *Runtime, forms *Block) (IExpr, error) {
|
||||||
if len(forms) == 0 {
|
if forms.Count() == 0 {
|
||||||
return &Nil, nil
|
return &Nothing, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
v, err := EvalForm(rt, rt.CurrentNS().GetRootScope(), MakeList(forms))
|
v, err := EvalForms(rt, rt.CurrentNS().GetRootScope(), forms)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return v.(*List).First(), nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ type Function struct {
|
||||||
name string
|
name string
|
||||||
scope IScope
|
scope IScope
|
||||||
params IColl
|
params IColl
|
||||||
body IColl
|
body *Block
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Function) GetType() ast.NodeType {
|
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)
|
return fmt.Sprintf("<Fn: %s at %p", f.name, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Function) GetBody() IColl {
|
func (f *Function) GetBody() *Block {
|
||||||
return f.body
|
return f.body
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeFunction(scope IScope, params IColl, body IColl) *Function {
|
func MakeFunction(scope IScope, params IColl, body *Block) *Function {
|
||||||
return &Function{
|
return &Function{
|
||||||
scope: scope,
|
scope: scope,
|
||||||
params: params,
|
params: params,
|
||||||
|
|
|
@ -24,10 +24,6 @@ type NilType struct{}
|
||||||
|
|
||||||
var Nil = NilType{}
|
var Nil = NilType{}
|
||||||
|
|
||||||
func (n NilType) Eval() IExpr {
|
|
||||||
return &Nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (n NilType) GetType() ast.NodeType {
|
func (n NilType) GetType() ast.NodeType {
|
||||||
return ast.Nil
|
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{
|
parser := StringParser{
|
||||||
buffer: strings.Split(input, ""),
|
buffer: strings.Split(input, ""),
|
||||||
pos: 0,
|
pos: 0,
|
||||||
|
@ -350,8 +350,8 @@ func ParseToAST(input string) (ASTree, error) {
|
||||||
break
|
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
|
package core
|
||||||
|
|
||||||
func ReadString(input string) (ASTree, error) {
|
func ReadString(input string) (*Block, error) {
|
||||||
return ParseToAST(input)
|
return ParseToAST(input)
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,7 @@ func Fn(rt *Runtime, scope IScope, args *List) (IExpr, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var params IColl
|
var params IColl
|
||||||
body := MakeEmptyList()
|
body := MakeEmptyBlock()
|
||||||
|
|
||||||
arguments := args.First()
|
arguments := args.First()
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ func Fn(rt *Runtime, scope IScope, args *List) (IExpr, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.Count() > 1 {
|
if args.Count() > 1 {
|
||||||
body = args.Rest().(*List)
|
body.SetContent(args.Rest().(*List).ToSlice())
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeFunction(scope, params, body), nil
|
return MakeFunction(scope, params, body), nil
|
||||||
|
|
|
@ -22,7 +22,6 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"serene-lang.org/bootstrap/pkg/ast"
|
"serene-lang.org/bootstrap/pkg/ast"
|
||||||
)
|
)
|
||||||
|
@ -49,16 +48,3 @@ type Node struct {
|
||||||
func (n Node) GetLocation() int {
|
func (n Node) GetLocation() int {
|
||||||
return n.location
|
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