Browse Source

added framework for "inlineing" and scoping.

Can now also resolve references
master
Pixdigit 2 years ago
parent
commit
14711a1cc1
  1. 31
      internal/AST/ReferenceNode.go
  2. 2
      internal/AST/ScopeNode.go
  3. 115
      internal/AST/TransformNode.go
  4. 4
      internal/printTree.go
  5. 8
      internal/test.go
  6. 18
      internal/treeVisitor.go
  7. 5
      test.sct

31
internal/AST/ReferenceNode.go

@ -1,9 +1,12 @@
package AST
import "fmt"
import (
"fmt"
"strings"
)
type ReferenceNode struct {
ReferenceName string
ReferencePath string
resolved bool
destination Unique
}
@ -32,9 +35,29 @@ func NewLiteralReferenceNode(reference Unique) *ReferenceNode {
return NewResolvedReferenceNode("#literal", reference)
}
func (rn *ReferenceNode) Path() []string {
return strings.Split(rn.ReferencePath, ".")
}
func (rn *ReferenceNode) Root() string {
//As the name can not be nil the path is never empty
return rn.Path()[0]
}
func (rn *ReferenceNode) BaseName() string {
return rn.Path()[len(rn.Path())-1]
}
func (rn *ReferenceNode) ChildReference() (*ReferenceNode, error) {
if len(rn.Path()) < 2 {
return nil, fmt.Errorf("Reference %v has no child", rn.ReferencePath)
}
return NewReferenceNode(strings.Join(rn.Path()[1:len(rn.Path())], ".")), nil
}
func (rn *ReferenceNode) Resolve(reference Unique) error {
if rn.resolved {
return fmt.Errorf("reference to %v is already resolved", rn.ReferenceName)
return fmt.Errorf("Reference to %v is already resolved", rn.ReferencePath)
}
rn.resolved = true
@ -49,7 +72,7 @@ func (rn *ReferenceNode) IsResolved() bool {
func (rn *ReferenceNode) ResolvesTo() (Unique, error) {
if !rn.resolved {
return nil, fmt.Errorf("Reference is not resolved")
return nil, fmt.Errorf("Reference %v is not resolved", rn.ReferencePath)
} else {
return rn.destination, nil
}

2
internal/AST/ScopeNode.go

@ -86,8 +86,6 @@ func (sn *ScopeNode) Errors() []*ErrorNode {
return errs
}
func (sn *ScopeNode) Fold() error {
// for _, variable := range sn.variables {
// fmt.Println("Found Variable")

115
internal/AST/TransformNode.go

@ -2,18 +2,24 @@ package AST
import "fmt"
const anonName = "#anonymous"
type TransformNode struct {
*ScopeNode
Parameters []string
parent *ReferenceNode
inlined bool
anonymous bool
}
func NewTransformNode(name string, parameters []string, transformBlock *ScopeNode) *TransformNode {
transformBlock.SetName(name)
func NewTransformNode(name string, parameters []string, scope *ScopeNode) *TransformNode {
scope.SetName(name)
tn := &TransformNode{
transformBlock,
scope,
parameters,
NewReferenceNode("#parent"),
false,
false,
}
for _, childTrans := range tn.transforms {
@ -23,9 +29,20 @@ func NewTransformNode(name string, parameters []string, transformBlock *ScopeNod
return tn
}
func NewIdentNode(name string, scope *ScopeNode) *TransformNode {
scope.SetName(name)
return NewTransformNode(name, []string{}, scope)
func NewInlineTransformNode(name string, parameters []string, scope *ScopeNode) *TransformNode {
transform := NewTransformNode(name, parameters, scope)
transform.inlined = true
return transform
}
func NewImmediateTransformNode(parameters []string, scope *ScopeNode) *TransformNode {
transform := NewInlineTransformNode(anonName, []string{}, scope)
transform.anonymous = true
return transform
}
func NewIdentityNode(scope *ScopeNode) *TransformNode {
return NewImmediateTransformNode([]string{}, scope)
}
func (tn *TransformNode) AddChild(node Unique) error {
@ -35,35 +52,88 @@ func (tn *TransformNode) AddChild(node Unique) error {
return tn.ScopeNode.AddChild(node)
}
func (tn *TransformNode) FindTransByName(name string) (*TransformNode, error) {
for _, trans := range tn.transforms {
if trans.Name() == name {
return trans, nil
func (tn *TransformNode) Inlined() bool {
return tn.inlined
}
func (tn *TransformNode) Inline() {
tn.inlined = true
}
func (tn *TransformNode) resolveRef(ref *ReferenceNode) (*TransformNode, bool) {
if len(ref.Path()) == 1 {
if tn.Name() == ref.BaseName() {
return tn, true
}
for _, childTrans := range tn.transforms {
if childTrans.Name() == ref.BaseName() {
return childTrans, true
}
}
if tn.HasParent() {
//tn only has parent if the reference is resolved.
//As parent reference is only set by SetParents this is always a TransformNode
return tn.parent.destination.(*TransformNode).resolveRef(ref)
}
} else {
root, found := tn.findRoot(ref)
if !found {
return nil, found
}
for _, childTrans := range root.transforms {
childRef, err := ref.ChildReference()
if err != nil {
panic(fmt.Sprintf("Reached unreachable statement. Maybe this helps: %v", err))
}
trans, found := childTrans.resolveRef(childRef)
if found {
return trans, found
}
}
}
return nil, false
}
func (tn *TransformNode) findRoot(ref *ReferenceNode) (trans *TransformNode, found bool) {
trans = nil
found = false
parent, err := tn.Parent(); if err != nil {return nil, fmt.Errorf("Could not find transform with name %v", name)}
for _, childTrans := range tn.transforms {
if childTrans.Name() == ref.Root() {
trans = childTrans
found = true
return
}
}
tr, err := parent.FindTransByName(name)
return tr, err
if tn.HasParent() {
//tn only has parent if the reference is resolved.
//As parent reference is only set by SetParents this is always a TransformNode
trans, found = tn.parent.destination.(*TransformNode).findRoot(ref)
}
return
}
func (tn *TransformNode) ResolveRefs() error {
if !tn.ParentsSet() {
return fmt.Errorf("%v can only resolve references when all children know their parents", tn.Name())
}
for _, variable := range tn.variables {
transRef := variable.Transform
if !transRef.IsResolved() {
trans, err := tn.FindTransByName(transRef.ReferenceName); if err != nil {return fmt.Errorf("Ref %v for %v can not be resolved", transRef.ReferenceName, variable.Name())}
variable.Transform.Resolve(trans)
}
}
for _, childTrans := range tn.transforms {
childTrans.ResolveRefs()
}
for _, variable := range tn.variables {
transRef := variable.Transform
if !transRef.IsResolved() {
dest, found := tn.resolveRef(transRef)
if found {
transRef.Resolve(dest)
}
}
}
return nil
}
@ -101,3 +171,8 @@ func (tn *TransformNode) ParentsSet() bool {
}
return true
}
func (tn *TransformNode) SetName(name string) {
tn.ScopeNode.SetName(name)
tn.anonymous = false
}

4
internal/printTree.go

@ -39,7 +39,7 @@ func printIndented(amount int, node AST.Unique) {
argStrings := make([]string, len(n.Args))
i := 0
for param, arg := range n.Args {
refName := arg.ReferenceName
refName := arg.ReferencePath
if dest, err := arg.ResolvesTo(); err == nil {
if err, ok := dest.(*AST.ErrorNode); ok {
refName = err.Error()
@ -49,7 +49,7 @@ func printIndented(amount int, node AST.Unique) {
i++
}
argsString := strings.Join(argStrings, ", ")
fmt.Printf("%v <- %v {%+v}\n", n.Name(), n.Transform.ReferenceName, argsString)
fmt.Printf("%v <- %v {%+v}\n", n.Name(), n.Transform.ReferencePath, argsString)
case *AST.ErrorNode:
fmt.Println("Error: ", n.Info)
}

8
internal/test.go

@ -47,7 +47,7 @@ func Test() {
printTree(astTree)
fmt.Println()
astTree.SetParents(nil)
// astTree.SetParents(nil)
err = astTree.ResolveRefs()
if err != nil {
panic(err)
@ -76,7 +76,11 @@ func Test() {
func show(tr *AST.TransformNode) {
for _, v := range tr.Variables() {
dest, err := v.Transform.ResolvesTo()
fmt.Printf("%v has destID %v and err %v\n", v.Name(), dest.ID(), err)
if err != nil {
fmt.Printf("%v could not be resolved %v\n", v.Name(), err)
} else {
fmt.Printf("%v has destID %v\n", v.Name(), dest.ID())
}
}
for _, t := range tr.Transforms() {
show(t)

18
internal/treeVisitor.go

@ -38,7 +38,7 @@ func (s *ScriptoidTreeVisitor) VisitScript(ctx *parser.ScriptContext) *AST.Trans
scope := s.VisitScope(ctx.Scope().(*parser.ScopeContext))
//TODO: replace Script name by module or file name
trans := AST.NewIdentNode("#script", scope)
trans := AST.NewTransformNode("#script", []string{}, scope)
trans.SetParents(nil)
return trans
@ -129,13 +129,14 @@ func (s *ScriptoidTreeVisitor) VisitLiteral(ctx *parser.LiteralContext) AST.Uniq
} else if str != nil {
node = AST.NewErrorNode("Strings are not implemented yet")
} else if fun != nil {
node = s.VisitFunction_literal(fun.(*parser.Function_literalContext))
fun := s.VisitFunction_literal(fun.(*parser.Function_literalContext))
fun.Inline()
node = fun
} else if call != nil {
node = s.VisitCall(call.(*parser.CallContext))
node.SetName("#literal")
} else if block != nil {
scope := s.VisitBlock(block.(*parser.BlockContext))
node = AST.NewTransformNode("blockLiteral", []string{}, scope)
node = AST.NewIdentityNode(scope)
} else {
node = AST.NewErrorNode(fmt.Sprintf("Literal is not of a known type. Token: %v", ctx.GetText()))
}
@ -188,7 +189,7 @@ func (s *ScriptoidTreeVisitor) VisitFunction_literal(ctx *parser.Function_litera
parameters = []string{}
}
scope := s.VisitBlock(ctx.Block().(*parser.BlockContext))
return AST.NewTransformNode("#literal", parameters, scope)
return AST.NewImmediateTransformNode(parameters, scope)
}
func (s *ScriptoidTreeVisitor) VisitCall(ctx *parser.CallContext) *AST.CallNode {
@ -209,8 +210,9 @@ func (s *ScriptoidTreeVisitor) VisitCall(ctx *parser.CallContext) *AST.CallNode
if refCtx != nil {
ref = AST.NewReferenceNode(refCtx.GetText())
} else if fun != nil {
trans := s.VisitFunction(fun.(*parser.FunctionContext))
ref = AST.NewLiteralReferenceNode(trans)
transform := s.VisitFunction(fun.(*parser.FunctionContext))
transform.Inline()
ref = AST.NewLiteralReferenceNode(transform)
} else if funLit != nil {
trans := s.VisitFunction_literal(funLit.(*parser.Function_literalContext))
ref = AST.NewLiteralReferenceNode(trans)
@ -261,7 +263,7 @@ func (s *ScriptoidTreeVisitor) VisitArgs(ctx *parser.ArgsContext) AST.Arguments
argName = idents[len(idents)-1].GetText()
reference = AST.NewReferenceNode(refCtx.GetText())
} else {
argName = "unkown"
argName = "#unkown"
err := AST.NewErrorNode(fmt.Sprintf("Argument to call could not be parsed: %v", argMapCtx.GetText()))
reference = AST.NewErrorReferenceNode(err)
}

5
test.sct

@ -9,10 +9,15 @@ var New_test_variable = 7; var b = 2.35
func add: a, b {
var d = 5;
func inner: {
}
}
var res = add(a: 2, b: b, test)
var placeholder = add.inner()
func foo: {
}

Loading…
Cancel
Save