Add a very basic eval function for symbols

This commit is contained in:
Sameer Rahmani 2020-11-15 19:30:07 +00:00
parent a7457fceb6
commit 95ec031ce6
11 changed files with 124 additions and 65 deletions

View File

@ -29,7 +29,7 @@ var replCmd = &cobra.Command{
Long: `Runs the local Serene's REPL to interact with Serene`,
Run: func(cmd *cobra.Command, args []string) {
// TODO: Get the debug value from a CLI flag
core.REPL(false)
core.REPL(debugMode)
},
}

View File

@ -24,6 +24,8 @@ import (
"github.com/spf13/cobra"
)
var debugMode bool
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "Serene",
@ -54,4 +56,10 @@ func Execute() {
func init() {
cobra.OnInitialize()
rootCmd.PersistentFlags().BoolVar(
&debugMode,
"debug",
false,
"Turns on the debug mode.")
}

View File

@ -30,12 +30,24 @@ import (
func rep(rt *runtime.Runtime, line string) {
ast, err := reader.ReadString(line)
if err != nil {
fmt.Printf("Error: %s", err)
fmt.Println(err)
}
if rt.IsDebugMode() {
fmt.Println("\n### DEBUG ###")
printer.Print(rt, ast)
fmt.Println("#############\n")
}
result, err := Eval(rt, ast)
if err != nil {
fmt.Printf("Error: %s\n", err)
return
}
//eval.Eval(rt, ast)
printer.Print(rt, ast)
printer.Print(rt, result)
}
/** TODO:

View File

@ -0,0 +1,77 @@
/*
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 (
"errors"
"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"
)
func evalForm(rt *runtime.Runtime, scope scope.IScope, form types.IExpr) (types.IExpr, error) {
switch form.GetType() {
case ast.Nil:
case ast.Number:
return form, nil
// Symbol Evaluation Rules:
// * If it's a NS qualified symbol (NSQS), Look it up in the external symbol table of
// the current namespace.
// * 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()
expr := scope.Lookup(symbolName)
if expr == nil {
return nil, fmt.Errorf("Can't resolve symbol '%s' in ns '%s'", symbolName, rt.CurrentNS().GetName())
}
return expr.Value, nil
}
// Default case
return nil, errors.New("not implemented")
}
func Eval(rt *runtime.Runtime, forms types.ASTree) (types.IExpr, error) {
if len(forms) == 0 {
return &types.Nil, nil
}
var ret types.IExpr
for _, form := range forms {
// v is here to shut up the linter
v, err := evalForm(rt, rt.CurrentNS().GetRootScope(), form)
if err != nil {
return nil, err
}
ret = v
}
return ret, nil
}

View File

@ -1,39 +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 eval provides all the necessary functions to eval expressions
package eval
import (
"serene-lang.org/bootstrap/pkg/runtime"
"serene-lang.org/bootstrap/pkg/types"
)
func eval(rt *runtime.Runtime, forms types.ASTree) types.IExpr {
if len(forms) == 0 {
return &types.Nil
}
var ret types.IExpr
for _, form := range forms {
ret = eval_form(rt, rt.CurrentNS().GetRootScope(), form)
}
ret
}

View File

@ -95,15 +95,14 @@ func readRawSymbol(parser IParsable) (types.IExpr, error) {
var symbol string
if c == nil {
return nil, errors.New("unexpected EOF while parsing a symbol")
return nil, errors.New("unexpected enf of file while parsing a symbol")
}
if isValidForSymbol(*c) {
parser.next(false)
symbol = *c
} else {
return nil, fmt.Errorf("unexpected character: got '%s', expected a symbol at %s",
return nil, fmt.Errorf("unexpected character: got '%s', expected a symbol at %d",
*c,
parser.GetLocation(),
)

View File

@ -26,6 +26,6 @@ import (
"serene-lang.org/bootstrap/pkg/types"
)
func Print(rt *runtime.Runtime, ast types.ASTree) {
func Print(rt *runtime.Runtime, ast types.IPrintable) {
fmt.Println(ast.String())
}

View File

@ -41,6 +41,10 @@ type Runtime struct {
debugMode bool
}
func (r *Runtime) IsDebugMode() bool {
return r.debugMode
}
func (r *Runtime) CurrentNS() *namespace.Namespace {
if r.currentNS == "" {
panic("current ns is not set on the runtime.")

View File

@ -21,46 +21,44 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package scope
import (
"fmt"
"serene-lang.org/bootstrap/pkg/types"
)
type IScope interface {
Lookup(k string) (*Binding, error)
Lookup(k string) *Binding
Insert(k string, v types.IExpr, public bool)
}
type Binding struct {
value types.IExpr
public bool
Value types.IExpr
Public bool
}
type Scope struct {
bindings map[string]*Binding
parent IScope
bindings map[string]Binding
parent *Scope
}
func (s *Scope) Lookup(k string) (*Binding, error) {
func (s *Scope) Lookup(k string) *Binding {
v, ok := s.bindings[k]
if ok {
return v, nil
return &v
}
if s.parent != nil {
return s.parent.Lookup(k)
} else {
return nil, fmt.Errorf("can't resolve symbol '%s'", k)
}
return nil
}
func (s *Scope) Insert(k string, v types.IExpr, public bool) {
s.bindings[k] = &Binding{value: v, public: public}
s.bindings[k] = Binding{Value: v, Public: public}
}
func MakeScope(parent *Scope) Scope {
return Scope{
parent: parent,
bindings: map[string]*Binding{},
bindings: map[string]Binding{},
}
}

View File

@ -25,10 +25,6 @@ type Symbol struct {
name string
}
func (s *Symbol) Eval() IExpr {
return &Nil
}
func (s *Symbol) GetType() ast.NodeType {
return ast.Symbol
}
@ -38,6 +34,11 @@ func (s *Symbol) String() string {
return s.name
}
func (s *Symbol) GetName() string {
// TODO: Handle ns qualified symbols here
return s.name
}
func (s *Symbol) ToDebugStr() string {
return s.name
}

View File

@ -40,7 +40,6 @@ type IExpr interface {
ast.ITypable
IPrintable
IDebuggable
Eval() IExpr
}
type Node struct {