diff --git a/bootstrap/examples/hello-world.srn b/bootstrap/examples/hello-world.srn
index 460fdd9..f206f87 100644
--- a/bootstrap/examples/hello-world.srn
+++ b/bootstrap/examples/hello-world.srn
@@ -9,7 +9,7 @@
(name args &body)
(list 'def name (cons 'fn (cons args body))))
-(defn pp (x)
+(defn pp (x y)
(println x))
(def main
diff --git a/bootstrap/go.mod b/bootstrap/go.mod
index 24fb38b..8d2dafb 100644
--- a/bootstrap/go.mod
+++ b/bootstrap/go.mod
@@ -4,6 +4,7 @@ go 1.15
require (
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/spf13/cobra v1.1.1
github.com/spf13/viper v1.7.1
diff --git a/bootstrap/go.sum b/bootstrap/go.sum
index 04c2ecb..0a71ec0 100644
--- a/bootstrap/go.sum
+++ b/bootstrap/go.sum
@@ -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/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/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/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=
diff --git a/bootstrap/pkg/ast/ast.go b/bootstrap/pkg/ast/ast.go
index 298ce47..8bd421f 100644
--- a/bootstrap/pkg/ast/ast.go
+++ b/bootstrap/pkg/ast/ast.go
@@ -20,6 +20,11 @@ along with this program. If not, see .
// Serene's AST.
package ast
+import (
+ "sort"
+ "strings"
+)
+
type NodeType int
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 {
start int
end int
- source *[]string
+ source Source
knownLocation bool
}
+var UnknownLocation *Location = &Location{knownLocation: false}
+
func (l *Location) GetStart() int {
return l.start
}
@@ -55,8 +89,42 @@ func (l *Location) GetEnd() int {
return l.end
}
-func (l *Location) GetSource() *[]string {
- return l.source
+func (l *Location) GetSource() *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 {
@@ -64,12 +132,12 @@ func (l *Location) IsKnownLocaiton() bool {
}
type ILocatable interface {
- GetLocation() Location
+ GetLocation() *Location
}
-func MakeLocation(input *[]string, start int, end int) Location {
- return Location{
- source: input,
+func MakeLocation(input *Source, start int, end int) *Location {
+ return &Location{
+ source: *input,
start: start,
end: end,
knownLocation: true,
@@ -80,8 +148,6 @@ type ITypable interface {
GetType() NodeType
}
-func MakeUnknownLocation() Location {
- return Location{
- knownLocation: false,
- }
+func MakeUnknownLocation() *Location {
+ return UnknownLocation
}
diff --git a/bootstrap/pkg/core/block.go b/bootstrap/pkg/core/block.go
index 308f9a3..8b7fef1 100644
--- a/bootstrap/pkg/core/block.go
+++ b/bootstrap/pkg/core/block.go
@@ -51,7 +51,7 @@ func (b *Block) ToDebugStr() string {
return fmt.Sprintf("%#v", b)
}
-func (b *Block) GetLocation() ast.Location {
+func (b *Block) GetLocation() *ast.Location {
if len(b.body) > 0 {
return b.body[0].GetLocation()
}
diff --git a/bootstrap/pkg/core/builtins.go b/bootstrap/pkg/core/builtins.go
index 08cb606..f96a87d 100644
--- a/bootstrap/pkg/core/builtins.go
+++ b/bootstrap/pkg/core/builtins.go
@@ -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) {
switch args.Count() {
case 0:
- return nil, MakeErrorFor(rt, args, "'require' function is missing")
+ return nil, MakeError(rt, args, "'require' function is missing")
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:
}
@@ -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) {
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()
diff --git a/bootstrap/pkg/core/call_stack.go b/bootstrap/pkg/core/call_stack.go
index 51b5883..d8023c7 100644
--- a/bootstrap/pkg/core/call_stack.go
+++ b/bootstrap/pkg/core/call_stack.go
@@ -33,38 +33,51 @@ package core
// compare the stack items by their address, identity and location.
// * Add support for iteration on the stack.
-import "fmt"
+import (
+ "fmt"
+)
type ICallStack interface {
// Push the given callable `f` to the stack
Push(f IFn) IError
- Pop() FnCall
+ Pop() *Frame
+ Peek() *Frame
Count() uint
}
-type FnCall struct {
- Fn IFn
+type Frame struct {
// Number of recursive calls to this function
- count uint
+ Count uint
+ Fn IFn
+ Caller IExpr
}
+type TraceBack = []Frame
+
type CallStackItem struct {
prev *CallStackItem
- data FnCall
+ data Frame
}
type CallStack struct {
+ debug bool
head *CallStackItem
count uint
- debug bool
}
func (c *CallStack) Count() uint {
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 {
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.")
}
+ if caller == nil {
+ return MakePlainError("Can't push 'nil' pointer to the call stack for the caller.")
+ }
+
// Empty Stack
if c.head == nil {
c.head = &CallStackItem{
- data: FnCall{
- Fn: f,
- count: 0,
+ data: Frame{
+ Fn: f,
+ Caller: caller,
+ Count: 0,
},
}
c.count++
@@ -87,15 +105,16 @@ func (c *CallStack) Push(f IFn) IError {
nodeData := &c.head.data
// 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
- nodeData.count++
+ nodeData.Count++
} else {
c.head = &CallStackItem{
prev: c.head,
- data: FnCall{
- Fn: f,
- count: 0,
+ data: Frame{
+ Fn: f,
+ Caller: caller,
+ Count: 0,
},
}
c.count++
@@ -103,7 +122,7 @@ func (c *CallStack) Push(f IFn) IError {
return nil
}
-func (c *CallStack) Pop() *FnCall {
+func (c *CallStack) Pop() *Frame {
if c.head == nil {
if c.debug {
fmt.Println("[Stack] <-- nil")
@@ -120,6 +139,32 @@ func (c *CallStack) Pop() *FnCall {
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 {
return CallStack{
count: 0,
diff --git a/bootstrap/pkg/core/core.go b/bootstrap/pkg/core/core.go
index e5aa750..ac40a56 100644
--- a/bootstrap/pkg/core/core.go
+++ b/bootstrap/pkg/core/core.go
@@ -23,13 +23,14 @@ import (
"fmt"
"os"
"path/filepath"
+ "strings"
"github.com/chzyer/readline"
"serene-lang.org/bootstrap/pkg/ast"
)
func rep(rt *Runtime, line string) {
- ast, err := ReadString(line)
+ ast, err := ReadString("*REPL*", line)
if err != nil {
PrintError(rt, err)
@@ -120,7 +121,17 @@ func Run(flags map[string]bool, args []string) {
}
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 {
PrintError(rt, err)
@@ -133,6 +144,7 @@ func Run(flags map[string]bool, args []string) {
if !inserted {
err := MakeError(
rt,
+ loadedNS,
fmt.Sprintf(
"the namespace '%s' didn't get inserted in the runtime.",
loadedNS.GetName()),
@@ -163,24 +175,22 @@ func Run(flags map[string]bool, args []string) {
mainFn := mainBinding.Value.(*Function)
var fnArgs []IExpr
+ var argNode Node
if len(args) > 1 {
for _, arg := range args[1:] {
node := MakeNodeFromExpr(mainFn)
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(fnArgs))
+ _, err = mainFn.Apply(rt, loadedNS.GetRootScope(), mainFn.Node, MakeList(argNode, fnArgs))
if err != nil {
PrintError(rt, err)
os.Exit(1)
}
-
- // rt.Stack.Pop()
- // if rt.Stack.Count() != 0 {
- // panic("Call stack is not empty.")
- // }
}
diff --git a/bootstrap/pkg/core/errors.go b/bootstrap/pkg/core/errors.go
index 7e3d4aa..35f8a83 100644
--- a/bootstrap/pkg/core/errors.go
+++ b/bootstrap/pkg/core/errors.go
@@ -49,6 +49,7 @@ type IError interface {
IRepresentable
IDebuggable
+ GetStackTrace() *TraceBack
// To wrap Golan rrrrors
WithError(err error) IError
@@ -62,6 +63,7 @@ type Error struct {
Node
WrappedErr error
msg string
+ trace *TraceBack
}
func (e *Error) String() string {
@@ -89,32 +91,25 @@ func (e *Error) Error() string {
return e.msg
}
+func (e *Error) GetStackTrace() *TraceBack {
+ return e.trace
+}
+
func MakePlainError(msg string) IError {
return &Error{
msg: msg,
}
}
-// MakeError creates an Error without any location.
-func MakeError(rt *Runtime, msg string) IError {
- return MakePlainError(msg)
-}
-
-// MakeErrorFor creates an Error which points to the given IExpr `e` as
+// MakeError creates an Error which points to the given IExpr `e` as
// the root of the error.
-func MakeErrorFor(rt *Runtime, e IExpr, msg string) IError {
- loc := e.GetLocation()
+func MakeError(rt *Runtime, e IExpr, msg string) IError {
+ trace := append(*rt.Stack.ToTraceBack(), Frame{0, rt.Stack.GetCurrentFn(), e})
return &Error{
- Node: MakeNodeFromLocation(loc),
- msg: msg,
- }
-}
-
-//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...),
+ Node: MakeNodeFromExpr(e),
+ msg: msg,
+ trace: &trace,
}
}
diff --git a/bootstrap/pkg/core/eval.go b/bootstrap/pkg/core/eval.go
index a7dd0e4..b73a950 100644
--- a/bootstrap/pkg/core/eval.go
+++ b/bootstrap/pkg/core/eval.go
@@ -84,7 +84,7 @@ func evalForm(rt *Runtime, scope IScope, form IExpr) (IExpr, IError) {
if sym.IsNSQualified() {
// Whether a namespace with the given alias loaded or not
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()),
)
}
@@ -97,11 +97,14 @@ func evalForm(rt *Runtime, scope IScope, form IExpr) (IExpr, IError) {
}
if expr == nil {
- return nil, MakeRuntimeErrorf(
+ return nil, MakeError(
rt,
- "can't resolve symbol '%s' in ns '%s'",
- symbolName,
- nsName,
+ sym,
+ fmt.Sprintf(
+ "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
}
}
- return MakeList(result), nil
+
+ return MakeList(MakeNodeFromExpr(lst), result), nil
}
// 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)
@@ -185,7 +189,6 @@ tco:
body:
for i := 0; i < len(exprs); i++ {
- //for i, forms := range exprs {
forms := exprs[i]
executionScope := forms.GetExecutionScope()
scope := scope
@@ -275,7 +278,7 @@ tco:
case "quote":
// Including the `quote` itself
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()
err = nil
@@ -310,12 +313,18 @@ tco:
result := []IExpr{}
for _, lst := range lists {
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()...)
}
- 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
// TODO: Implement `list` in serene itself when we have destructuring available
@@ -324,7 +333,7 @@ tco:
// given in the second argument.
case "cons":
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))
@@ -335,7 +344,7 @@ tco:
coll, ok := evaledForms.(*List).Rest().First().(IColl)
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
@@ -366,7 +375,7 @@ tco:
// as a macro and returns the expanded forms.
case "macroexpand":
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))
@@ -381,7 +390,7 @@ tco:
// * It needs at least a collection of arguments
// * Defines an anonymous function.
case "fn":
- ret, err = Fn(rt, scope, list.Rest().(*List))
+ ret, err = Fn(rt, scope, list)
continue body // no rewrite
// `if` evaluation rules:
@@ -392,7 +401,7 @@ tco:
case "if":
args := list.Rest().(*List)
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())
@@ -436,7 +445,7 @@ tco:
// the result.
case "eval":
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))
if err != nil {
@@ -457,7 +466,7 @@ tco:
// which is the result of the last expre in `BODY`
case "let":
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))
@@ -470,7 +479,7 @@ tco:
body := list.Rest().Rest().(*List).ToSlice()
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 {
@@ -485,7 +494,7 @@ tco:
// TODO: We need to destruct the bindings here and remove this check
// for the symbol type
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
}
@@ -546,7 +555,7 @@ tco:
break body //return
}
- rt.Stack.Push(fn)
+ rt.Stack.Push(list, fn)
body := append(
fn.GetBody().ToSlice(),
// Add the PopStack instruction to clean up the stack after
@@ -561,7 +570,8 @@ tco:
// by the `NativeFunction` struct
case ast.NativeFn:
fn := f.(*NativeFunction)
- rt.Stack.Push(fn)
+
+ rt.Stack.Push(list, fn)
ret, err = fn.Apply(
rt,
scope,
@@ -572,7 +582,7 @@ tco:
continue body // no rewrite
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
break tco
}
@@ -613,7 +623,7 @@ func EvalNSBody(rt *Runtime, ns *Namespace) (*Namespace, IError) {
exprs := body.ToSlice()
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 {
@@ -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()))
}
diff --git a/bootstrap/pkg/core/function.go b/bootstrap/pkg/core/function.go
index b183b1b..da357a4 100644
--- a/bootstrap/pkg/core/function.go
+++ b/bootstrap/pkg/core/function.go
@@ -48,8 +48,9 @@ import (
type nativeFnHandler = func(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IError)
type IFn interface {
- ast.ILocatable
+ IExpr
Apply(rt *Runtime, scope IScope, n Node, args *List) (IExpr, IError)
+ GetName() string
}
// 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
// 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{
+ Node: n,
scope: scope,
params: params,
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)
}
- 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()))
}
@@ -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 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
// 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
// next.
- rest := MakeEmptyList()
+ rest := MakeEmptyList(MakeNodeFromExpr(binds[i]))
if i == len(exprs)-1 {
// If the number of values matches the number of bindings
// 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)
- 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)
@@ -215,6 +227,10 @@ func (f *NativeFunction) GetType() ast.NodeType {
return ast.NativeFn
}
+func (f *NativeFunction) GetName() string {
+ return f.name
+}
+
func (f *NativeFunction) String() string {
return fmt.Sprintf("", f.name, f)
}
diff --git a/bootstrap/pkg/core/keyword.go b/bootstrap/pkg/core/keyword.go
index 629bebd..d2a1c39 100644
--- a/bootstrap/pkg/core/keyword.go
+++ b/bootstrap/pkg/core/keyword.go
@@ -159,7 +159,7 @@ func (k *Keyword) Eval(rt *Runtime, scope IScope) (*Keyword, IError) {
}
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
return k, nil
diff --git a/bootstrap/pkg/core/list.go b/bootstrap/pkg/core/list.go
index e1b744e..1e3c2fc 100644
--- a/bootstrap/pkg/core/list.go
+++ b/bootstrap/pkg/core/list.go
@@ -70,9 +70,16 @@ func (l *List) First() IExpr {
func (l *List) Rest() ISeq {
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 {
@@ -97,8 +104,8 @@ func (l *List) ToSlice() []IExpr {
}
func (l *List) Cons(e IExpr) IExpr {
- elems := l.ToSlice()
- return MakeList(append([]IExpr{e}, elems...))
+ elements := append([]IExpr{e}, l.ToSlice()...)
+ return MakeList(MakeNodeFromExprs(elements), elements)
}
// END: IColl ---
@@ -118,14 +125,16 @@ func ListStartsWith(l *List, sym string) bool {
return false
}
-func MakeList(elements []IExpr) *List {
+func MakeList(n Node, elements []IExpr) *List {
return &List{
+ Node: n,
exprs: elements,
}
}
-func MakeEmptyList() *List {
+func MakeEmptyList(n Node) *List {
return &List{
+ Node: n,
exprs: []IExpr{},
}
}
diff --git a/bootstrap/pkg/core/namespace.go b/bootstrap/pkg/core/namespace.go
index a185ab9..0a2b48e 100644
--- a/bootstrap/pkg/core/namespace.go
+++ b/bootstrap/pkg/core/namespace.go
@@ -56,7 +56,7 @@ func (n *Namespace) GetType() ast.NodeType {
return ast.Namespace
}
-func (n *Namespace) GetLocation() ast.Location {
+func (n *Namespace) GetLocation() *ast.Location {
return ast.MakeUnknownLocation()
}
@@ -141,7 +141,7 @@ func (n *Namespace) getForms() *Block {
// requireNS finds and loads the namespace addressed by the given
// `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
loadedForms, err := rt.LoadNS(ns)
@@ -155,11 +155,12 @@ func requireNS(rt *Runtime, ns string) (*Namespace, IError) {
if body.Count() == 0 {
return nil, MakeError(
rt,
+ body,
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)
return &namespace, nil
@@ -188,21 +189,21 @@ func RequireNamespace(rt *Runtime, namespace IExpr) (IExpr, IError) {
first := list.First()
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()
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)
alias = second.(*Symbol).GetName()
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 {
return nil, err
@@ -217,6 +218,7 @@ func RequireNamespace(rt *Runtime, namespace IExpr) (IExpr, IError) {
if !inserted {
return nil, MakeError(
rt,
+ loadedNS,
fmt.Sprintf(
"the namespace '%s' didn't get inserted in the runtime.",
loadedNS.GetName()),
@@ -231,6 +233,7 @@ func RequireNamespace(rt *Runtime, namespace IExpr) (IExpr, IError) {
if !inserted {
return nil, MakeError(
rt,
+ loadedNS,
fmt.Sprintf(
"can't set the current ns back to '%s' from '%s'.",
prevNS.GetName(),
diff --git a/bootstrap/pkg/core/nothing.go b/bootstrap/pkg/core/nothing.go
index cb33351..118ed7f 100644
--- a/bootstrap/pkg/core/nothing.go
+++ b/bootstrap/pkg/core/nothing.go
@@ -36,7 +36,7 @@ func (n NothingType) Hash() uint32 {
return hash.HashOf(append([]byte{byte(ast.Block)}, bytes...))
}
-func (n NothingType) GetLocation() ast.Location {
+func (n NothingType) GetLocation() *ast.Location {
return ast.MakeUnknownLocation()
}
diff --git a/bootstrap/pkg/core/parser.go b/bootstrap/pkg/core/parser.go
index 10a9554..59234c9 100644
--- a/bootstrap/pkg/core/parser.go
+++ b/bootstrap/pkg/core/parser.go
@@ -33,6 +33,8 @@ package core
import (
"strings"
"unicode"
+
+ "serene-lang.org/bootstrap/pkg/ast"
)
// 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
GetLocation() int
+ GetSource() *ast.Source
Buffer() *[]string
}
// StringParser is an implementation of the IParsable that operates on strings.
// To put it simply it parses input strings
type StringParser struct {
- buffer []string
- pos int
+ buffer []string
+ pos int
+ source string
+ lineIndex []int
}
// Implementing IParsable for StringParser ---
@@ -75,6 +80,12 @@ func (sp *StringParser) next(skipWhitespace bool) *string {
return nil
}
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
if skipWhitespace && isSeparator(&char) {
@@ -127,6 +138,14 @@ func (sp *StringParser) GetLocation() int {
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 {
return &sp.buffer
}
@@ -136,7 +155,7 @@ func (sp *StringParser) Buffer() *[]string {
// makeErrorAtPoint is a helper function which generates an `IError` that
// points at the current position of the buffer.
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...)
}
@@ -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)
if err != nil {
@@ -228,7 +247,7 @@ func readString(parser IParsable) (IExpr, IError) {
}
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
}
@@ -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) {
@@ -387,7 +409,7 @@ func readQuotedExpr(parser IParsable) (IExpr, IError) {
return nil, err
}
- symNode := MakeNode(parser.Buffer(), parser.GetLocation(), parser.GetLocation())
+ symNode := MakeNode(parser.GetSource(), parser.GetLocation(), parser.GetLocation())
sym, err := MakeSymbol(symNode, "quote")
if err != nil {
@@ -395,10 +417,15 @@ func readQuotedExpr(parser IParsable) (IExpr, IError) {
return nil, err
}
- return MakeList([]IExpr{
+ listElems := []IExpr{
sym,
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.
@@ -417,7 +444,7 @@ func readUnquotedExpr(parser IParsable) (IExpr, IError) {
var err IError
var expr IExpr
- node := MakeNode(parser.Buffer(), parser.GetLocation(), parser.GetLocation())
+ node := MakeNode(parser.GetSource(), parser.GetLocation(), parser.GetLocation())
if *c == "@" {
parser.next(true)
@@ -441,7 +468,11 @@ func readUnquotedExpr(parser IParsable) (IExpr, IError) {
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
@@ -452,16 +483,19 @@ func readQuasiquotedExpr(parser IParsable) (IExpr, IError) {
return nil, err
}
- node := MakeNode(parser.Buffer(), parser.GetLocation(), parser.GetLocation())
+ node := MakeNode(parser.GetSource(), parser.GetLocation(), parser.GetLocation())
sym, err := MakeSymbol(node, "quasiquote")
if err != nil {
err.SetNode(&node)
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
}
// 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
// just anbstraction for a ordered collection of expressions.
// It doesn't have anything to do with the concept of blocks
-// from other programming languages
-func ParseToAST(input string) (*Block, IError) {
+// from other programming languages.
+func ParseToAST(source string, input string) (*Block, IError) {
var ast Block
parser := StringParser{
buffer: strings.Split(input, ""),
pos: 0,
+ source: source,
}
for {
diff --git a/bootstrap/pkg/core/printer.go b/bootstrap/pkg/core/printer.go
index 462ed08..97fd7a9 100644
--- a/bootstrap/pkg/core/printer.go
+++ b/bootstrap/pkg/core/printer.go
@@ -21,6 +21,8 @@ package core
import (
"fmt"
"strings"
+
+ "github.com/gookit/color"
)
func toRepresanbleString(ast ...IRepresentable) string {
@@ -63,6 +65,36 @@ func Println(rt *Runtime, ast ...IRepresentable) {
}
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()
- 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())
}
diff --git a/bootstrap/pkg/core/quasiquote.go b/bootstrap/pkg/core/quasiquote.go
index ed402cf..53c679e 100644
--- a/bootstrap/pkg/core/quasiquote.go
+++ b/bootstrap/pkg/core/quasiquote.go
@@ -98,10 +98,15 @@ func qqProcess(rt *Runtime, e IExpr) (IExpr, IError) {
// newErr.stack(err)
return nil, err
}
- return MakeList([]IExpr{
+ elems := []IExpr{
sym,
e,
- }), nil
+ }
+
+ return MakeList(
+ MakeNodeFromExprs(elems),
+ elems,
+ ), nil
case ast.List:
list := e.(*List)
@@ -125,7 +130,7 @@ func qqProcess(rt *Runtime, e IExpr) (IExpr, IError) {
}
// ???
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
diff --git a/bootstrap/pkg/core/reader.go b/bootstrap/pkg/core/reader.go
index 3c638d9..040ba88 100644
--- a/bootstrap/pkg/core/reader.go
+++ b/bootstrap/pkg/core/reader.go
@@ -18,6 +18,6 @@ along with this program. If not, see .
package core
-func ReadString(input string) (*Block, IError) {
- return ParseToAST(input)
+func ReadString(src string, input string) (*Block, IError) {
+ return ParseToAST(src, input)
}
diff --git a/bootstrap/pkg/core/runtime.go b/bootstrap/pkg/core/runtime.go
index 9aab2cf..bca2701 100644
--- a/bootstrap/pkg/core/runtime.go
+++ b/bootstrap/pkg/core/runtime.go
@@ -147,8 +147,8 @@ func nsNameToPath(ns string) string {
// LoadNS looks up the namespace specified by the given name `ns`
// and reads the content as expressions (parse it) and returns the
// expressions.
-func (r *Runtime) LoadNS(ns string) (*loadedForms, IError) {
- nsFile := nsNameToPath(ns)
+func (r *Runtime) LoadNS(ns *Symbol) (*loadedForms, IError) {
+ nsFile := nsNameToPath(ns.GetName())
for _, loadPath := range r.paths {
possibleFile := path.Join(loadPath, nsFile)
@@ -167,13 +167,14 @@ func (r *Runtime) LoadNS(ns string) (*loadedForms, IError) {
if err != nil {
readError := MakeError(
r,
+ ns,
fmt.Sprintf("error while reading the file at %s", possibleFile),
)
readError.WithError(err)
return nil, readError
}
- body, e := ReadString(string(data))
+ body, e := ReadString(possibleFile, string(data))
if e != nil {
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
- 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) {
diff --git a/bootstrap/pkg/core/sforms.go b/bootstrap/pkg/core/sforms.go
index b5d2585..aaa806f 100644
--- a/bootstrap/pkg/core/sforms.go
+++ b/bootstrap/pkg/core/sforms.go
@@ -34,7 +34,7 @@ func Def(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
name := args.First()
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)
@@ -55,7 +55,7 @@ func Def(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
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
@@ -72,7 +72,7 @@ func DefMacro(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
name := args.First()
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)
@@ -100,21 +100,21 @@ func DefMacro(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
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`.
// `args` contains the arugment list, docstring and body of the function.
func Fn(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
- if args.Count() < 1 {
- return nil, MakeError(rt, "'fn' needs at least an arguments list")
+ if args.Count() < 2 {
+ return nil, MakeError(rt, args, "'fn' needs at least an arguments list")
}
var params IColl
body := MakeEmptyBlock()
- arguments := args.First()
+ arguments := args.Rest().First()
// TODO: Add vector in here
// Or any other icoll
@@ -123,26 +123,26 @@ func Fn(rt *Runtime, scope IScope, args *List) (IExpr, IError) {
}
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) {
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()
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()
if nsName != rt.CurrentNS().GetName() {
- return nil, MakeErrorFor(
+ return nil, MakeError(
rt,
args,
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)
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
diff --git a/bootstrap/pkg/core/types.go b/bootstrap/pkg/core/types.go
index a176d52..78ac526 100644
--- a/bootstrap/pkg/core/types.go
+++ b/bootstrap/pkg/core/types.go
@@ -81,8 +81,8 @@ type Node struct {
}
// GetLocation returns the location of the Node in the source input
-func (n Node) GetLocation() ast.Location {
- return n.location
+func (n Node) GetLocation() *ast.Location {
+ return &n.location
}
type ExecutionScope struct {
@@ -123,9 +123,9 @@ func toRepresentables(ast IColl) []IRepresentable {
}
// MakeNodeFromLocation creates a new Node for the given Location `loc`
-func MakeNodeFromLocation(loc ast.Location) Node {
+func MakeNodeFromLocation(loc *ast.Location) Node {
return Node{
- location: loc,
+ location: *loc,
}
}
@@ -136,14 +136,30 @@ func MakeNodeFromExpr(e IExpr) Node {
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
// 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))
}
// MakeSinglePointNode creates a not the points to a single char in the
// input
-func MakeSinglePointNode(input *[]string, point int) Node {
+func MakeSinglePointNode(input *ast.Source, point int) Node {
return MakeNode(input, point, point)
}
diff --git a/dev.org b/dev.org
index f6e9ede..0d387f0 100644
--- a/dev.org
+++ b/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/
- 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/
+- 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
- 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