[Bootstrap] Fix the order and location on the traceback
In order to fix this issue I had to make many minor tweaks including reordering the traceback and the way we pass down nodes.
This commit is contained in:
parent
0cc7646e3a
commit
c2d4273319
|
@ -63,7 +63,7 @@ func (s *Source) GetPos(start, end int) *string {
|
||||||
}
|
}
|
||||||
func (s *Source) GetLine(linenum int) string {
|
func (s *Source) GetLine(linenum int) string {
|
||||||
lines := strings.Split(strings.Join(*s.Buffer, ""), "\n")
|
lines := strings.Split(strings.Join(*s.Buffer, ""), "\n")
|
||||||
if linenum > 0 && linenum < len(lines) {
|
if linenum > 0 && linenum <= len(lines) {
|
||||||
return lines[linenum-1]
|
return lines[linenum-1]
|
||||||
}
|
}
|
||||||
return "----"
|
return "----"
|
||||||
|
@ -107,6 +107,21 @@ func (s *Source) LineNumberFor(pos int) int {
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var builtinSource *Source
|
||||||
|
|
||||||
|
func GetBuiltinSource() *Source {
|
||||||
|
if builtinSource == nil {
|
||||||
|
buf := strings.Split("builtin", "")
|
||||||
|
lineindex := []int{len(buf) - 1}
|
||||||
|
builtinSource = &Source{
|
||||||
|
Buffer: &buf,
|
||||||
|
Path: "Builtin",
|
||||||
|
LineIndex: &lineindex,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return builtinSource
|
||||||
|
}
|
||||||
|
|
||||||
type Location struct {
|
type Location struct {
|
||||||
start int
|
start int
|
||||||
end int
|
end int
|
||||||
|
@ -125,7 +140,10 @@ func (l *Location) GetEnd() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Location) GetSource() *Source {
|
func (l *Location) GetSource() *Source {
|
||||||
return &l.source
|
if l.IsKnownLocaiton() {
|
||||||
|
return &l.source
|
||||||
|
}
|
||||||
|
return GetBuiltinSource()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Location) IncStart(x int) {
|
func (l *Location) IncStart(x int) {
|
||||||
|
|
|
@ -22,10 +22,10 @@ package core
|
||||||
// the language which are implemented in Go
|
// the language which are implemented in Go
|
||||||
var BUILTINS = map[string]NativeFunction{
|
var BUILTINS = map[string]NativeFunction{
|
||||||
"pr": MakeNativeFn("pr", PrNativeFn),
|
"pr": MakeNativeFn("pr", PrNativeFn),
|
||||||
"prn": MakeNativeFn("pr", PrnNativeFn),
|
"prn": MakeNativeFn("prn", PrnNativeFn),
|
||||||
"print": MakeNativeFn("print", PrintNativeFn),
|
"print": MakeNativeFn("print", PrintNativeFn),
|
||||||
"println": MakeNativeFn("println", PrintlnNativeFn),
|
"println": MakeNativeFn("println", PrintlnNativeFn),
|
||||||
"require": MakeNativeFn("print", RequireNativeFn),
|
"require": MakeNativeFn("require", RequireNativeFn),
|
||||||
"hash": MakeNativeFn("hash", HashNativeFn),
|
"hash": MakeNativeFn("hash", HashNativeFn),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,10 @@ type CallStack struct {
|
||||||
count uint
|
count uint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Frame) String() string {
|
||||||
|
return fmt.Sprintf("<Frame: FN: %s, Count: %d Caller: \n%s\n>", f.Fn, f.Count, f.Caller)
|
||||||
|
}
|
||||||
|
|
||||||
func (c *CallStack) Count() uint {
|
func (c *CallStack) Count() uint {
|
||||||
return c.count
|
return c.count
|
||||||
}
|
}
|
||||||
|
@ -158,7 +162,8 @@ func (c *CallStack) ToTraceBack() *TraceBack {
|
||||||
if item == nil {
|
if item == nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
tr = append(tr, &item.data)
|
// TODO: This doesn't seem efficient. Fix it.
|
||||||
|
tr = append([]*Frame{&item.data}, tr...)
|
||||||
item = item.prev
|
item = item.prev
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -82,19 +82,20 @@ func evalForm(rt *Runtime, scope IScope, form IExpr) (IExpr, IError) {
|
||||||
return MakeNil(MakeNodeFromExpr(form)), nil
|
return MakeNil(MakeNodeFromExpr(form)), nil
|
||||||
default:
|
default:
|
||||||
var expr *Binding
|
var expr *Binding
|
||||||
|
ns := scope.GetNS(rt)
|
||||||
if sym.IsNSQualified() {
|
if sym.IsNSQualified() {
|
||||||
// Whether a namespace with the given alias loaded or not
|
// Whether a namespace with the given alias loaded or not
|
||||||
if !rt.CurrentNS().hasExternal(sym.GetNSPart()) {
|
if !ns.hasExternal(sym.GetNSPart()) {
|
||||||
return nil, MakeError(rt, sym,
|
return nil, MakeError(rt, sym,
|
||||||
fmt.Sprintf("Namespace '%s' is no loaded", sym.GetNSPart()),
|
fmt.Sprintf("Namespace '%s' is no loaded", sym.GetNSPart()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
expr = rt.CurrentNS().LookupGlobal(rt, sym)
|
expr = ns.LookupGlobal(rt, sym)
|
||||||
nsName = sym.GetNSPart()
|
nsName = sym.GetNSPart()
|
||||||
} else {
|
} else {
|
||||||
expr = scope.Lookup(rt, symbolName)
|
expr = scope.Lookup(rt, symbolName)
|
||||||
nsName = rt.CurrentNS().GetName()
|
nsName = ns.GetName()
|
||||||
}
|
}
|
||||||
|
|
||||||
if expr == nil {
|
if expr == nil {
|
||||||
|
@ -199,7 +200,7 @@ tco:
|
||||||
}
|
}
|
||||||
|
|
||||||
if rt.IsDebugMode() {
|
if rt.IsDebugMode() {
|
||||||
fmt.Printf("[DEBUG] Evaluating forms in NS: %s, Forms: %s\n", rt.CurrentNS().GetName(), forms)
|
fmt.Printf("[DEBUG] Evaluating forms in NS: %s, Forms: %s\n", scope.GetNS(rt).GetName(), forms)
|
||||||
fmt.Printf("[DEBUG] * State: I: %d, Exprs: %s\n", i, exprs)
|
fmt.Printf("[DEBUG] * State: I: %d, Exprs: %s\n", i, exprs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,7 +395,7 @@ tco:
|
||||||
// * The rest of the arguments will form a block that acts as the
|
// * The rest of the arguments will form a block that acts as the
|
||||||
// body of the macro.
|
// body of the macro.
|
||||||
case "defmacro":
|
case "defmacro":
|
||||||
ret, err = DefMacro(rt, scope, list.Rest().(*List))
|
ret, err = DefMacro(rt, scope, list)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -511,7 +512,7 @@ tco:
|
||||||
return nil, MakeError(rt, list, "'let' needs at list 1 aruments")
|
return nil, MakeError(rt, list, "'let' needs at list 1 aruments")
|
||||||
}
|
}
|
||||||
|
|
||||||
letScope := MakeScope(scope.(*Scope))
|
letScope := MakeScope(rt, scope.(*Scope), nil)
|
||||||
|
|
||||||
// Since we're using IColl for the bindings, we can use either lists
|
// Since we're using IColl for the bindings, we can use either lists
|
||||||
// or vectors or even hashmaps for bindings
|
// or vectors or even hashmaps for bindings
|
||||||
|
@ -565,6 +566,7 @@ tco:
|
||||||
default:
|
default:
|
||||||
// Evaluating all the elements of the list
|
// Evaluating all the elements of the list
|
||||||
listExprs, e := evalForm(rt, scope, list)
|
listExprs, e := evalForm(rt, scope, list)
|
||||||
|
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return nil, e
|
return nil, e
|
||||||
}
|
}
|
||||||
|
@ -589,8 +591,8 @@ tco:
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return nil, e
|
return nil, e
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.Stack.Push(list, fn)
|
rt.Stack.Push(list, fn)
|
||||||
|
|
||||||
body := append(
|
body := append(
|
||||||
fn.GetBody().ToSlice(),
|
fn.GetBody().ToSlice(),
|
||||||
// Add the PopStack instruction to clean up the stack after
|
// Add the PopStack instruction to clean up the stack after
|
||||||
|
@ -607,6 +609,7 @@ tco:
|
||||||
fn := f.(*NativeFunction)
|
fn := f.(*NativeFunction)
|
||||||
|
|
||||||
rt.Stack.Push(list, fn)
|
rt.Stack.Push(list, fn)
|
||||||
|
|
||||||
ret, err = fn.Apply(
|
ret, err = fn.Apply(
|
||||||
rt,
|
rt,
|
||||||
scope,
|
scope,
|
||||||
|
|
|
@ -157,7 +157,7 @@ func MakeFunction(n Node, scope IScope, params IColl, body *Block) *Function {
|
||||||
// MakeFnScope a new scope for the body of a function. It binds the `bindings`
|
// MakeFnScope a new scope for the body of a function. It binds the `bindings`
|
||||||
// to the given `values`.
|
// to the given `values`.
|
||||||
func MakeFnScope(rt *Runtime, parent IScope, bindings IColl, values IColl) (*Scope, IError) {
|
func MakeFnScope(rt *Runtime, parent IScope, bindings IColl, values IColl) (*Scope, IError) {
|
||||||
scope := MakeScope(parent.(*Scope))
|
scope := MakeScope(rt, parent.(*Scope), nil)
|
||||||
// TODO: Implement destructuring
|
// TODO: Implement destructuring
|
||||||
binds := bindings.ToSlice()
|
binds := bindings.ToSlice()
|
||||||
exprs := values.ToSlice()
|
exprs := values.ToSlice()
|
||||||
|
@ -169,6 +169,16 @@ func MakeFnScope(rt *Runtime, parent IScope, bindings IColl, values IColl) (*Sco
|
||||||
if lastBinding.GetType() == ast.Symbol && lastBinding.(*Symbol).IsRestable() {
|
if lastBinding.GetType() == ast.Symbol && lastBinding.(*Symbol).IsRestable() {
|
||||||
numberOfBindings = len(binds) - 1
|
numberOfBindings = len(binds) - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if lastBinding.GetType() == ast.Symbol && !lastBinding.(*Symbol).IsRestable() && numberOfBindings < len(exprs) {
|
||||||
|
return nil, MakeSemanticError(
|
||||||
|
rt,
|
||||||
|
values.(IExpr),
|
||||||
|
errors.E0002,
|
||||||
|
fmt.Sprintf("expected '%d' arguments, got '%d'.", bindings.Count(), values.Count()),
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if numberOfBindings > len(exprs) {
|
if numberOfBindings > len(exprs) {
|
||||||
|
@ -201,7 +211,7 @@ func MakeFnScope(rt *Runtime, parent IScope, bindings IColl, values IColl) (*Sco
|
||||||
// next.
|
// next.
|
||||||
rest := MakeEmptyList(MakeNodeFromExpr(binds[i]))
|
rest := MakeEmptyList(MakeNodeFromExpr(binds[i]))
|
||||||
|
|
||||||
if i == len(exprs)-1 {
|
if i <= len(exprs)-1 {
|
||||||
// If the number of values matches the number of bindings
|
// If the number of values matches the number of bindings
|
||||||
// or it is more than that create a list from them
|
// or it is more than that create a list from them
|
||||||
// to pass it to the last argument that has to be Restable (e.g &x)
|
// to pass it to the last argument that has to be Restable (e.g &x)
|
||||||
|
@ -260,6 +270,7 @@ func (f *NativeFunction) Apply(rt *Runtime, scope IScope, n Node, args *List) (I
|
||||||
|
|
||||||
func MakeNativeFn(name string, f nativeFnHandler) NativeFunction {
|
func MakeNativeFn(name string, f nativeFnHandler) NativeFunction {
|
||||||
return NativeFunction{
|
return NativeFunction{
|
||||||
|
Node: MakeNodeFromLocation(ast.MakeUnknownLocation()),
|
||||||
name: name,
|
name: name,
|
||||||
fn: f,
|
fn: f,
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import "serene-lang.org/bootstrap/pkg/ast"
|
// TODO:
|
||||||
|
// * Add support for `before` and `after` state in macroexpantion
|
||||||
|
// and call stack. So in case of an error. Users should be able
|
||||||
|
// to see the forms before and after expansion.
|
||||||
|
|
||||||
|
import (
|
||||||
|
"serene-lang.org/bootstrap/pkg/ast"
|
||||||
|
)
|
||||||
|
|
||||||
// Serene macros are in fact functions with the `isMacro` flag set to true.
|
// Serene macros are in fact functions with the `isMacro` flag set to true.
|
||||||
// We have only normal macro implementation in bootstrap version of serene in
|
// We have only normal macro implementation in bootstrap version of serene in
|
||||||
|
@ -84,6 +91,7 @@ func macroexpand(rt *Runtime, scope IScope, form IExpr) (IExpr, IError) {
|
||||||
var macro *Function
|
var macro *Function
|
||||||
var e IError
|
var e IError
|
||||||
ok := false
|
ok := false
|
||||||
|
//form := expr
|
||||||
|
|
||||||
for {
|
for {
|
||||||
macro, ok = isMacroCall(rt, scope, form)
|
macro, ok = isMacroCall(rt, scope, form)
|
||||||
|
|
|
@ -160,7 +160,7 @@ func requireNS(rt *Runtime, ns *Symbol) (*Namespace, IError) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace := MakeNS(ns.GetName(), source)
|
namespace := MakeNS(rt, ns.GetName(), source)
|
||||||
namespace.setForms(body)
|
namespace.setForms(body)
|
||||||
|
|
||||||
return &namespace, nil
|
return &namespace, nil
|
||||||
|
@ -252,8 +252,9 @@ func RequireNamespace(rt *Runtime, namespace IExpr) (IExpr, IError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeNS creates a new namespace with the given `name` and `source`
|
// MakeNS creates a new namespace with the given `name` and `source`
|
||||||
func MakeNS(name string, source string) Namespace {
|
func MakeNS(rt *Runtime, name string, source string) Namespace {
|
||||||
s := MakeScope(nil)
|
s := MakeScope(rt, nil, &name)
|
||||||
|
|
||||||
return Namespace{
|
return Namespace{
|
||||||
name: name,
|
name: name,
|
||||||
rootScope: *s,
|
rootScope: *s,
|
||||||
|
|
|
@ -158,7 +158,7 @@ func (d Double) F64() float64 {
|
||||||
return d.value
|
return d.value
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeNumberFromStr(strValue string, isDouble bool) (INumber, error) {
|
func MakeNumberFromStr(n Node, strValue string, isDouble bool) (INumber, error) {
|
||||||
var ret INumber
|
var ret INumber
|
||||||
|
|
||||||
if isDouble {
|
if isDouble {
|
||||||
|
@ -169,6 +169,7 @@ func MakeNumberFromStr(strValue string, isDouble bool) (INumber, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = Double{
|
ret = Double{
|
||||||
|
Node: n,
|
||||||
value: v,
|
value: v,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -178,6 +179,7 @@ func MakeNumberFromStr(strValue string, isDouble bool) (INumber, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = Integer{
|
ret = Integer{
|
||||||
|
Node: n,
|
||||||
value: v,
|
value: v,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -341,8 +341,9 @@ func readNumber(parser IParsable, neg bool) (IExpr, IError) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
n := MakeSinglePointNode(parser.GetSource(), parser.GetLocation())
|
||||||
value, err := MakeNumberFromStr(result, isDouble)
|
n.location.DecStart(len(result))
|
||||||
|
value, err := MakeNumberFromStr(n, result, isDouble)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, makeErrorFromError(parser, err)
|
return nil, makeErrorFromError(parser, err)
|
||||||
|
@ -425,6 +426,7 @@ func readList(parser IParsable) (IExpr, IError) {
|
||||||
|
|
||||||
node.location.DecStart(1)
|
node.location.DecStart(1)
|
||||||
node.location.IncEnd(1)
|
node.location.IncEnd(1)
|
||||||
|
|
||||||
return MakeList(*node, list), nil
|
return MakeList(*node, list), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -85,9 +85,10 @@ func printError(rt *Runtime, err IError, stage int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
color.Yellow.Printf(
|
color.Yellow.Printf(
|
||||||
"%d: At '%s'\n",
|
"%d: At '%s':%d\n",
|
||||||
stage,
|
stage,
|
||||||
source.Path,
|
source.Path,
|
||||||
|
source.LineNumberFor(loc.GetStart()),
|
||||||
)
|
)
|
||||||
|
|
||||||
color.White.Printf("%s\n", lines)
|
color.White.Printf("%s\n", lines)
|
||||||
|
@ -115,11 +116,17 @@ func printErrorWithTraceBack(rt *Runtime, err IError) {
|
||||||
|
|
||||||
var lines string
|
var lines string
|
||||||
for i := startline; i <= endline; i++ {
|
for i := startline; i <= endline; i++ {
|
||||||
fLoc := t.Fn.GetLocation()
|
fLoc := t.Caller.GetLocation()
|
||||||
line := fLoc.GetSource().GetLine(i)
|
|
||||||
if line != "----" {
|
if fLoc.IsKnownLocaiton() {
|
||||||
lines += fmt.Sprintf("%d:\t%s\n", i, line)
|
line := fLoc.GetSource().GetLine(i)
|
||||||
|
if line != "----" {
|
||||||
|
lines += fmt.Sprintf("%d:\t%s\n", i, line)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lines += "Builtin\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
color.Yellow.Printf(
|
color.Yellow.Printf(
|
||||||
|
@ -137,6 +144,7 @@ func printErrorWithTraceBack(rt *Runtime, err IError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrintError(rt *Runtime, err IError) {
|
func PrintError(rt *Runtime, err IError) {
|
||||||
|
|
||||||
switch err.GetErrType() {
|
switch err.GetErrType() {
|
||||||
case SyntaxError, SemanticError:
|
case SyntaxError, SemanticError:
|
||||||
printError(rt, err, 0)
|
printError(rt, err, 0)
|
||||||
|
|
|
@ -115,7 +115,7 @@ func (r *Runtime) GetNS(ns string) (*Namespace, bool) {
|
||||||
// CreateNS is a helper function to create a namespace and set it to be
|
// CreateNS is a helper function to create a namespace and set it to be
|
||||||
// the current namespace of the runtime. `MakeNS` is much preferred
|
// the current namespace of the runtime. `MakeNS` is much preferred
|
||||||
func (r *Runtime) CreateNS(name string, source string, setAsCurrent bool) {
|
func (r *Runtime) CreateNS(name string, source string, setAsCurrent bool) {
|
||||||
ns := MakeNS(name, source)
|
ns := MakeNS(r, name, source)
|
||||||
|
|
||||||
if setAsCurrent {
|
if setAsCurrent {
|
||||||
r.currentNS = name
|
r.currentNS = name
|
||||||
|
|
|
@ -23,6 +23,8 @@ import "fmt"
|
||||||
type IScope interface {
|
type IScope interface {
|
||||||
Lookup(rt *Runtime, k string) *Binding
|
Lookup(rt *Runtime, k string) *Binding
|
||||||
Insert(k string, v IExpr, public bool)
|
Insert(k string, v IExpr, public bool)
|
||||||
|
GetNS(rt *Runtime) *Namespace
|
||||||
|
SetNS(ns *string)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Binding struct {
|
type Binding struct {
|
||||||
|
@ -33,6 +35,7 @@ type Binding struct {
|
||||||
type Scope struct {
|
type Scope struct {
|
||||||
bindings map[string]Binding
|
bindings map[string]Binding
|
||||||
parent *Scope
|
parent *Scope
|
||||||
|
ns *string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Scope) Lookup(rt *Runtime, k string) *Binding {
|
func (s *Scope) Lookup(rt *Runtime, k string) *Binding {
|
||||||
|
@ -42,6 +45,9 @@ func (s *Scope) Lookup(rt *Runtime, k string) *Binding {
|
||||||
|
|
||||||
v, ok := s.bindings[k]
|
v, ok := s.bindings[k]
|
||||||
if ok {
|
if ok {
|
||||||
|
if rt.IsDebugMode() {
|
||||||
|
fmt.Printf("[DEBUG] Found '%s': '%s'\n", k, v.Value.String())
|
||||||
|
}
|
||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +58,10 @@ func (s *Scope) Lookup(rt *Runtime, k string) *Binding {
|
||||||
builtin := rt.LookupBuiltin(k)
|
builtin := rt.LookupBuiltin(k)
|
||||||
|
|
||||||
if builtin != nil {
|
if builtin != nil {
|
||||||
|
if rt.IsDebugMode() {
|
||||||
|
fmt.Printf("[DEBUG] Found builtin '%s': '%s'\n", k, builtin)
|
||||||
|
}
|
||||||
|
|
||||||
return &Binding{builtin, true}
|
return &Binding{builtin, true}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,9 +72,36 @@ func (s *Scope) Insert(k string, v 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 (s *Scope) GetNS(rt *Runtime) *Namespace {
|
||||||
|
if s.ns == nil {
|
||||||
|
panic("A scope with no namespace !!!!")
|
||||||
|
}
|
||||||
|
ns, ok := rt.GetNS(*s.ns)
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Sprintf("A scope with the wrong namespace! '%s'", s.ns))
|
||||||
|
}
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Scope) SetNS(ns *string) {
|
||||||
|
s.ns = ns
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeScope(rt *Runtime, parent *Scope, namespace *string) *Scope {
|
||||||
|
var belongsTo *string
|
||||||
|
|
||||||
|
if parent != nil {
|
||||||
|
nsName := parent.GetNS(rt).GetName()
|
||||||
|
belongsTo = &nsName
|
||||||
|
} else if namespace == nil {
|
||||||
|
panic("When the 'parent' is nil, you have to provide the 'namespace' name.")
|
||||||
|
} else {
|
||||||
|
belongsTo = namespace
|
||||||
|
}
|
||||||
|
|
||||||
return &Scope{
|
return &Scope{
|
||||||
parent: parent,
|
parent: parent,
|
||||||
bindings: map[string]Binding{},
|
bindings: map[string]Binding{},
|
||||||
|
ns: belongsTo,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,40 +67,40 @@ func DefMacro(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
||||||
|
|
||||||
// TODO: Add support for docstrings and meta
|
// TODO: Add support for docstrings and meta
|
||||||
|
|
||||||
switch args.Count() {
|
if args.Count() < 2 {
|
||||||
case 3:
|
return nil, MakeError(rt, args, "'defmacro' form need at least 2 arguments")
|
||||||
name := args.First()
|
|
||||||
|
|
||||||
if name.GetType() != ast.Symbol {
|
|
||||||
return nil, MakeError(rt, name, "the first argument of 'defmacro' has to be a symbol")
|
|
||||||
}
|
|
||||||
|
|
||||||
sym := name.(*Symbol)
|
|
||||||
|
|
||||||
var params IColl
|
|
||||||
body := MakeEmptyBlock()
|
|
||||||
|
|
||||||
arguments := args.Rest().First()
|
|
||||||
|
|
||||||
// TODO: Add vector in here
|
|
||||||
// Or any other icoll
|
|
||||||
if arguments.GetType() == ast.List {
|
|
||||||
params = arguments.(IColl)
|
|
||||||
}
|
|
||||||
|
|
||||||
if args.Count() > 2 {
|
|
||||||
body.SetContent(args.Rest().Rest().(*List).ToSlice())
|
|
||||||
}
|
|
||||||
|
|
||||||
macro := MakeMacro(scope, sym.GetName(), params, body)
|
|
||||||
|
|
||||||
ns := rt.CurrentNS()
|
|
||||||
ns.DefineGlobal(sym.GetName(), macro, true)
|
|
||||||
|
|
||||||
return macro, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, MakeError(rt, args, "'defmacro' form need at least 2 arguments")
|
name := args.Rest().First()
|
||||||
|
|
||||||
|
if name.GetType() != ast.Symbol {
|
||||||
|
return nil, MakeError(rt, name, "the first argument of 'defmacro' has to be a symbol")
|
||||||
|
}
|
||||||
|
|
||||||
|
sym := name.(*Symbol)
|
||||||
|
|
||||||
|
var params IColl
|
||||||
|
body := MakeEmptyBlock()
|
||||||
|
|
||||||
|
arguments := args.Rest().Rest().First()
|
||||||
|
|
||||||
|
// TODO: Add vector in here
|
||||||
|
// Or any other icoll
|
||||||
|
if arguments.GetType() == ast.List {
|
||||||
|
params = arguments.(IColl)
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.Count() > 2 {
|
||||||
|
body.SetContent(args.Rest().Rest().Rest().(*List).ToSlice())
|
||||||
|
}
|
||||||
|
|
||||||
|
macro := MakeMacro(scope, sym.GetName(), params, body)
|
||||||
|
|
||||||
|
ns := scope.GetNS(rt)
|
||||||
|
ns.DefineGlobal(sym.GetName(), macro, true)
|
||||||
|
|
||||||
|
return macro, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fn defines a function inside the given scope `scope` with the given `args`.
|
// Fn defines a function inside the given scope `scope` with the given `args`.
|
||||||
|
|
|
@ -74,6 +74,10 @@ type IExpr interface {
|
||||||
IScopable
|
IScopable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Add helper functions to reach methods on Node.location. For example
|
||||||
|
// Node.location.DecStart() has to have a helper on the Node liek:
|
||||||
|
// Node.DecStartLocation
|
||||||
|
|
||||||
// Node struct is simply representing a Node in the AST which provides the
|
// Node struct is simply representing a Node in the AST which provides the
|
||||||
// functionalities required to trace the code based on the location.
|
// functionalities required to trace the code based on the location.
|
||||||
type Node struct {
|
type Node struct {
|
||||||
|
|
Loading…
Reference in New Issue