Add a very basic eval function for symbols
This commit is contained in:
parent
a7457fceb6
commit
95ec031ce6
|
@ -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)
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -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.")
|
||||
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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(),
|
||||
)
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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{},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -40,7 +40,6 @@ type IExpr interface {
|
|||
ast.ITypable
|
||||
IPrintable
|
||||
IDebuggable
|
||||
Eval() IExpr
|
||||
}
|
||||
|
||||
type Node struct {
|
||||
|
|
Loading…
Reference in New Issue