[Bootstrap] Use Serene itself to load and run the main function
This commit consist a series of fixes to make the reach the main goal of the commit: * Fix the 'MakeNodeFromExprs' behavior so it returns a pointer to a node and if the number of input exprs is zero then nil. * Fix all the eval loop to return immediately in case of any error duh! * Add a `errtype` field to `Error` with an `ErrType` enum type that indicates the type of the error, the type being syntax, semantic and runtime error at the moment. * Rename some of the Error functions to match the error type. For Exapmle `MakeSyntaxError` and `MakeSemanticError`
This commit is contained in:
parent
e895377811
commit
9be27c124a
|
@ -20,15 +20,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
package core
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/chzyer/readline"
|
||||
"serene-lang.org/bootstrap/pkg/ast"
|
||||
)
|
||||
|
||||
type mainRunner struct {
|
||||
NS string
|
||||
Args string
|
||||
}
|
||||
|
||||
func rep(rt *Runtime, line string) {
|
||||
ast, err := ReadString("*REPL*", line)
|
||||
|
||||
|
@ -113,6 +118,7 @@ func Run(flags map[string]bool, args []string) {
|
|||
}
|
||||
|
||||
rt := MakeRuntime([]string{cwd}, flags)
|
||||
rt.CreateNS("user", "REPL", true)
|
||||
|
||||
if len(args) == 0 {
|
||||
|
||||
|
@ -120,77 +126,51 @@ func Run(flags map[string]bool, args []string) {
|
|||
os.Exit(1)
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
arguments := ""
|
||||
ns := args[0]
|
||||
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)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
rt.InsertNS(ns, loadedNS)
|
||||
inserted := rt.setCurrentNS(loadedNS.GetName())
|
||||
|
||||
if !inserted {
|
||||
err := MakeError(
|
||||
rt,
|
||||
loadedNS,
|
||||
fmt.Sprintf(
|
||||
"the namespace '%s' didn't get inserted in the runtime.",
|
||||
loadedNS.GetName()),
|
||||
)
|
||||
PrintError(rt, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Evaluating the body of the loaded ns (Check for ns validation happens here)
|
||||
loadedNS, err = EvalNSBody(rt, loadedNS)
|
||||
if err != nil {
|
||||
PrintError(rt, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
mainBinding := loadedNS.GetRootScope().Lookup(rt, "main")
|
||||
|
||||
if mainBinding == nil {
|
||||
PrintError(rt, MakePlainError(fmt.Sprintf("can't find the 'main' function in '%s' namespace", ns)))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if mainBinding.Value.GetType() != ast.Fn {
|
||||
PrintError(rt, MakePlainError("'main' is not a function"))
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
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))
|
||||
arguments += "\"" + arg + "\""
|
||||
}
|
||||
argNode = MakeNodeFromExprs(fnArgs)
|
||||
} else {
|
||||
argNode = node
|
||||
}
|
||||
|
||||
_, err = mainFn.Apply(rt, loadedNS.GetRootScope(), mainFn.Node, MakeList(argNode, fnArgs))
|
||||
tmpl, e := template.New("run").Parse(
|
||||
`(def run-main
|
||||
(fn ()
|
||||
(require '({{.NS}} n))
|
||||
(n/main {{.Args}})))
|
||||
|
||||
(run-main)`,
|
||||
)
|
||||
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
e = tmpl.Execute(&buf, &mainRunner{ns, arguments})
|
||||
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
|
||||
if rt.IsDebugMode() {
|
||||
fmt.Println("[DEBUG] Evaluating the following form to run the 'main' fn:")
|
||||
fmt.Println(buf.String())
|
||||
}
|
||||
|
||||
ast, err := ReadString("*RUN*", buf.String())
|
||||
|
||||
if err != nil {
|
||||
PrintError(rt, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
_, err = Eval(rt, ast)
|
||||
|
||||
if err != nil {
|
||||
PrintError(rt, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,14 @@ import (
|
|||
"serene-lang.org/bootstrap/pkg/errors"
|
||||
)
|
||||
|
||||
type ErrType uint8
|
||||
|
||||
const (
|
||||
SyntaxError ErrType = iota
|
||||
SemanticError
|
||||
RuntimeError
|
||||
)
|
||||
|
||||
// IError defines the necessary functionality of the internal errors.
|
||||
type IError interface {
|
||||
// In order to point to a specific point in the input
|
||||
|
@ -50,6 +58,7 @@ type IError interface {
|
|||
IRepresentable
|
||||
IDebuggable
|
||||
|
||||
GetErrType() ErrType
|
||||
GetDescription() *string
|
||||
GetStackTrace() *TraceBack
|
||||
// To wrap Golan rrrrors
|
||||
|
@ -63,6 +72,7 @@ type IError interface {
|
|||
|
||||
type Error struct {
|
||||
Node
|
||||
errtype ErrType
|
||||
errno errors.Errno
|
||||
WrappedErr error
|
||||
msg string
|
||||
|
@ -81,6 +91,10 @@ func (e *Error) ToDebugStr() string {
|
|||
return fmt.Sprintf("%s:\n\t%s", e.msg, e.WrappedErr.Error())
|
||||
}
|
||||
|
||||
func (e *Error) GetErrType() ErrType {
|
||||
return e.errtype
|
||||
}
|
||||
|
||||
func (e *Error) WithError(err error) IError {
|
||||
e.WrappedErr = err
|
||||
return e
|
||||
|
@ -117,19 +131,22 @@ func MakePlainError(msg string) IError {
|
|||
// MakeError creates an Error which points to the given IExpr `e` as
|
||||
// the root of the error.
|
||||
func MakeError(rt *Runtime, e IExpr, msg string) IError {
|
||||
trace := append(*rt.Stack.ToTraceBack(), &Frame{0, rt.Stack.GetCurrentFn(), e})
|
||||
frame := MakeFrame(e, rt.Stack.GetCurrentFn(), 1)
|
||||
trace := append(*rt.Stack.ToTraceBack(), frame)
|
||||
|
||||
return &Error{
|
||||
Node: MakeNodeFromExpr(e),
|
||||
msg: msg,
|
||||
trace: &trace,
|
||||
Node: MakeNodeFromExpr(e),
|
||||
errtype: RuntimeError,
|
||||
msg: msg,
|
||||
trace: &trace,
|
||||
}
|
||||
}
|
||||
|
||||
func MakeParsetimeErrorf(n Node, msg string, a ...interface{}) IError {
|
||||
func MakeSyntaxErrorf(n Node, msg string, a ...interface{}) IError {
|
||||
return &Error{
|
||||
Node: n,
|
||||
msg: fmt.Sprintf(msg, a...),
|
||||
Node: n,
|
||||
errtype: SyntaxError,
|
||||
msg: fmt.Sprintf(msg, a...),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,9 +158,10 @@ func MakeSemanticError(rt *Runtime, e IExpr, errno errors.Errno, msg string) IEr
|
|||
}
|
||||
|
||||
return &Error{
|
||||
Node: MakeNodeFromExpr(e),
|
||||
errno: errno,
|
||||
msg: msg,
|
||||
trace: frames,
|
||||
Node: MakeNodeFromExpr(e),
|
||||
errtype: SemanticError,
|
||||
errno: errno,
|
||||
msg: msg,
|
||||
trace: frames,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -218,6 +218,10 @@ tco:
|
|||
// Evaluating forms one by one
|
||||
if forms.GetType() != ast.List {
|
||||
ret, err = evalForm(rt, scope, forms)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
continue body
|
||||
}
|
||||
|
||||
|
@ -271,6 +275,10 @@ tco:
|
|||
// TODO: decide on the syntax and complete the docs
|
||||
case "ns":
|
||||
ret, err = NSForm(rt, scope, list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
continue body // no rewrite
|
||||
|
||||
// `quote` evaluation rules:
|
||||
|
@ -298,6 +306,10 @@ tco:
|
|||
// Creates a new list form it's arguments.
|
||||
case "list":
|
||||
ret, err = evalForm(rt, scope, list.Rest().(*List))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
continue body // no rewrite
|
||||
|
||||
// TODO: Implement `concat` in serene itself when we have protocols available
|
||||
|
@ -320,12 +332,19 @@ tco:
|
|||
result = append(result, lst.(*List).ToSlice()...)
|
||||
}
|
||||
|
||||
node := MakeNodeFromExpr(list)
|
||||
if len(result) > 0 {
|
||||
node = MakeNodeFromExprs(result)
|
||||
n := MakeNodeFromExprs(result)
|
||||
|
||||
if n == nil {
|
||||
n = &list.Node
|
||||
}
|
||||
|
||||
node := *n
|
||||
|
||||
ret, err = MakeList(node, result), nil
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
continue body // no rewrite
|
||||
|
||||
// TODO: Implement `list` in serene itself when we have destructuring available
|
||||
|
@ -349,6 +368,10 @@ tco:
|
|||
}
|
||||
|
||||
ret, err = coll.Cons(evaledForms.(*List).First()), nil
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
continue body // no rewrite
|
||||
|
||||
// `def` evaluation rules
|
||||
|
@ -359,6 +382,10 @@ tco:
|
|||
// the symbol name binded to the value
|
||||
case "def":
|
||||
ret, err = Def(rt, scope, list.Rest().(*List))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
continue body // no rewrite
|
||||
|
||||
// `defmacro` evaluation rules:
|
||||
|
@ -368,6 +395,10 @@ tco:
|
|||
// body of the macro.
|
||||
case "defmacro":
|
||||
ret, err = DefMacro(rt, scope, list.Rest().(*List))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
continue body // no rewrite
|
||||
|
||||
// `macroexpand` evaluation rules:
|
||||
|
@ -385,6 +416,9 @@ tco:
|
|||
}
|
||||
|
||||
ret, err = macroexpand(rt, scope, evaledForm.(*List).First())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue body // no rewrite
|
||||
|
||||
// `fn` evaluation rules:
|
||||
|
@ -392,6 +426,9 @@ tco:
|
|||
// * Defines an anonymous function.
|
||||
case "fn":
|
||||
ret, err = Fn(rt, scope, list)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue body // no rewrite
|
||||
|
||||
// `if` evaluation rules:
|
||||
|
@ -454,6 +491,10 @@ tco:
|
|||
}
|
||||
|
||||
ret, err = EvalForms(rt, scope, form)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
continue body // no rewrite
|
||||
|
||||
// `let` evaluation rules:
|
||||
|
@ -525,9 +566,7 @@ tco:
|
|||
// Evaluating all the elements of the list
|
||||
listExprs, e := evalForm(rt, scope, list)
|
||||
if e != nil {
|
||||
err = e
|
||||
ret = nil
|
||||
break tco //return
|
||||
return nil, e
|
||||
}
|
||||
|
||||
f := listExprs.(*List).First()
|
||||
|
@ -541,19 +580,14 @@ tco:
|
|||
// `expressions` to the body of function and loop again
|
||||
fn := f.(*Function)
|
||||
if e != nil {
|
||||
err = e
|
||||
ret = nil
|
||||
break body //return
|
||||
|
||||
return nil, e
|
||||
}
|
||||
|
||||
argList := listExprs.(*List).Rest().(*List)
|
||||
|
||||
fnScope, e := MakeFnScope(rt, fn.GetScope(), fn.GetParams(), argList)
|
||||
if e != nil {
|
||||
err = e
|
||||
ret = nil
|
||||
break body //return
|
||||
return nil, e
|
||||
}
|
||||
|
||||
rt.Stack.Push(list, fn)
|
||||
|
@ -579,6 +613,11 @@ tco:
|
|||
MakeNodeFromExpr(fn),
|
||||
listExprs.(*List),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rt.Stack.Pop()
|
||||
continue body // no rewrite
|
||||
|
||||
|
|
|
@ -209,7 +209,13 @@ func MakeFnScope(rt *Runtime, parent IScope, bindings IColl, values IColl) (*Sco
|
|||
var node Node
|
||||
|
||||
if len(elements) > 0 {
|
||||
node = MakeNodeFromExprs(elements)
|
||||
n := MakeNodeFromExprs(elements)
|
||||
|
||||
if n == nil {
|
||||
n = &values.(*List).Node
|
||||
}
|
||||
|
||||
node = *n
|
||||
} else {
|
||||
node = MakeNodeFromExpr(binds[i])
|
||||
}
|
||||
|
|
|
@ -181,11 +181,11 @@ func extractParts(s string) (string, string) {
|
|||
|
||||
func MakeKeyword(n Node, name string) (*Keyword, IError) {
|
||||
if strings.Count(name, ":") > 2 {
|
||||
return nil, MakeParsetimeErrorf(n, "can't parse the keyword with more that two colons: '%s'", name)
|
||||
return nil, MakeSyntaxErrorf(n, "can't parse the keyword with more that two colons: '%s'", name)
|
||||
}
|
||||
|
||||
if strings.Count(name, "/") > 1 {
|
||||
return nil, MakeParsetimeErrorf(n, "illegal namespace path for the given keyword: '%s'", name)
|
||||
return nil, MakeSyntaxErrorf(n, "illegal namespace path for the given keyword: '%s'", name)
|
||||
}
|
||||
|
||||
var nsName string
|
||||
|
|
|
@ -76,7 +76,12 @@ func (l *List) Rest() ISeq {
|
|||
rest := l.exprs[1:]
|
||||
node := l.Node
|
||||
if len(rest) > 0 {
|
||||
node = MakeNodeFromExprs(rest)
|
||||
// n won't be nil here but we should check anyway
|
||||
n := MakeNodeFromExprs(rest)
|
||||
if n == nil {
|
||||
panic("'MakeNodeFromExprs' has returned nil for none empty array of exprs")
|
||||
}
|
||||
node = *n
|
||||
}
|
||||
|
||||
return MakeList(node, rest)
|
||||
|
@ -105,7 +110,14 @@ func (l *List) ToSlice() []IExpr {
|
|||
|
||||
func (l *List) Cons(e IExpr) IExpr {
|
||||
elements := append([]IExpr{e}, l.ToSlice()...)
|
||||
return MakeList(MakeNodeFromExprs(elements), elements)
|
||||
node := MakeNodeFromExprs(elements)
|
||||
|
||||
// Since 'elements' is not empty node won't be nil but we should
|
||||
// check anyway
|
||||
if node == nil {
|
||||
node = &l.Node
|
||||
}
|
||||
return MakeList(*node, elements)
|
||||
}
|
||||
|
||||
// END: IColl ---
|
||||
|
|
|
@ -199,6 +199,7 @@ func RequireNamespace(rt *Runtime, namespace IExpr) (IExpr, IError) {
|
|||
|
||||
ns = first.(*Symbol)
|
||||
alias = second.(*Symbol).GetName()
|
||||
|
||||
default:
|
||||
return nil, MakeError(rt, ns, "Don't know how to load the given namespace")
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ func (sp *StringParser) Buffer() *[]string {
|
|||
// points at the current position of the buffer.
|
||||
func makeErrorAtPoint(p IParsable, msg string, a ...interface{}) IError {
|
||||
n := MakeSinglePointNode(p.GetSource(), p.GetLocation())
|
||||
return MakeParsetimeErrorf(n, msg, a...)
|
||||
return MakeSyntaxErrorf(n, msg, a...)
|
||||
}
|
||||
|
||||
// makeErrorFromError is a function which wraps a Golang error in an IError
|
||||
|
@ -407,9 +407,14 @@ func readList(parser IParsable) (IExpr, IError) {
|
|||
}
|
||||
|
||||
node := MakeNodeFromExprs(list)
|
||||
if node == nil {
|
||||
n := MakeSinglePointNode(parser.GetSource(), parser.GetLocation())
|
||||
node = &n
|
||||
}
|
||||
|
||||
node.location.DecStart(1)
|
||||
node.location.IncEnd(1)
|
||||
return MakeList(node, list), nil
|
||||
return MakeList(*node, list), nil
|
||||
}
|
||||
|
||||
func readComment(parser IParsable) (IExpr, IError) {
|
||||
|
@ -443,9 +448,14 @@ func readQuotedExpr(parser IParsable) (IExpr, IError) {
|
|||
}
|
||||
|
||||
listNode := MakeNodeFromExprs(listElems)
|
||||
if listNode == nil {
|
||||
n := MakeSinglePointNode(parser.GetSource(), parser.GetLocation())
|
||||
listNode = &n
|
||||
}
|
||||
|
||||
listNode.location.DecStart(1)
|
||||
listNode.location.IncStart(1)
|
||||
return MakeList(listNode, listElems), nil
|
||||
return MakeList(*listNode, listElems), nil
|
||||
}
|
||||
|
||||
// readUnquotedExpr reads different unquoting expressions from their short representaions.
|
||||
|
@ -489,10 +499,19 @@ func readUnquotedExpr(parser IParsable) (IExpr, IError) {
|
|||
}
|
||||
|
||||
listElems := []IExpr{sym, expr}
|
||||
|
||||
listNode := MakeNodeFromExprs(listElems)
|
||||
|
||||
// listNode won't be nil in this case but it doesn't
|
||||
// mean we shouldn't check
|
||||
if listNode == nil {
|
||||
n := MakeSinglePointNode(parser.GetSource(), parser.GetLocation())
|
||||
listNode = &n
|
||||
}
|
||||
|
||||
listNode.location.DecStart(1)
|
||||
listNode.location.IncStart(1)
|
||||
return MakeList(listNode, listElems), nil
|
||||
return MakeList(*listNode, listElems), nil
|
||||
}
|
||||
|
||||
// readQuasiquotedExpr reads the backquote and replace it with a call
|
||||
|
@ -512,10 +531,17 @@ func readQuasiquotedExpr(parser IParsable) (IExpr, IError) {
|
|||
|
||||
listElems := []IExpr{sym, expr}
|
||||
listNode := MakeNodeFromExprs(listElems)
|
||||
// listNode won't be nil in this case but it doesn't
|
||||
// mean we shouldn't check
|
||||
if listNode == nil {
|
||||
n := MakeSinglePointNode(parser.GetSource(), parser.GetLocation())
|
||||
listNode = &n
|
||||
}
|
||||
|
||||
listNode.location.DecStart(1)
|
||||
listNode.location.IncStart(1)
|
||||
|
||||
return MakeList(listNode, listElems), nil
|
||||
return MakeList(*listNode, listElems), nil
|
||||
}
|
||||
|
||||
// readExpr reads one expression from the input. This function is the most
|
||||
|
|
|
@ -65,9 +65,11 @@ func Println(rt *Runtime, ast ...IRepresentable) {
|
|||
}
|
||||
|
||||
func PrintError(rt *Runtime, err IError) {
|
||||
trace := err.GetStackTrace()
|
||||
|
||||
trace := err.GetStackTrace()
|
||||
fmt.Println(err)
|
||||
for i, t := range *trace {
|
||||
fmt.Println(*t)
|
||||
caller := t.Caller
|
||||
callerLoc := caller.GetLocation()
|
||||
callerSource := callerLoc.GetSource()
|
||||
|
@ -82,7 +84,11 @@ func PrintError(rt *Runtime, err IError) {
|
|||
|
||||
var lines string
|
||||
for i := startline; i <= endline; i++ {
|
||||
lines += fmt.Sprintf("%d:\t%s\n", i, t.Fn.GetLocation().GetSource().GetLine(i))
|
||||
fmt.Println(">>>>>>>>>> ", err)
|
||||
fLoc := t.Fn.GetLocation()
|
||||
fmt.Println(">>>>>>>>>> ", fLoc, fLoc.GetSource())
|
||||
|
||||
lines += fmt.Sprintf("%d:\t%s\n", i, fLoc.GetSource().GetLine(i))
|
||||
}
|
||||
|
||||
color.Yellow.Printf(
|
||||
|
|
|
@ -103,8 +103,12 @@ func qqProcess(rt *Runtime, e IExpr) (IExpr, IError) {
|
|||
e,
|
||||
}
|
||||
|
||||
n := MakeNodeFromExprs(elems)
|
||||
if n == nil {
|
||||
n = &sym.Node
|
||||
}
|
||||
return MakeList(
|
||||
MakeNodeFromExprs(elems),
|
||||
*n,
|
||||
elems,
|
||||
), nil
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"serene-lang.org/bootstrap/pkg/ast"
|
||||
|
@ -86,7 +85,7 @@ func MakeSymbol(n Node, s string) (*Symbol, IError) {
|
|||
name = parts[1]
|
||||
nsPart = parts[0]
|
||||
default:
|
||||
return nil, MakePlainError(fmt.Sprintf("can't create a symbol from '%s'. More that on '/' is illegal.", s))
|
||||
return nil, MakeSyntaxErrorf(n, "can't create a symbol from '%s'. More that on '/' is illegal.", s)
|
||||
}
|
||||
|
||||
return &Symbol{
|
||||
|
|
|
@ -122,6 +122,12 @@ func toRepresentables(ast IColl) []IRepresentable {
|
|||
return params
|
||||
}
|
||||
|
||||
// TODO: I don't like the current interface and signatures of these
|
||||
// 'Make*Node*' functions. Refactor them to have the same interface
|
||||
// For instance if we need to return a pointer to a Node all of them
|
||||
// has to return a pointer not just one of them. The return type
|
||||
// should be predictable
|
||||
|
||||
// MakeNodeFromLocation creates a new Node for the given Location `loc`
|
||||
func MakeNodeFromLocation(loc *ast.Location) Node {
|
||||
return Node{
|
||||
|
@ -139,17 +145,16 @@ func MakeNodeFromExpr(e IExpr) Node {
|
|||
// 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 {
|
||||
func MakeNodeFromExprs(es []IExpr) *Node {
|
||||
if len(es) == 0 {
|
||||
// TODO: This is temporary, fix it.
|
||||
panic("can't create a node from empty elements.")
|
||||
return nil
|
||||
}
|
||||
|
||||
firstLoc := es[0].GetLocation()
|
||||
endLoc := es[len(es)-1].GetLocation()
|
||||
loc := ast.MakeLocation(firstLoc.GetSource(), firstLoc.GetStart(), endLoc.GetEnd())
|
||||
|
||||
return MakeNodeFromLocation(loc)
|
||||
n := MakeNodeFromLocation(loc)
|
||||
return &n
|
||||
}
|
||||
|
||||
// MakeNode creates a new Node in the the given `input` that points to a
|
||||
|
|
Loading…
Reference in New Issue