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`,
|
Long: `Runs the local Serene's REPL to interact with Serene`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
// TODO: Get the debug value from a CLI flag
|
// TODO: Get the debug value from a CLI flag
|
||||||
core.REPL(false)
|
core.REPL(debugMode)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var debugMode bool
|
||||||
|
|
||||||
// rootCmd represents the base command when called without any subcommands
|
// rootCmd represents the base command when called without any subcommands
|
||||||
var rootCmd = &cobra.Command{
|
var rootCmd = &cobra.Command{
|
||||||
Use: "Serene",
|
Use: "Serene",
|
||||||
|
@ -54,4 +56,10 @@ func Execute() {
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
cobra.OnInitialize()
|
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) {
|
func rep(rt *runtime.Runtime, line string) {
|
||||||
ast, err := reader.ReadString(line)
|
ast, err := reader.ReadString(line)
|
||||||
|
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
//eval.Eval(rt, ast)
|
|
||||||
printer.Print(rt, ast)
|
printer.Print(rt, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** TODO:
|
/** 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
|
var symbol string
|
||||||
|
|
||||||
if c == nil {
|
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) {
|
if isValidForSymbol(*c) {
|
||||||
parser.next(false)
|
parser.next(false)
|
||||||
symbol = *c
|
symbol = *c
|
||||||
} else {
|
} else {
|
||||||
|
return nil, fmt.Errorf("unexpected character: got '%s', expected a symbol at %d",
|
||||||
return nil, fmt.Errorf("unexpected character: got '%s', expected a symbol at %s",
|
|
||||||
*c,
|
*c,
|
||||||
parser.GetLocation(),
|
parser.GetLocation(),
|
||||||
)
|
)
|
||||||
|
|
|
@ -26,6 +26,6 @@ import (
|
||||||
"serene-lang.org/bootstrap/pkg/types"
|
"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())
|
fmt.Println(ast.String())
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,10 @@ type Runtime struct {
|
||||||
debugMode bool
|
debugMode bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *Runtime) IsDebugMode() bool {
|
||||||
|
return r.debugMode
|
||||||
|
}
|
||||||
|
|
||||||
func (r *Runtime) CurrentNS() *namespace.Namespace {
|
func (r *Runtime) CurrentNS() *namespace.Namespace {
|
||||||
if r.currentNS == "" {
|
if r.currentNS == "" {
|
||||||
panic("current ns is not set on the runtime.")
|
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
|
package scope
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"serene-lang.org/bootstrap/pkg/types"
|
"serene-lang.org/bootstrap/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type IScope interface {
|
type IScope interface {
|
||||||
Lookup(k string) (*Binding, error)
|
Lookup(k string) *Binding
|
||||||
Insert(k string, v types.IExpr, public bool)
|
Insert(k string, v types.IExpr, public bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Binding struct {
|
type Binding struct {
|
||||||
value types.IExpr
|
Value types.IExpr
|
||||||
public bool
|
Public bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type Scope struct {
|
type Scope struct {
|
||||||
bindings map[string]*Binding
|
bindings map[string]Binding
|
||||||
parent IScope
|
parent *Scope
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) Lookup(k string) (*Binding, error) {
|
func (s *Scope) Lookup(k string) *Binding {
|
||||||
v, ok := s.bindings[k]
|
v, ok := s.bindings[k]
|
||||||
if ok {
|
if ok {
|
||||||
return v, nil
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.parent != nil {
|
if s.parent != nil {
|
||||||
return s.parent.Lookup(k)
|
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) {
|
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 {
|
func MakeScope(parent *Scope) Scope {
|
||||||
return Scope{
|
return Scope{
|
||||||
parent: parent,
|
parent: parent,
|
||||||
bindings: map[string]*Binding{},
|
bindings: map[string]Binding{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,10 +25,6 @@ type Symbol struct {
|
||||||
name string
|
name string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Symbol) Eval() IExpr {
|
|
||||||
return &Nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Symbol) GetType() ast.NodeType {
|
func (s *Symbol) GetType() ast.NodeType {
|
||||||
return ast.Symbol
|
return ast.Symbol
|
||||||
}
|
}
|
||||||
|
@ -38,6 +34,11 @@ func (s *Symbol) String() string {
|
||||||
return s.name
|
return s.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Symbol) GetName() string {
|
||||||
|
// TODO: Handle ns qualified symbols here
|
||||||
|
return s.name
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Symbol) ToDebugStr() string {
|
func (s *Symbol) ToDebugStr() string {
|
||||||
return s.name
|
return s.name
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ type IExpr interface {
|
||||||
ast.ITypable
|
ast.ITypable
|
||||||
IPrintable
|
IPrintable
|
||||||
IDebuggable
|
IDebuggable
|
||||||
Eval() IExpr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Node struct {
|
type Node struct {
|
||||||
|
|
Loading…
Reference in New Issue