Record the caller details in the stack frame
This commit is contained in:
parent
3904b050bb
commit
9d106d4278
|
@ -9,7 +9,7 @@
|
||||||
(name args &body)
|
(name args &body)
|
||||||
(list 'def name (cons 'fn (cons args body))))
|
(list 'def name (cons 'fn (cons args body))))
|
||||||
|
|
||||||
(defn pp (x)
|
(defn pp (x y)
|
||||||
(println x))
|
(println x))
|
||||||
|
|
||||||
(def main
|
(def main
|
||||||
|
|
|
@ -4,6 +4,7 @@ go 1.15
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
|
||||||
|
github.com/gookit/color v1.3.5
|
||||||
github.com/rjeczalik/pkgconfig v0.0.0-20190903131546-94d388dab445
|
github.com/rjeczalik/pkgconfig v0.0.0-20190903131546-94d388dab445
|
||||||
github.com/spf13/cobra v1.1.1
|
github.com/spf13/cobra v1.1.1
|
||||||
github.com/spf13/viper v1.7.1
|
github.com/spf13/viper v1.7.1
|
||||||
|
|
|
@ -68,6 +68,8 @@ github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OI
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
|
github.com/gookit/color v1.3.5 h1:1nszcmDVrfti1Su5fhtuS5YBs/Xs6v8UIi0bJ/2oDHY=
|
||||||
|
github.com/gookit/color v1.3.5/go.mod h1:GqqLKF1le3EfrbHbYsYa5WdLqfc/PHMdMRbt6tMnqIc=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
|
|
|
@ -20,6 +20,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
// Serene's AST.
|
// Serene's AST.
|
||||||
package ast
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
type NodeType int
|
type NodeType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -40,13 +45,42 @@ const (
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Source struct {
|
||||||
|
Buffer *[]string
|
||||||
|
// It can be the path to the source file or something like "*in*"
|
||||||
|
// for standard in
|
||||||
|
Path string
|
||||||
|
LineIndex *[]int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Source) GetLine(linenum int) string {
|
||||||
|
lines := strings.Split(strings.Join(*s.Buffer, ""), "\n")
|
||||||
|
return lines[linenum-1]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Source) LineNumberFor(pos int) int {
|
||||||
|
if pos < 0 {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
return sort.Search(len(*s.LineIndex), func(i int) bool {
|
||||||
|
if i == 0 {
|
||||||
|
return pos < (*s.LineIndex)[i]
|
||||||
|
} else {
|
||||||
|
return (*s.LineIndex)[i-1] < pos && pos < (*s.LineIndex)[i]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type Location struct {
|
type Location struct {
|
||||||
start int
|
start int
|
||||||
end int
|
end int
|
||||||
source *[]string
|
source Source
|
||||||
knownLocation bool
|
knownLocation bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var UnknownLocation *Location = &Location{knownLocation: false}
|
||||||
|
|
||||||
func (l *Location) GetStart() int {
|
func (l *Location) GetStart() int {
|
||||||
return l.start
|
return l.start
|
||||||
}
|
}
|
||||||
|
@ -55,8 +89,42 @@ func (l *Location) GetEnd() int {
|
||||||
return l.end
|
return l.end
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Location) GetSource() *[]string {
|
func (l *Location) GetSource() *Source {
|
||||||
return l.source
|
return &l.source
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Location) IncStart(x int) {
|
||||||
|
if x+l.start < len(*l.source.Buffer) {
|
||||||
|
l.start += x
|
||||||
|
} else {
|
||||||
|
l.start = len(*l.source.Buffer) - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Location) DecStart(x int) {
|
||||||
|
if l.start-x >= 0 {
|
||||||
|
l.start -= x
|
||||||
|
} else {
|
||||||
|
l.start = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Location) IncEnd(x int) {
|
||||||
|
if x+l.end < len(*l.source.Buffer) {
|
||||||
|
l.end += x
|
||||||
|
} else {
|
||||||
|
l.end = len(*l.source.Buffer) - 1
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *Location) DecEnd(x int) {
|
||||||
|
if l.end-x >= 0 {
|
||||||
|
l.end -= x
|
||||||
|
} else {
|
||||||
|
l.end = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Location) IsKnownLocaiton() bool {
|
func (l *Location) IsKnownLocaiton() bool {
|
||||||
|
@ -64,12 +132,12 @@ func (l *Location) IsKnownLocaiton() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ILocatable interface {
|
type ILocatable interface {
|
||||||
GetLocation() Location
|
GetLocation() *Location
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeLocation(input *[]string, start int, end int) Location {
|
func MakeLocation(input *Source, start int, end int) *Location {
|
||||||
return Location{
|
return &Location{
|
||||||
source: input,
|
source: *input,
|
||||||
start: start,
|
start: start,
|
||||||
end: end,
|
end: end,
|
||||||
knownLocation: true,
|
knownLocation: true,
|
||||||
|
@ -80,8 +148,6 @@ type ITypable interface {
|
||||||
GetType() NodeType
|
GetType() NodeType
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeUnknownLocation() Location {
|
func MakeUnknownLocation() *Location {
|
||||||
return Location{
|
return UnknownLocation
|
||||||
knownLocation: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,7 +51,7 @@ func (b *Block) ToDebugStr() string {
|
||||||
return fmt.Sprintf("%#v", b)
|
return fmt.Sprintf("%#v", b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *Block) GetLocation() ast.Location {
|
func (b *Block) GetLocation() *ast.Location {
|
||||||
if len(b.body) > 0 {
|
if len(b.body) > 0 {
|
||||||
return b.body[0].GetLocation()
|
return b.body[0].GetLocation()
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,9 +53,9 @@ func PrintlnNativeFn(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IErr
|
||||||
func RequireNativeFn(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IError) {
|
func RequireNativeFn(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IError) {
|
||||||
switch args.Count() {
|
switch args.Count() {
|
||||||
case 0:
|
case 0:
|
||||||
return nil, MakeErrorFor(rt, args, "'require' function is missing")
|
return nil, MakeError(rt, args, "'require' function is missing")
|
||||||
case 1:
|
case 1:
|
||||||
return nil, MakeErrorFor(rt, args.First(), "'require' function needs at least one argument")
|
return nil, MakeError(rt, args.First(), "'require' function needs at least one argument")
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ func RequireNativeFn(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IErr
|
||||||
|
|
||||||
func HashNativeFn(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IError) {
|
func HashNativeFn(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IError) {
|
||||||
if args.Count() != 2 {
|
if args.Count() != 2 {
|
||||||
return nil, MakeErrorFor(rt, args.First(), "'hash' function needs exactly one argument")
|
return nil, MakeError(rt, args.First(), "'hash' function needs exactly one argument")
|
||||||
}
|
}
|
||||||
|
|
||||||
expr := args.Rest().First()
|
expr := args.Rest().First()
|
||||||
|
|
|
@ -33,38 +33,51 @@ package core
|
||||||
// compare the stack items by their address, identity and location.
|
// compare the stack items by their address, identity and location.
|
||||||
// * Add support for iteration on the stack.
|
// * Add support for iteration on the stack.
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
type ICallStack interface {
|
type ICallStack interface {
|
||||||
// Push the given callable `f` to the stack
|
// Push the given callable `f` to the stack
|
||||||
Push(f IFn) IError
|
Push(f IFn) IError
|
||||||
Pop() FnCall
|
Pop() *Frame
|
||||||
|
Peek() *Frame
|
||||||
Count() uint
|
Count() uint
|
||||||
}
|
}
|
||||||
|
|
||||||
type FnCall struct {
|
type Frame struct {
|
||||||
Fn IFn
|
|
||||||
// Number of recursive calls to this function
|
// Number of recursive calls to this function
|
||||||
count uint
|
Count uint
|
||||||
|
Fn IFn
|
||||||
|
Caller IExpr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TraceBack = []Frame
|
||||||
|
|
||||||
type CallStackItem struct {
|
type CallStackItem struct {
|
||||||
prev *CallStackItem
|
prev *CallStackItem
|
||||||
data FnCall
|
data Frame
|
||||||
}
|
}
|
||||||
|
|
||||||
type CallStack struct {
|
type CallStack struct {
|
||||||
|
debug bool
|
||||||
head *CallStackItem
|
head *CallStackItem
|
||||||
count uint
|
count uint
|
||||||
debug bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CallStack) Count() uint {
|
func (c *CallStack) Count() uint {
|
||||||
return c.count
|
return c.count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CallStack) Push(f IFn) IError {
|
func (c *CallStack) GetCurrentFn() IFn {
|
||||||
|
if c.head == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.head.data.Fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CallStack) Push(caller IExpr, f IFn) IError {
|
||||||
if c.debug {
|
if c.debug {
|
||||||
fmt.Println("[Stack] -->", f)
|
fmt.Println("[Stack] -->", f)
|
||||||
}
|
}
|
||||||
|
@ -73,12 +86,17 @@ func (c *CallStack) Push(f IFn) IError {
|
||||||
return MakePlainError("Can't push 'nil' pointer to the call stack.")
|
return MakePlainError("Can't push 'nil' pointer to the call stack.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if caller == nil {
|
||||||
|
return MakePlainError("Can't push 'nil' pointer to the call stack for the caller.")
|
||||||
|
}
|
||||||
|
|
||||||
// Empty Stack
|
// Empty Stack
|
||||||
if c.head == nil {
|
if c.head == nil {
|
||||||
c.head = &CallStackItem{
|
c.head = &CallStackItem{
|
||||||
data: FnCall{
|
data: Frame{
|
||||||
Fn: f,
|
Fn: f,
|
||||||
count: 0,
|
Caller: caller,
|
||||||
|
Count: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
c.count++
|
c.count++
|
||||||
|
@ -87,15 +105,16 @@ func (c *CallStack) Push(f IFn) IError {
|
||||||
nodeData := &c.head.data
|
nodeData := &c.head.data
|
||||||
|
|
||||||
// If the same function was on top of the stack
|
// If the same function was on top of the stack
|
||||||
if nodeData.Fn == f {
|
if nodeData.Fn == f && caller == nodeData.Caller {
|
||||||
// TODO: expand the check here to support address and location as well
|
// TODO: expand the check here to support address and location as well
|
||||||
nodeData.count++
|
nodeData.Count++
|
||||||
} else {
|
} else {
|
||||||
c.head = &CallStackItem{
|
c.head = &CallStackItem{
|
||||||
prev: c.head,
|
prev: c.head,
|
||||||
data: FnCall{
|
data: Frame{
|
||||||
Fn: f,
|
Fn: f,
|
||||||
count: 0,
|
Caller: caller,
|
||||||
|
Count: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
c.count++
|
c.count++
|
||||||
|
@ -103,7 +122,7 @@ func (c *CallStack) Push(f IFn) IError {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CallStack) Pop() *FnCall {
|
func (c *CallStack) Pop() *Frame {
|
||||||
if c.head == nil {
|
if c.head == nil {
|
||||||
if c.debug {
|
if c.debug {
|
||||||
fmt.Println("[Stack] <-- nil")
|
fmt.Println("[Stack] <-- nil")
|
||||||
|
@ -120,6 +139,32 @@ func (c *CallStack) Pop() *FnCall {
|
||||||
return &result.data
|
return &result.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CallStack) Peek() *Frame {
|
||||||
|
if c.head == nil {
|
||||||
|
if c.debug {
|
||||||
|
fmt.Println("[Stack] <-- nil")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result := c.head
|
||||||
|
return &result.data
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CallStack) ToTraceBack() *TraceBack {
|
||||||
|
var tr TraceBack
|
||||||
|
item := c.head
|
||||||
|
for {
|
||||||
|
if item == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
tr = append(tr, item.data)
|
||||||
|
item = item.prev
|
||||||
|
}
|
||||||
|
|
||||||
|
return &tr
|
||||||
|
}
|
||||||
|
|
||||||
func MakeCallStack(debugMode bool) CallStack {
|
func MakeCallStack(debugMode bool) CallStack {
|
||||||
return CallStack{
|
return CallStack{
|
||||||
count: 0,
|
count: 0,
|
||||||
|
|
|
@ -23,13 +23,14 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/chzyer/readline"
|
"github.com/chzyer/readline"
|
||||||
"serene-lang.org/bootstrap/pkg/ast"
|
"serene-lang.org/bootstrap/pkg/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
func rep(rt *Runtime, line string) {
|
func rep(rt *Runtime, line string) {
|
||||||
ast, err := ReadString(line)
|
ast, err := ReadString("*REPL*", line)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
PrintError(rt, err)
|
PrintError(rt, err)
|
||||||
|
@ -120,7 +121,17 @@ func Run(flags map[string]bool, args []string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ns := args[0]
|
ns := args[0]
|
||||||
loadedNS, err := requireNS(rt, ns)
|
nsAsBuffer := strings.Split(ns, "")
|
||||||
|
source := &ast.Source{Buffer: &nsAsBuffer, Path: "*input-argument*"}
|
||||||
|
node := MakeNode(source, 0, len(ns))
|
||||||
|
nsSym, err := MakeSymbol(node, ns)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
PrintError(rt, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
loadedNS, err := requireNS(rt, nsSym)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
PrintError(rt, err)
|
PrintError(rt, err)
|
||||||
|
@ -133,6 +144,7 @@ func Run(flags map[string]bool, args []string) {
|
||||||
if !inserted {
|
if !inserted {
|
||||||
err := MakeError(
|
err := MakeError(
|
||||||
rt,
|
rt,
|
||||||
|
loadedNS,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"the namespace '%s' didn't get inserted in the runtime.",
|
"the namespace '%s' didn't get inserted in the runtime.",
|
||||||
loadedNS.GetName()),
|
loadedNS.GetName()),
|
||||||
|
@ -163,24 +175,22 @@ func Run(flags map[string]bool, args []string) {
|
||||||
mainFn := mainBinding.Value.(*Function)
|
mainFn := mainBinding.Value.(*Function)
|
||||||
|
|
||||||
var fnArgs []IExpr
|
var fnArgs []IExpr
|
||||||
|
var argNode Node
|
||||||
|
|
||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
for _, arg := range args[1:] {
|
for _, arg := range args[1:] {
|
||||||
node := MakeNodeFromExpr(mainFn)
|
node := MakeNodeFromExpr(mainFn)
|
||||||
fnArgs = append(fnArgs, MakeString(node, arg))
|
fnArgs = append(fnArgs, MakeString(node, arg))
|
||||||
}
|
}
|
||||||
|
argNode = MakeNodeFromExprs(fnArgs)
|
||||||
|
} else {
|
||||||
|
argNode = node
|
||||||
}
|
}
|
||||||
|
|
||||||
//rt.Stack.Push(mainFn)
|
_, err = mainFn.Apply(rt, loadedNS.GetRootScope(), mainFn.Node, MakeList(argNode, fnArgs))
|
||||||
_, err = mainFn.Apply(rt, loadedNS.GetRootScope(), mainFn.Node, MakeList(fnArgs))
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
PrintError(rt, err)
|
PrintError(rt, err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rt.Stack.Pop()
|
|
||||||
// if rt.Stack.Count() != 0 {
|
|
||||||
// panic("Call stack is not empty.")
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ type IError interface {
|
||||||
IRepresentable
|
IRepresentable
|
||||||
IDebuggable
|
IDebuggable
|
||||||
|
|
||||||
|
GetStackTrace() *TraceBack
|
||||||
// To wrap Golan rrrrors
|
// To wrap Golan rrrrors
|
||||||
WithError(err error) IError
|
WithError(err error) IError
|
||||||
|
|
||||||
|
@ -62,6 +63,7 @@ type Error struct {
|
||||||
Node
|
Node
|
||||||
WrappedErr error
|
WrappedErr error
|
||||||
msg string
|
msg string
|
||||||
|
trace *TraceBack
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Error) String() string {
|
func (e *Error) String() string {
|
||||||
|
@ -89,32 +91,25 @@ func (e *Error) Error() string {
|
||||||
return e.msg
|
return e.msg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Error) GetStackTrace() *TraceBack {
|
||||||
|
return e.trace
|
||||||
|
}
|
||||||
|
|
||||||
func MakePlainError(msg string) IError {
|
func MakePlainError(msg string) IError {
|
||||||
return &Error{
|
return &Error{
|
||||||
msg: msg,
|
msg: msg,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeError creates an Error without any location.
|
// MakeError creates an Error which points to the given IExpr `e` as
|
||||||
func MakeError(rt *Runtime, msg string) IError {
|
|
||||||
return MakePlainError(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MakeErrorFor creates an Error which points to the given IExpr `e` as
|
|
||||||
// the root of the error.
|
// the root of the error.
|
||||||
func MakeErrorFor(rt *Runtime, e IExpr, msg string) IError {
|
func MakeError(rt *Runtime, e IExpr, msg string) IError {
|
||||||
loc := e.GetLocation()
|
trace := append(*rt.Stack.ToTraceBack(), Frame{0, rt.Stack.GetCurrentFn(), e})
|
||||||
|
|
||||||
return &Error{
|
return &Error{
|
||||||
Node: MakeNodeFromLocation(loc),
|
Node: MakeNodeFromExpr(e),
|
||||||
msg: msg,
|
msg: msg,
|
||||||
}
|
trace: &trace,
|
||||||
}
|
|
||||||
|
|
||||||
//MakeRuntimeErrorf is a helper function which works like `fmt.Errorf`
|
|
||||||
func MakeRuntimeErrorf(rt *Runtime, msg string, a ...interface{}) IError {
|
|
||||||
return &Error{
|
|
||||||
msg: fmt.Sprintf(msg, a...),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,7 +84,7 @@ func evalForm(rt *Runtime, scope IScope, form IExpr) (IExpr, IError) {
|
||||||
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 !rt.CurrentNS().hasExternal(sym.GetNSPart()) {
|
||||||
return nil, MakeErrorFor(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()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -97,11 +97,14 @@ func evalForm(rt *Runtime, scope IScope, form IExpr) (IExpr, IError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if expr == nil {
|
if expr == nil {
|
||||||
return nil, MakeRuntimeErrorf(
|
return nil, MakeError(
|
||||||
rt,
|
rt,
|
||||||
"can't resolve symbol '%s' in ns '%s'",
|
sym,
|
||||||
symbolName,
|
fmt.Sprintf(
|
||||||
nsName,
|
"can't resolve symbol '%s' in ns '%s'",
|
||||||
|
symbolName,
|
||||||
|
nsName,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,11 +129,12 @@ func evalForm(rt *Runtime, scope IScope, form IExpr) (IExpr, IError) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MakeList(result), nil
|
|
||||||
|
return MakeList(MakeNodeFromExpr(lst), result), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default case
|
// Default case
|
||||||
return nil, MakeError(rt, fmt.Sprintf("support for '%d' is not implemented", form.GetType()))
|
return nil, MakeError(rt, form, fmt.Sprintf("support for '%d' is not implemented", form.GetType()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EvalForms evaluates the given expr `expressions` (it can be a list, block, symbol or anything else)
|
// EvalForms evaluates the given expr `expressions` (it can be a list, block, symbol or anything else)
|
||||||
|
@ -185,7 +189,6 @@ tco:
|
||||||
|
|
||||||
body:
|
body:
|
||||||
for i := 0; i < len(exprs); i++ {
|
for i := 0; i < len(exprs); i++ {
|
||||||
//for i, forms := range exprs {
|
|
||||||
forms := exprs[i]
|
forms := exprs[i]
|
||||||
executionScope := forms.GetExecutionScope()
|
executionScope := forms.GetExecutionScope()
|
||||||
scope := scope
|
scope := scope
|
||||||
|
@ -275,7 +278,7 @@ tco:
|
||||||
case "quote":
|
case "quote":
|
||||||
// Including the `quote` itself
|
// Including the `quote` itself
|
||||||
if list.Count() != 2 {
|
if list.Count() != 2 {
|
||||||
return nil, MakeErrorFor(rt, list, "'quote' quote only accepts one argument.")
|
return nil, MakeError(rt, list, "'quote' quote only accepts one argument.")
|
||||||
}
|
}
|
||||||
ret = list.Rest().First()
|
ret = list.Rest().First()
|
||||||
err = nil
|
err = nil
|
||||||
|
@ -310,12 +313,18 @@ tco:
|
||||||
result := []IExpr{}
|
result := []IExpr{}
|
||||||
for _, lst := range lists {
|
for _, lst := range lists {
|
||||||
if lst.GetType() != ast.List {
|
if lst.GetType() != ast.List {
|
||||||
return nil, MakeErrorFor(rt, lst, fmt.Sprintf("don't know how to concat '%s'", lst.String()))
|
return nil, MakeError(rt, lst, fmt.Sprintf("don't know how to concat '%s'", lst.String()))
|
||||||
}
|
}
|
||||||
|
|
||||||
result = append(result, lst.(*List).ToSlice()...)
|
result = append(result, lst.(*List).ToSlice()...)
|
||||||
}
|
}
|
||||||
ret, err = MakeList(result), nil
|
|
||||||
|
node := MakeNodeFromExpr(list)
|
||||||
|
if len(result) > 0 {
|
||||||
|
node = MakeNodeFromExprs(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
ret, err = MakeList(node, result), nil
|
||||||
continue body // no rewrite
|
continue body // no rewrite
|
||||||
|
|
||||||
// TODO: Implement `list` in serene itself when we have destructuring available
|
// TODO: Implement `list` in serene itself when we have destructuring available
|
||||||
|
@ -324,7 +333,7 @@ tco:
|
||||||
// given in the second argument.
|
// given in the second argument.
|
||||||
case "cons":
|
case "cons":
|
||||||
if list.Count() != 3 {
|
if list.Count() != 3 {
|
||||||
return nil, MakeErrorFor(rt, list, "'cons' needs exactly 3 arguments")
|
return nil, MakeError(rt, list, "'cons' needs exactly 3 arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
evaledForms, err := evalForm(rt, scope, list.Rest().(*List))
|
evaledForms, err := evalForm(rt, scope, list.Rest().(*List))
|
||||||
|
@ -335,7 +344,7 @@ tco:
|
||||||
coll, ok := evaledForms.(*List).Rest().First().(IColl)
|
coll, ok := evaledForms.(*List).Rest().First().(IColl)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, MakeErrorFor(rt, list, "second arg of 'cons' has to be a collection")
|
return nil, MakeError(rt, list, "second arg of 'cons' has to be a collection")
|
||||||
}
|
}
|
||||||
|
|
||||||
ret, err = coll.Cons(evaledForms.(*List).First()), nil
|
ret, err = coll.Cons(evaledForms.(*List).First()), nil
|
||||||
|
@ -366,7 +375,7 @@ tco:
|
||||||
// as a macro and returns the expanded forms.
|
// as a macro and returns the expanded forms.
|
||||||
case "macroexpand":
|
case "macroexpand":
|
||||||
if list.Count() != 2 {
|
if list.Count() != 2 {
|
||||||
return nil, MakeErrorFor(rt, list, "'macroexpand' needs exactly one argument.")
|
return nil, MakeError(rt, list, "'macroexpand' needs exactly one argument.")
|
||||||
}
|
}
|
||||||
evaledForm, e := evalForm(rt, scope, list.Rest().(*List))
|
evaledForm, e := evalForm(rt, scope, list.Rest().(*List))
|
||||||
|
|
||||||
|
@ -381,7 +390,7 @@ tco:
|
||||||
// * It needs at least a collection of arguments
|
// * It needs at least a collection of arguments
|
||||||
// * Defines an anonymous function.
|
// * Defines an anonymous function.
|
||||||
case "fn":
|
case "fn":
|
||||||
ret, err = Fn(rt, scope, list.Rest().(*List))
|
ret, err = Fn(rt, scope, list)
|
||||||
continue body // no rewrite
|
continue body // no rewrite
|
||||||
|
|
||||||
// `if` evaluation rules:
|
// `if` evaluation rules:
|
||||||
|
@ -392,7 +401,7 @@ tco:
|
||||||
case "if":
|
case "if":
|
||||||
args := list.Rest().(*List)
|
args := list.Rest().(*List)
|
||||||
if args.Count() != 3 {
|
if args.Count() != 3 {
|
||||||
return nil, MakeError(rt, "'if' needs exactly 3 aruments")
|
return nil, MakeError(rt, args, "'if' needs exactly 3 aruments")
|
||||||
}
|
}
|
||||||
|
|
||||||
pred, err := EvalForms(rt, scope, args.First())
|
pred, err := EvalForms(rt, scope, args.First())
|
||||||
|
@ -436,7 +445,7 @@ tco:
|
||||||
// the result.
|
// the result.
|
||||||
case "eval":
|
case "eval":
|
||||||
if list.Count() != 2 {
|
if list.Count() != 2 {
|
||||||
return nil, MakeErrorFor(rt, list, "'eval' needs exactly 1 arguments")
|
return nil, MakeError(rt, list, "'eval' needs exactly 1 arguments")
|
||||||
}
|
}
|
||||||
form, err := evalForm(rt, scope, list.Rest().(*List))
|
form, err := evalForm(rt, scope, list.Rest().(*List))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -457,7 +466,7 @@ tco:
|
||||||
// which is the result of the last expre in `BODY`
|
// which is the result of the last expre in `BODY`
|
||||||
case "let":
|
case "let":
|
||||||
if list.Count() < 2 {
|
if list.Count() < 2 {
|
||||||
return nil, MakeError(rt, "'let' needs at list 1 aruments")
|
return nil, MakeError(rt, list, "'let' needs at list 1 aruments")
|
||||||
}
|
}
|
||||||
|
|
||||||
letScope := MakeScope(scope.(*Scope))
|
letScope := MakeScope(scope.(*Scope))
|
||||||
|
@ -470,7 +479,7 @@ tco:
|
||||||
body := list.Rest().Rest().(*List).ToSlice()
|
body := list.Rest().Rest().(*List).ToSlice()
|
||||||
|
|
||||||
if bindings.Count()%2 != 0 {
|
if bindings.Count()%2 != 0 {
|
||||||
return nil, MakeError(rt, "'let' bindings has to have even number of forms.")
|
return nil, MakeError(rt, list.Rest().First(), "'let' bindings has to have even number of forms.")
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
@ -485,7 +494,7 @@ tco:
|
||||||
// TODO: We need to destruct the bindings here and remove this check
|
// TODO: We need to destruct the bindings here and remove this check
|
||||||
// for the symbol type
|
// for the symbol type
|
||||||
if name.GetType() != ast.Symbol {
|
if name.GetType() != ast.Symbol {
|
||||||
err := MakeErrorFor(rt, name, "'let' doesn't support desbbtructuring yet, use a symbol.")
|
err := MakeError(rt, name, "'let' doesn't support desbbtructuring yet, use a symbol.")
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -546,7 +555,7 @@ tco:
|
||||||
break body //return
|
break body //return
|
||||||
}
|
}
|
||||||
|
|
||||||
rt.Stack.Push(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
|
||||||
|
@ -561,7 +570,8 @@ tco:
|
||||||
// by the `NativeFunction` struct
|
// by the `NativeFunction` struct
|
||||||
case ast.NativeFn:
|
case ast.NativeFn:
|
||||||
fn := f.(*NativeFunction)
|
fn := f.(*NativeFunction)
|
||||||
rt.Stack.Push(fn)
|
|
||||||
|
rt.Stack.Push(list, fn)
|
||||||
ret, err = fn.Apply(
|
ret, err = fn.Apply(
|
||||||
rt,
|
rt,
|
||||||
scope,
|
scope,
|
||||||
|
@ -572,7 +582,7 @@ tco:
|
||||||
continue body // no rewrite
|
continue body // no rewrite
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = MakeError(rt, "don't know how to execute anything beside function")
|
err = MakeError(rt, f, "don't know how to execute anything beside function")
|
||||||
ret = nil
|
ret = nil
|
||||||
break tco
|
break tco
|
||||||
}
|
}
|
||||||
|
@ -613,7 +623,7 @@ func EvalNSBody(rt *Runtime, ns *Namespace) (*Namespace, IError) {
|
||||||
exprs := body.ToSlice()
|
exprs := body.ToSlice()
|
||||||
|
|
||||||
if len(exprs) == 0 {
|
if len(exprs) == 0 {
|
||||||
return nil, MakeError(rt, fmt.Sprintf("the 'ns' form is missing from '%s'", ns.GetName()))
|
return nil, MakeError(rt, ns, fmt.Sprintf("the 'ns' form is missing from '%s'", ns.GetName()))
|
||||||
}
|
}
|
||||||
|
|
||||||
if exprs[0].GetType() == ast.List {
|
if exprs[0].GetType() == ast.List {
|
||||||
|
@ -627,5 +637,5 @@ func EvalNSBody(rt *Runtime, ns *Namespace) (*Namespace, IError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, MakeError(rt, fmt.Sprintf("the 'ns' form is missing from '%s'", ns.GetName()))
|
return nil, MakeError(rt, ns, fmt.Sprintf("the 'ns' form is missing from '%s'", ns.GetName()))
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,8 +48,9 @@ import (
|
||||||
type nativeFnHandler = func(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IError)
|
type nativeFnHandler = func(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IError)
|
||||||
|
|
||||||
type IFn interface {
|
type IFn interface {
|
||||||
ast.ILocatable
|
IExpr
|
||||||
Apply(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IError)
|
Apply(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IError)
|
||||||
|
GetName() string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function struct represent a user defined function.
|
// Function struct represent a user defined function.
|
||||||
|
@ -142,8 +143,9 @@ func (f *Function) Apply(rt *Runtime, scope IScope, n Node, args *List) (IExpr,
|
||||||
|
|
||||||
// MakeFunction Create a function with the given `params` and `body` in
|
// MakeFunction Create a function with the given `params` and `body` in
|
||||||
// the given `scope`.
|
// the given `scope`.
|
||||||
func MakeFunction(scope IScope, params IColl, body *Block) *Function {
|
func MakeFunction(n Node, scope IScope, params IColl, body *Block) *Function {
|
||||||
return &Function{
|
return &Function{
|
||||||
|
Node: n,
|
||||||
scope: scope,
|
scope: scope,
|
||||||
params: params,
|
params: params,
|
||||||
body: body,
|
body: body,
|
||||||
|
@ -173,7 +175,8 @@ func MakeFnScope(rt *Runtime, parent IScope, bindings IColl, values IColl) (*Sco
|
||||||
fmt.Printf("[DEBUG] Mismatch on bindings and values: Bindings: %s, Values: %s\n", bindings, values)
|
fmt.Printf("[DEBUG] Mismatch on bindings and values: Bindings: %s, Values: %s\n", bindings, values)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, MakeError(rt,
|
fmt.Println("3333333", values.(IExpr).GetLocation(), bindings.(IExpr).GetLocation())
|
||||||
|
return nil, MakeError(rt, values.(IExpr),
|
||||||
fmt.Sprintf("expected '%d' arguments, got '%d'.", bindings.Count(), values.Count()))
|
fmt.Sprintf("expected '%d' arguments, got '%d'.", bindings.Count(), values.Count()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,20 +188,29 @@ func MakeFnScope(rt *Runtime, parent IScope, bindings IColl, values IColl) (*Sco
|
||||||
if binds[i].GetType() == ast.Symbol && binds[i].(*Symbol).IsRestable() {
|
if binds[i].GetType() == ast.Symbol && binds[i].(*Symbol).IsRestable() {
|
||||||
|
|
||||||
if i != len(binds)-1 {
|
if i != len(binds)-1 {
|
||||||
return nil, MakeErrorFor(rt, binds[i], "The function argument with '&' has to be the last argument.")
|
return nil, MakeError(rt, binds[i], "The function argument with '&' has to be the last argument.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the number of values are one less than the number of bindings
|
// if the number of values are one less than the number of bindings
|
||||||
// but the last binding is a Restable (e.g &x) the the last bindings
|
// but the last binding is a Restable (e.g &x) the the last bindings
|
||||||
// has to be an empty list. Note the check for number of vlaues comes
|
// has to be an empty list. Note the check for number of vlaues comes
|
||||||
// next.
|
// next.
|
||||||
rest := MakeEmptyList()
|
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)
|
||||||
rest = MakeList(exprs[i:])
|
elements := exprs[i:]
|
||||||
|
var node Node
|
||||||
|
|
||||||
|
if len(elements) > 0 {
|
||||||
|
node = MakeNodeFromExprs(elements)
|
||||||
|
} else {
|
||||||
|
node = MakeNodeFromExpr(binds[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
rest = MakeList(node, elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
scope.Insert(binds[i].(*Symbol).GetName()[1:], rest, false)
|
scope.Insert(binds[i].(*Symbol).GetName()[1:], rest, false)
|
||||||
|
@ -215,6 +227,10 @@ func (f *NativeFunction) GetType() ast.NodeType {
|
||||||
return ast.NativeFn
|
return ast.NativeFn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *NativeFunction) GetName() string {
|
||||||
|
return f.name
|
||||||
|
}
|
||||||
|
|
||||||
func (f *NativeFunction) String() string {
|
func (f *NativeFunction) String() string {
|
||||||
return fmt.Sprintf("<NativeFn: %s at %p>", f.name, f)
|
return fmt.Sprintf("<NativeFn: %s at %p>", f.name, f)
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,7 +159,7 @@ func (k *Keyword) Eval(rt *Runtime, scope IScope) (*Keyword, IError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if aliasedNS == nil {
|
if aliasedNS == nil {
|
||||||
return nil, MakeErrorFor(rt, k, fmt.Sprintf("can't find the alias '%s' in the current namespace.", k.nsName))
|
return nil, MakeError(rt, k, fmt.Sprintf("can't find the alias '%s' in the current namespace.", k.nsName))
|
||||||
}
|
}
|
||||||
k.ns = aliasedNS
|
k.ns = aliasedNS
|
||||||
return k, nil
|
return k, nil
|
||||||
|
|
|
@ -70,9 +70,16 @@ func (l *List) First() IExpr {
|
||||||
|
|
||||||
func (l *List) Rest() ISeq {
|
func (l *List) Rest() ISeq {
|
||||||
if l.Count() < 2 {
|
if l.Count() < 2 {
|
||||||
return MakeEmptyList()
|
return MakeEmptyList(l.Node)
|
||||||
}
|
}
|
||||||
return MakeList(l.exprs[1:])
|
|
||||||
|
rest := l.exprs[1:]
|
||||||
|
node := l.Node
|
||||||
|
if len(rest) > 0 {
|
||||||
|
node = MakeNodeFromExprs(rest)
|
||||||
|
}
|
||||||
|
|
||||||
|
return MakeList(node, rest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *List) Hash() uint32 {
|
func (l *List) Hash() uint32 {
|
||||||
|
@ -97,8 +104,8 @@ func (l *List) ToSlice() []IExpr {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *List) Cons(e IExpr) IExpr {
|
func (l *List) Cons(e IExpr) IExpr {
|
||||||
elems := l.ToSlice()
|
elements := append([]IExpr{e}, l.ToSlice()...)
|
||||||
return MakeList(append([]IExpr{e}, elems...))
|
return MakeList(MakeNodeFromExprs(elements), elements)
|
||||||
}
|
}
|
||||||
|
|
||||||
// END: IColl ---
|
// END: IColl ---
|
||||||
|
@ -118,14 +125,16 @@ func ListStartsWith(l *List, sym string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeList(elements []IExpr) *List {
|
func MakeList(n Node, elements []IExpr) *List {
|
||||||
return &List{
|
return &List{
|
||||||
|
Node: n,
|
||||||
exprs: elements,
|
exprs: elements,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeEmptyList() *List {
|
func MakeEmptyList(n Node) *List {
|
||||||
return &List{
|
return &List{
|
||||||
|
Node: n,
|
||||||
exprs: []IExpr{},
|
exprs: []IExpr{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ func (n *Namespace) GetType() ast.NodeType {
|
||||||
return ast.Namespace
|
return ast.Namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Namespace) GetLocation() ast.Location {
|
func (n *Namespace) GetLocation() *ast.Location {
|
||||||
return ast.MakeUnknownLocation()
|
return ast.MakeUnknownLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ func (n *Namespace) getForms() *Block {
|
||||||
|
|
||||||
// requireNS finds and loads the namespace addressed by the given
|
// requireNS finds and loads the namespace addressed by the given
|
||||||
// `ns` string.
|
// `ns` string.
|
||||||
func requireNS(rt *Runtime, ns string) (*Namespace, IError) {
|
func requireNS(rt *Runtime, ns *Symbol) (*Namespace, IError) {
|
||||||
// TODO: use a hashing algorithm to avoid reloading an unchanged namespace
|
// TODO: use a hashing algorithm to avoid reloading an unchanged namespace
|
||||||
loadedForms, err := rt.LoadNS(ns)
|
loadedForms, err := rt.LoadNS(ns)
|
||||||
|
|
||||||
|
@ -155,11 +155,12 @@ func requireNS(rt *Runtime, ns string) (*Namespace, IError) {
|
||||||
if body.Count() == 0 {
|
if body.Count() == 0 {
|
||||||
return nil, MakeError(
|
return nil, MakeError(
|
||||||
rt,
|
rt,
|
||||||
|
body,
|
||||||
fmt.Sprintf("The '%s' ns source code doesn't start with an 'ns' form.", ns),
|
fmt.Sprintf("The '%s' ns source code doesn't start with an 'ns' form.", ns),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace := MakeNS(ns, source)
|
namespace := MakeNS(ns.GetName(), source)
|
||||||
namespace.setForms(body)
|
namespace.setForms(body)
|
||||||
|
|
||||||
return &namespace, nil
|
return &namespace, nil
|
||||||
|
@ -188,21 +189,21 @@ func RequireNamespace(rt *Runtime, namespace IExpr) (IExpr, IError) {
|
||||||
first := list.First()
|
first := list.First()
|
||||||
|
|
||||||
if first.GetType() != ast.Symbol {
|
if first.GetType() != ast.Symbol {
|
||||||
return nil, MakeErrorFor(rt, first, "The first element has to be a symbol")
|
return nil, MakeError(rt, first, "The first element has to be a symbol")
|
||||||
}
|
}
|
||||||
|
|
||||||
second := list.Rest().First()
|
second := list.Rest().First()
|
||||||
if second.GetType() != ast.Symbol {
|
if second.GetType() != ast.Symbol {
|
||||||
return nil, MakeErrorFor(rt, first, "The second element has to be a symbol")
|
return nil, MakeError(rt, first, "The second element has to be a symbol")
|
||||||
}
|
}
|
||||||
|
|
||||||
ns = first.(*Symbol)
|
ns = first.(*Symbol)
|
||||||
alias = second.(*Symbol).GetName()
|
alias = second.(*Symbol).GetName()
|
||||||
default:
|
default:
|
||||||
return nil, MakeErrorFor(rt, ns, "Don't know how to load the given namespace")
|
return nil, MakeError(rt, ns, "Don't know how to load the given namespace")
|
||||||
}
|
}
|
||||||
|
|
||||||
loadedNS, err := requireNS(rt, ns.GetName())
|
loadedNS, err := requireNS(rt, ns)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -217,6 +218,7 @@ func RequireNamespace(rt *Runtime, namespace IExpr) (IExpr, IError) {
|
||||||
if !inserted {
|
if !inserted {
|
||||||
return nil, MakeError(
|
return nil, MakeError(
|
||||||
rt,
|
rt,
|
||||||
|
loadedNS,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"the namespace '%s' didn't get inserted in the runtime.",
|
"the namespace '%s' didn't get inserted in the runtime.",
|
||||||
loadedNS.GetName()),
|
loadedNS.GetName()),
|
||||||
|
@ -231,6 +233,7 @@ func RequireNamespace(rt *Runtime, namespace IExpr) (IExpr, IError) {
|
||||||
if !inserted {
|
if !inserted {
|
||||||
return nil, MakeError(
|
return nil, MakeError(
|
||||||
rt,
|
rt,
|
||||||
|
loadedNS,
|
||||||
fmt.Sprintf(
|
fmt.Sprintf(
|
||||||
"can't set the current ns back to '%s' from '%s'.",
|
"can't set the current ns back to '%s' from '%s'.",
|
||||||
prevNS.GetName(),
|
prevNS.GetName(),
|
||||||
|
|
|
@ -36,7 +36,7 @@ func (n NothingType) Hash() uint32 {
|
||||||
return hash.HashOf(append([]byte{byte(ast.Block)}, bytes...))
|
return hash.HashOf(append([]byte{byte(ast.Block)}, bytes...))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n NothingType) GetLocation() ast.Location {
|
func (n NothingType) GetLocation() *ast.Location {
|
||||||
return ast.MakeUnknownLocation()
|
return ast.MakeUnknownLocation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ package core
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"serene-lang.org/bootstrap/pkg/ast"
|
||||||
)
|
)
|
||||||
|
|
||||||
// An array of the valid characters that be be used in a symbol
|
// An array of the valid characters that be be used in a symbol
|
||||||
|
@ -57,14 +59,17 @@ type IParsable interface {
|
||||||
|
|
||||||
// Returns the current position in the buffer
|
// Returns the current position in the buffer
|
||||||
GetLocation() int
|
GetLocation() int
|
||||||
|
GetSource() *ast.Source
|
||||||
Buffer() *[]string
|
Buffer() *[]string
|
||||||
}
|
}
|
||||||
|
|
||||||
// StringParser is an implementation of the IParsable that operates on strings.
|
// StringParser is an implementation of the IParsable that operates on strings.
|
||||||
// To put it simply it parses input strings
|
// To put it simply it parses input strings
|
||||||
type StringParser struct {
|
type StringParser struct {
|
||||||
buffer []string
|
buffer []string
|
||||||
pos int
|
pos int
|
||||||
|
source string
|
||||||
|
lineIndex []int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implementing IParsable for StringParser ---
|
// Implementing IParsable for StringParser ---
|
||||||
|
@ -75,6 +80,12 @@ func (sp *StringParser) next(skipWhitespace bool) *string {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
char := sp.buffer[sp.pos]
|
char := sp.buffer[sp.pos]
|
||||||
|
|
||||||
|
if char == "\n" {
|
||||||
|
// Including the \n itself
|
||||||
|
sp.lineIndex = append(sp.lineIndex, sp.pos+1)
|
||||||
|
}
|
||||||
|
|
||||||
sp.pos = sp.pos + 1
|
sp.pos = sp.pos + 1
|
||||||
|
|
||||||
if skipWhitespace && isSeparator(&char) {
|
if skipWhitespace && isSeparator(&char) {
|
||||||
|
@ -127,6 +138,14 @@ func (sp *StringParser) GetLocation() int {
|
||||||
return sp.pos
|
return sp.pos
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sp *StringParser) GetSource() *ast.Source {
|
||||||
|
return &ast.Source{
|
||||||
|
Buffer: &sp.buffer,
|
||||||
|
Path: sp.source,
|
||||||
|
LineIndex: &sp.lineIndex,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (sp *StringParser) Buffer() *[]string {
|
func (sp *StringParser) Buffer() *[]string {
|
||||||
return &sp.buffer
|
return &sp.buffer
|
||||||
}
|
}
|
||||||
|
@ -136,7 +155,7 @@ func (sp *StringParser) Buffer() *[]string {
|
||||||
// makeErrorAtPoint is a helper function which generates an `IError` that
|
// makeErrorAtPoint is a helper function which generates an `IError` that
|
||||||
// points at the current position of the buffer.
|
// points at the current position of the buffer.
|
||||||
func makeErrorAtPoint(p IParsable, msg string, a ...interface{}) IError {
|
func makeErrorAtPoint(p IParsable, msg string, a ...interface{}) IError {
|
||||||
n := MakeSinglePointNode(p.Buffer(), p.GetLocation())
|
n := MakeSinglePointNode(p.GetSource(), p.GetLocation())
|
||||||
return MakeParsetimeErrorf(n, msg, a...)
|
return MakeParsetimeErrorf(n, msg, a...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,7 +226,7 @@ func readRawSymbol(parser IParsable) (IExpr, IError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node := MakeNode(parser.Buffer(), parser.GetLocation()-len(symbol), parser.GetLocation())
|
node := MakeNode(parser.GetSource(), parser.GetLocation()-len(symbol), parser.GetLocation())
|
||||||
sym, err := MakeSymbol(node, symbol)
|
sym, err := MakeSymbol(node, symbol)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -228,7 +247,7 @@ func readString(parser IParsable) (IExpr, IError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if *c == "\"" {
|
if *c == "\"" {
|
||||||
node := MakeNode(parser.Buffer(), parser.GetLocation()-len(str), parser.GetLocation())
|
node := MakeNode(parser.GetSource(), parser.GetLocation()-len(str), parser.GetLocation())
|
||||||
return MakeString(node, str), nil
|
return MakeString(node, str), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,7 +386,10 @@ func readList(parser IParsable) (IExpr, IError) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeList(list), nil
|
node := MakeNodeFromExprs(list)
|
||||||
|
node.location.DecStart(1)
|
||||||
|
node.location.IncEnd(1)
|
||||||
|
return MakeList(node, list), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func readComment(parser IParsable) (IExpr, IError) {
|
func readComment(parser IParsable) (IExpr, IError) {
|
||||||
|
@ -387,7 +409,7 @@ func readQuotedExpr(parser IParsable) (IExpr, IError) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
symNode := MakeNode(parser.Buffer(), parser.GetLocation(), parser.GetLocation())
|
symNode := MakeNode(parser.GetSource(), parser.GetLocation(), parser.GetLocation())
|
||||||
sym, err := MakeSymbol(symNode, "quote")
|
sym, err := MakeSymbol(symNode, "quote")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -395,10 +417,15 @@ func readQuotedExpr(parser IParsable) (IExpr, IError) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeList([]IExpr{
|
listElems := []IExpr{
|
||||||
sym,
|
sym,
|
||||||
expr,
|
expr,
|
||||||
}), nil
|
}
|
||||||
|
|
||||||
|
listNode := MakeNodeFromExprs(listElems)
|
||||||
|
listNode.location.DecStart(1)
|
||||||
|
listNode.location.IncStart(1)
|
||||||
|
return MakeList(listNode, listElems), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// readUnquotedExpr reads different unquoting expressions from their short representaions.
|
// readUnquotedExpr reads different unquoting expressions from their short representaions.
|
||||||
|
@ -417,7 +444,7 @@ func readUnquotedExpr(parser IParsable) (IExpr, IError) {
|
||||||
var err IError
|
var err IError
|
||||||
var expr IExpr
|
var expr IExpr
|
||||||
|
|
||||||
node := MakeNode(parser.Buffer(), parser.GetLocation(), parser.GetLocation())
|
node := MakeNode(parser.GetSource(), parser.GetLocation(), parser.GetLocation())
|
||||||
|
|
||||||
if *c == "@" {
|
if *c == "@" {
|
||||||
parser.next(true)
|
parser.next(true)
|
||||||
|
@ -441,7 +468,11 @@ func readUnquotedExpr(parser IParsable) (IExpr, IError) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeList([]IExpr{sym, expr}), nil
|
listElems := []IExpr{sym, expr}
|
||||||
|
listNode := MakeNodeFromExprs(listElems)
|
||||||
|
listNode.location.DecStart(1)
|
||||||
|
listNode.location.IncStart(1)
|
||||||
|
return MakeList(listNode, listElems), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// readQuasiquotedExpr reads the backquote and replace it with a call
|
// readQuasiquotedExpr reads the backquote and replace it with a call
|
||||||
|
@ -452,16 +483,19 @@ func readQuasiquotedExpr(parser IParsable) (IExpr, IError) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
node := MakeNode(parser.Buffer(), parser.GetLocation(), parser.GetLocation())
|
node := MakeNode(parser.GetSource(), parser.GetLocation(), parser.GetLocation())
|
||||||
sym, err := MakeSymbol(node, "quasiquote")
|
sym, err := MakeSymbol(node, "quasiquote")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err.SetNode(&node)
|
err.SetNode(&node)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return MakeList([]IExpr{
|
|
||||||
sym,
|
listElems := []IExpr{sym, expr}
|
||||||
expr,
|
listNode := MakeNodeFromExprs(listElems)
|
||||||
}), nil
|
listNode.location.DecStart(1)
|
||||||
|
listNode.location.IncStart(1)
|
||||||
|
|
||||||
|
return MakeList(listNode, listElems), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// readExpr reads one expression from the input. This function is the most
|
// readExpr reads one expression from the input. This function is the most
|
||||||
|
@ -516,13 +550,14 @@ loop:
|
||||||
// by itself is not something available to the language. It's
|
// by itself is not something available to the language. It's
|
||||||
// just anbstraction for a ordered collection of expressions.
|
// just anbstraction for a ordered collection of expressions.
|
||||||
// It doesn't have anything to do with the concept of blocks
|
// It doesn't have anything to do with the concept of blocks
|
||||||
// from other programming languages
|
// from other programming languages.
|
||||||
func ParseToAST(input string) (*Block, IError) {
|
func ParseToAST(source string, input string) (*Block, IError) {
|
||||||
|
|
||||||
var ast Block
|
var ast Block
|
||||||
parser := StringParser{
|
parser := StringParser{
|
||||||
buffer: strings.Split(input, ""),
|
buffer: strings.Split(input, ""),
|
||||||
pos: 0,
|
pos: 0,
|
||||||
|
source: source,
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
|
@ -21,6 +21,8 @@ package core
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gookit/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
func toRepresanbleString(ast ...IRepresentable) string {
|
func toRepresanbleString(ast ...IRepresentable) string {
|
||||||
|
@ -63,6 +65,36 @@ func Println(rt *Runtime, ast ...IRepresentable) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func PrintError(rt *Runtime, err IError) {
|
func PrintError(rt *Runtime, err IError) {
|
||||||
|
trace := err.GetStackTrace()
|
||||||
|
|
||||||
|
for i, f := range *trace {
|
||||||
|
loc := f.Caller.GetLocation()
|
||||||
|
fmt.Println("===============")
|
||||||
|
fmt.Println(f.Fn.GetLocation())
|
||||||
|
fmt.Println(loc)
|
||||||
|
source := loc.GetSource()
|
||||||
|
// if loc.GetSource().Buffer != nil {
|
||||||
|
// fmt.Println(loc.GetSource().LineIndex)
|
||||||
|
// source = *loc.GetSource().Buffer
|
||||||
|
// }
|
||||||
|
startline := source.LineNumberFor(loc.GetStart()) - 1
|
||||||
|
endline := source.LineNumberFor(loc.GetEnd()) + 1
|
||||||
|
|
||||||
|
var lines string
|
||||||
|
for i := startline; i <= endline; i++ {
|
||||||
|
lines += fmt.Sprintf("%d:\t%s\n", i, source.GetLine(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
color.Yellow.Printf(
|
||||||
|
"%d: In function '%s' at '%s'\n",
|
||||||
|
i,
|
||||||
|
f.Fn.GetName(),
|
||||||
|
loc.GetSource().Path,
|
||||||
|
)
|
||||||
|
color.White.Printf("%s\n", lines)
|
||||||
|
}
|
||||||
loc := err.GetLocation()
|
loc := err.GetLocation()
|
||||||
fmt.Printf("Error: %s\nAt: %d to %d\n", err.String(), loc.GetStart(), loc.GetEnd())
|
|
||||||
|
errTag := color.Red.Sprint("ERROR")
|
||||||
|
fmt.Printf("%s: %s\nAt: %d to %d\n", errTag, err.String(), loc.GetStart(), loc.GetEnd())
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,10 +98,15 @@ func qqProcess(rt *Runtime, e IExpr) (IExpr, IError) {
|
||||||
// newErr.stack(err)
|
// newErr.stack(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return MakeList([]IExpr{
|
elems := []IExpr{
|
||||||
sym,
|
sym,
|
||||||
e,
|
e,
|
||||||
}), nil
|
}
|
||||||
|
|
||||||
|
return MakeList(
|
||||||
|
MakeNodeFromExprs(elems),
|
||||||
|
elems,
|
||||||
|
), nil
|
||||||
|
|
||||||
case ast.List:
|
case ast.List:
|
||||||
list := e.(*List)
|
list := e.(*List)
|
||||||
|
@ -125,7 +130,7 @@ func qqProcess(rt *Runtime, e IExpr) (IExpr, IError) {
|
||||||
}
|
}
|
||||||
// ???
|
// ???
|
||||||
if isUnquoteSplicing(first) {
|
if isUnquoteSplicing(first) {
|
||||||
return nil, MakeErrorFor(rt, first, "'unquote-splicing' is not allowed out of a collection.")
|
return nil, MakeError(rt, first, "'unquote-splicing' is not allowed out of a collection.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// p := list
|
// p := list
|
||||||
|
|
|
@ -18,6 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package core
|
package core
|
||||||
|
|
||||||
func ReadString(input string) (*Block, IError) {
|
func ReadString(src string, input string) (*Block, IError) {
|
||||||
return ParseToAST(input)
|
return ParseToAST(src, input)
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,8 +147,8 @@ func nsNameToPath(ns string) string {
|
||||||
// LoadNS looks up the namespace specified by the given name `ns`
|
// LoadNS looks up the namespace specified by the given name `ns`
|
||||||
// and reads the content as expressions (parse it) and returns the
|
// and reads the content as expressions (parse it) and returns the
|
||||||
// expressions.
|
// expressions.
|
||||||
func (r *Runtime) LoadNS(ns string) (*loadedForms, IError) {
|
func (r *Runtime) LoadNS(ns *Symbol) (*loadedForms, IError) {
|
||||||
nsFile := nsNameToPath(ns)
|
nsFile := nsNameToPath(ns.GetName())
|
||||||
for _, loadPath := range r.paths {
|
for _, loadPath := range r.paths {
|
||||||
possibleFile := path.Join(loadPath, nsFile)
|
possibleFile := path.Join(loadPath, nsFile)
|
||||||
|
|
||||||
|
@ -167,13 +167,14 @@ func (r *Runtime) LoadNS(ns string) (*loadedForms, IError) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
readError := MakeError(
|
readError := MakeError(
|
||||||
r,
|
r,
|
||||||
|
ns,
|
||||||
fmt.Sprintf("error while reading the file at %s", possibleFile),
|
fmt.Sprintf("error while reading the file at %s", possibleFile),
|
||||||
)
|
)
|
||||||
readError.WithError(err)
|
readError.WithError(err)
|
||||||
return nil, readError
|
return nil, readError
|
||||||
}
|
}
|
||||||
|
|
||||||
body, e := ReadString(string(data))
|
body, e := ReadString(possibleFile, string(data))
|
||||||
if e != nil {
|
if e != nil {
|
||||||
return nil, e
|
return nil, e
|
||||||
}
|
}
|
||||||
|
@ -182,7 +183,7 @@ func (r *Runtime) LoadNS(ns string) (*loadedForms, IError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add the load paths to the error message here
|
// TODO: Add the load paths to the error message here
|
||||||
return nil, MakeError(r, fmt.Sprintf("Can't find the namespace '%s' in any of load paths.", ns))
|
return nil, MakeError(r, ns, fmt.Sprintf("Can't find the namespace '%s' in any of load paths.", ns))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Runtime) InsertNS(nsName string, ns *Namespace) {
|
func (r *Runtime) InsertNS(nsName string, ns *Namespace) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ func Def(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
||||||
name := args.First()
|
name := args.First()
|
||||||
|
|
||||||
if name.GetType() != ast.Symbol {
|
if name.GetType() != ast.Symbol {
|
||||||
return nil, MakeError(rt, "the first argument of 'def' has to be a symbol")
|
return nil, MakeError(rt, name, "the first argument of 'def' has to be a symbol")
|
||||||
}
|
}
|
||||||
|
|
||||||
sym := name.(*Symbol)
|
sym := name.(*Symbol)
|
||||||
|
@ -55,7 +55,7 @@ func Def(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
||||||
return sym, nil
|
return sym, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, MakeError(rt, "'def' form need at least 2 arguments")
|
return nil, MakeError(rt, args, "'def' form need at least 2 arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Def defines a macro in the current namespace. The first
|
// Def defines a macro in the current namespace. The first
|
||||||
|
@ -72,7 +72,7 @@ func DefMacro(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
||||||
name := args.First()
|
name := args.First()
|
||||||
|
|
||||||
if name.GetType() != ast.Symbol {
|
if name.GetType() != ast.Symbol {
|
||||||
return nil, MakeError(rt, "the first argument of 'defmacro' has to be a symbol")
|
return nil, MakeError(rt, name, "the first argument of 'defmacro' has to be a symbol")
|
||||||
}
|
}
|
||||||
|
|
||||||
sym := name.(*Symbol)
|
sym := name.(*Symbol)
|
||||||
|
@ -100,21 +100,21 @@ func DefMacro(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
||||||
return macro, nil
|
return macro, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, MakeError(rt, "'defmacro' form need at least 2 arguments")
|
return nil, MakeError(rt, args, "'defmacro' form need at least 2 arguments")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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`.
|
||||||
// `args` contains the arugment list, docstring and body of the function.
|
// `args` contains the arugment list, docstring and body of the function.
|
||||||
func Fn(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
func Fn(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
||||||
|
|
||||||
if args.Count() < 1 {
|
if args.Count() < 2 {
|
||||||
return nil, MakeError(rt, "'fn' needs at least an arguments list")
|
return nil, MakeError(rt, args, "'fn' needs at least an arguments list")
|
||||||
}
|
}
|
||||||
|
|
||||||
var params IColl
|
var params IColl
|
||||||
body := MakeEmptyBlock()
|
body := MakeEmptyBlock()
|
||||||
|
|
||||||
arguments := args.First()
|
arguments := args.Rest().First()
|
||||||
|
|
||||||
// TODO: Add vector in here
|
// TODO: Add vector in here
|
||||||
// Or any other icoll
|
// Or any other icoll
|
||||||
|
@ -123,26 +123,26 @@ func Fn(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.Count() > 1 {
|
if args.Count() > 1 {
|
||||||
body.SetContent(args.Rest().(*List).ToSlice())
|
body.SetContent(args.Rest().Rest().(*List).ToSlice())
|
||||||
}
|
}
|
||||||
|
|
||||||
return MakeFunction(scope, params, body), nil
|
return MakeFunction(MakeNodeFromExpr(args.First()), scope, params, body), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NSForm(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
func NSForm(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
||||||
if args.Count() == 1 {
|
if args.Count() == 1 {
|
||||||
return nil, MakeErrorFor(rt, args, "namespace's name is missing")
|
return nil, MakeError(rt, args, "namespace's name is missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
name := args.Rest().First()
|
name := args.Rest().First()
|
||||||
|
|
||||||
if name.GetType() != ast.Symbol {
|
if name.GetType() != ast.Symbol {
|
||||||
return nil, MakeErrorFor(rt, name, "the first argument to the 'ns' has to be a symbol")
|
return nil, MakeError(rt, name, "the first argument to the 'ns' has to be a symbol")
|
||||||
}
|
}
|
||||||
nsName := name.(*Symbol).GetName()
|
nsName := name.(*Symbol).GetName()
|
||||||
|
|
||||||
if nsName != rt.CurrentNS().GetName() {
|
if nsName != rt.CurrentNS().GetName() {
|
||||||
return nil, MakeErrorFor(
|
return nil, MakeError(
|
||||||
rt,
|
rt,
|
||||||
args,
|
args,
|
||||||
fmt.Sprintf("the namespace '%s' doesn't match the file name.", nsName),
|
fmt.Sprintf("the namespace '%s' doesn't match the file name.", nsName),
|
||||||
|
@ -151,7 +151,7 @@ func NSForm(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
|
||||||
ns, ok := rt.GetNS(nsName)
|
ns, ok := rt.GetNS(nsName)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, MakeErrorFor(rt, name, fmt.Sprintf("can't find the namespace '%s'. Is it the same as the file name?", nsName))
|
return nil, MakeError(rt, name, fmt.Sprintf("can't find the namespace '%s'. Is it the same as the file name?", nsName))
|
||||||
}
|
}
|
||||||
|
|
||||||
return ns, nil
|
return ns, nil
|
||||||
|
|
|
@ -81,8 +81,8 @@ type Node struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetLocation returns the location of the Node in the source input
|
// GetLocation returns the location of the Node in the source input
|
||||||
func (n Node) GetLocation() ast.Location {
|
func (n Node) GetLocation() *ast.Location {
|
||||||
return n.location
|
return &n.location
|
||||||
}
|
}
|
||||||
|
|
||||||
type ExecutionScope struct {
|
type ExecutionScope struct {
|
||||||
|
@ -123,9 +123,9 @@ func toRepresentables(ast IColl) []IRepresentable {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeNodeFromLocation creates a new Node for the given Location `loc`
|
// MakeNodeFromLocation creates a new Node for the given Location `loc`
|
||||||
func MakeNodeFromLocation(loc ast.Location) Node {
|
func MakeNodeFromLocation(loc *ast.Location) Node {
|
||||||
return Node{
|
return Node{
|
||||||
location: loc,
|
location: *loc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,14 +136,30 @@ func MakeNodeFromExpr(e IExpr) Node {
|
||||||
return MakeNodeFromLocation(e.GetLocation())
|
return MakeNodeFromLocation(e.GetLocation())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeNodeFromExprs creates a new Node from the given slice of `IExpr`s.
|
||||||
|
// We use the Node to pass it to other IExpr constructors to
|
||||||
|
// keep the reference to the original form in the input string
|
||||||
|
func MakeNodeFromExprs(es []IExpr) Node {
|
||||||
|
if len(es) == 0 {
|
||||||
|
// TODO: This is temporary, fix it.
|
||||||
|
panic("can't create a node from empty elements.")
|
||||||
|
}
|
||||||
|
|
||||||
|
firstLoc := es[0].GetLocation()
|
||||||
|
endLoc := es[len(es)-1].GetLocation()
|
||||||
|
loc := ast.MakeLocation(firstLoc.GetSource(), firstLoc.GetStart(), endLoc.GetEnd())
|
||||||
|
|
||||||
|
return MakeNodeFromLocation(loc)
|
||||||
|
}
|
||||||
|
|
||||||
// MakeNode creates a new Node in the the given `input` that points to a
|
// MakeNode creates a new Node in the the given `input` that points to a
|
||||||
// range of characters starting from the `start` till the `end`.
|
// range of characters starting from the `start` till the `end`.
|
||||||
func MakeNode(input *[]string, start int, end int) Node {
|
func MakeNode(input *ast.Source, start int, end int) Node {
|
||||||
return MakeNodeFromLocation(ast.MakeLocation(input, start, end))
|
return MakeNodeFromLocation(ast.MakeLocation(input, start, end))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeSinglePointNode creates a not the points to a single char in the
|
// MakeSinglePointNode creates a not the points to a single char in the
|
||||||
// input
|
// input
|
||||||
func MakeSinglePointNode(input *[]string, point int) Node {
|
func MakeSinglePointNode(input *ast.Source, point int) Node {
|
||||||
return MakeNode(input, point, point)
|
return MakeNode(input, point, point)
|
||||||
}
|
}
|
||||||
|
|
1
dev.org
1
dev.org
|
@ -35,6 +35,7 @@ https://www.reddit.com/r/ProgrammingLanguages/comments/8ggx2n/is_llvm_a_good_bac
|
||||||
- Official LLVM tutorial C++ :: https://llvm.org/docs/tutorial/
|
- Official LLVM tutorial C++ :: https://llvm.org/docs/tutorial/
|
||||||
- Interactive C++ with Cling :: https://blog.llvm.org/posts/2020-11-30-interactive-cpp-with-cling/
|
- Interactive C++ with Cling :: https://blog.llvm.org/posts/2020-11-30-interactive-cpp-with-cling/
|
||||||
- My First LLVM Compiler :: https://www.wilfred.me.uk/blog/2015/02/21/my-first-llvm-compiler/
|
- My First LLVM Compiler :: https://www.wilfred.me.uk/blog/2015/02/21/my-first-llvm-compiler/
|
||||||
|
- A Complete Guide to LLVM for Programming Language Creators :: https://mukulrathi.co.uk/create-your-own-programming-language/llvm-ir-cpp-api-tutorial/
|
||||||
** Data structures
|
** Data structures
|
||||||
- Pure functional datastructures papaer :: https://www.cs.cmu.edu/~rwh/theses/okasaki.pdf
|
- Pure functional datastructures papaer :: https://www.cs.cmu.edu/~rwh/theses/okasaki.pdf
|
||||||
- Dynamic typing: syntax and proof theory :: https://reader.elsevier.com/reader/sd/pii/0167642394000042?token=CEFF5C5D1B03FD680762FC4889A14C0CA2BB28FE390EC51099984536E12AC358F3D28A5C25C274296ACBBC32E5AE23CD
|
- Dynamic typing: syntax and proof theory :: https://reader.elsevier.com/reader/sd/pii/0167642394000042?token=CEFF5C5D1B03FD680762FC4889A14C0CA2BB28FE390EC51099984536E12AC358F3D28A5C25C274296ACBBC32E5AE23CD
|
||||||
|
|
Loading…
Reference in New Issue