Skip to content

Commit

Permalink
Moved "def" parsing to function
Browse files Browse the repository at this point in the history
+ Added SignatureParser & SignatureNode tests
  • Loading branch information
RealA10N committed Aug 3, 2024
1 parent ea59e83 commit 40fb314
Show file tree
Hide file tree
Showing 3 changed files with 177 additions and 20 deletions.
21 changes: 19 additions & 2 deletions parse/function.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,45 @@
package parse

import (
"usm/lex"
"usm/source"
)

type FunctionNode struct {
source.UnmanagedSourceView
Signature SignatureNode
Block BlockNode
}

func (n FunctionNode) View() source.UnmanagedSourceView {
return n.Signature.View().Merge(n.Block.View())
return n.UnmanagedSourceView
}

func (n FunctionNode) String(ctx source.SourceContext) string {
return n.Signature.String(ctx) + " " + n.Block.String(ctx)
return "def " + n.Signature.String(ctx) + " " + n.Block.String(ctx)
}

type FunctionParser struct {
SignatureParser SignatureParser
BlockParser BlockParser
}

func (FunctionParser) parseDef(v *TokenView, node *FunctionNode) ParsingError {
def, err := v.ConsumeToken(lex.DefToken)
if err != nil {
return err
}

node.Start = def.View.Start
return nil
}

func (p FunctionParser) Parse(v *TokenView) (node FunctionNode, err ParsingError) {
err = p.parseDef(v, &node)
if err != nil {
return
}

node.Signature, err = p.SignatureParser.Parse(v)
if err != nil {
return
Expand Down
29 changes: 11 additions & 18 deletions parse/signature.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ func (n SignatureNode) View() source.UnmanagedSourceView {
return n.UnmanagedSourceView
}

func (n SignatureNode) String(ctx source.SourceContext) string {
s := "def "
func (n SignatureNode) String(ctx source.SourceContext) (s string) {
for _, ret := range n.Returns {
s += ret.String(ctx) + " "
}
Expand All @@ -28,24 +27,14 @@ func (n SignatureNode) String(ctx source.SourceContext) string {
s += " " + arg.String(ctx)
}

return s
return
}

type SignatureParser struct {
ParameterParser ParameterParser
TypeParser TypeParser
}

func (SignatureParser) parseDef(v *TokenView, node *SignatureNode) ParsingError {
def, err := v.ConsumeToken(lex.DefToken)
if err != nil {
return err
}

node.Start = def.View.Start
return nil
}

func (SignatureParser) parseIdentifier(v *TokenView, node *SignatureNode) ParsingError {
id, err := v.ConsumeToken(lex.GlbToken)
if err != nil {
Expand All @@ -56,6 +45,14 @@ func (SignatureParser) parseIdentifier(v *TokenView, node *SignatureNode) Parsin
return nil
}

func (SignatureParser) updateNodeViewStart(node *SignatureNode) {
if len(node.Returns) > 0 {
node.Start = node.Returns[0].View().Start
} else {
node.Start = node.Identifier.Start
}
}

func (SignatureParser) updateNodeViewEnd(node *SignatureNode) {
if len(node.Parameters) > 0 {
node.End = node.Parameters[len(node.Parameters)-1].View().End
Expand All @@ -65,11 +62,6 @@ func (SignatureParser) updateNodeViewEnd(node *SignatureNode) {
}

func (p SignatureParser) Parse(v *TokenView) (node SignatureNode, err ParsingError) {
err = p.parseDef(v, &node)
if err != nil {
return
}

node.Returns = ParseMany(p.TypeParser, v)

err = p.parseIdentifier(v, &node)
Expand All @@ -78,6 +70,7 @@ func (p SignatureParser) Parse(v *TokenView) (node SignatureNode, err ParsingErr
}

node.Parameters = ParseMany(p.ParameterParser, v)
p.updateNodeViewStart(&node)
p.updateNodeViewEnd(&node)
return
}
147 changes: 147 additions & 0 deletions parse/signature_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
package parse_test

import (
"testing"
"usm/lex"
"usm/parse"
"usm/source"

"github.com/stretchr/testify/assert"
)

func TestSignatureParserOnlyIdentifier(t *testing.T) {
v, ctx := source.NewSourceView("@fibonacci").Detach()
glb := lex.Token{Type: lex.GlbToken, View: v}
tknView := parse.NewTokenView([]lex.Token{glb})

expectedSig := parse.SignatureNode{
UnmanagedSourceView: v.Subview(0, 10),
Identifier: v,
}

sig, err := parse.SignatureParser{}.Parse(&tknView)
assert.Nil(t, err)
assert.Equal(t, expectedSig, sig)

assert.Equal(t, v, sig.View())
assert.Equal(t, "@fibonacci", sig.String(ctx))
}

func TestSignatureParserVoidFunction(t *testing.T) {
v, ctx := source.NewSourceView("... @printNumber $i32 %x ...").Detach()
glb := lex.Token{Type: lex.GlbToken, View: v.Subview(4, 16)}
typ := lex.Token{Type: lex.TypToken, View: v.Subview(18, 22)}
reg := lex.Token{Type: lex.RegToken, View: v.Subview(23, 25)}
tknView := parse.NewTokenView([]lex.Token{glb, typ, reg})

expectedSig := parse.SignatureNode{
UnmanagedSourceView: v.Subview(4, 25),
Identifier: glb.View,
Parameters: []parse.ParameterNode{
parse.ParameterNode{
Type: parse.TypeNode{typ.View},
Register: parse.RegisterNode{reg.View},
},
},
}

sig, err := parse.SignatureParser{}.Parse(&tknView)
assert.Nil(t, err)
assert.Equal(t, expectedSig, sig)
assert.Equal(t, v.Subview(4, 25), sig.View())
assert.Equal(t, "@printNumber $i32 %x", sig.String(ctx))
}

func TestSignatureParserSingleReturn(t *testing.T) {
v, ctx := source.NewSourceView("$i32 @add $i32 %x $i32 %y").Detach()
ret := lex.Token{Type: lex.TypToken, View: v.Subview(0, 4)}
id := lex.Token{Type: lex.GlbToken, View: v.Subview(5, 9)}
param1Typ := lex.Token{Type: lex.TypToken, View: v.Subview(10, 14)}
param1Reg := lex.Token{Type: lex.RegToken, View: v.Subview(15, 17)}
param2Typ := lex.Token{Type: lex.TypToken, View: v.Subview(18, 22)}
param2Reg := lex.Token{Type: lex.RegToken, View: v.Subview(23, 25)}
tknView := parse.NewTokenView([]lex.Token{
ret, id, param1Typ, param1Reg, param2Typ, param2Reg,
})

expectedSig := parse.SignatureNode{
UnmanagedSourceView: v,
Identifier: id.View,
Parameters: []parse.ParameterNode{
parse.ParameterNode{
Type: parse.TypeNode{param1Typ.View},
Register: parse.RegisterNode{param1Reg.View},
},
parse.ParameterNode{
Type: parse.TypeNode{param2Typ.View},
Register: parse.RegisterNode{param2Reg.View},
},
},
Returns: []parse.TypeNode{
parse.TypeNode{ret.View},
},
}

sig, err := parse.SignatureParser{}.Parse(&tknView)
assert.Nil(t, err)
assert.Equal(t, expectedSig, sig)
assert.Equal(t, v, sig.View())
assert.Equal(t, "$i32 @add $i32 %x $i32 %y", sig.String(ctx))
}

func TestSignatureParserMutltiReturn(t *testing.T) {
v, ctx := source.NewSourceView("$i32 $i32 @divmod $i32 %n $i32 %m").Detach()
ret1 := lex.Token{Type: lex.TypToken, View: v.Subview(0, 4)}
ret2 := lex.Token{Type: lex.TypToken, View: v.Subview(6, 10)}
id := lex.Token{Type: lex.GlbToken, View: v.Subview(12, 19)}
param1Typ := lex.Token{Type: lex.TypToken, View: v.Subview(21, 25)}
param1Reg := lex.Token{Type: lex.RegToken, View: v.Subview(26, 28)}
param2Typ := lex.Token{Type: lex.TypToken, View: v.Subview(30, 34)}
param2Reg := lex.Token{Type: lex.RegToken, View: v.Subview(35, 37)}
tknView := parse.NewTokenView([]lex.Token{
ret1, ret2, id, param1Typ, param1Reg, param2Typ, param2Reg,
})

expectedSig := parse.SignatureNode{
UnmanagedSourceView: v,
Identifier: id.View,
Parameters: []parse.ParameterNode{
parse.ParameterNode{
Type: parse.TypeNode{param1Typ.View},
Register: parse.RegisterNode{param1Reg.View},
},
parse.ParameterNode{
Type: parse.TypeNode{param2Typ.View},
Register: parse.RegisterNode{param2Reg.View},
},
},
Returns: []parse.TypeNode{
parse.TypeNode{ret1.View},
parse.TypeNode{ret2.View},
},
}

sig, err := parse.SignatureParser{}.Parse(&tknView)
assert.Nil(t, err)
assert.Equal(t, expectedSig, sig)
assert.Equal(t, v, sig.View())
assert.Equal(t, "$i32 $i32 @divmod $i32 %n $i32 %m", sig.String(ctx))
}

func TestSignatureParserIdentifierNotGlobal(t *testing.T) {
v, _ := source.NewSourceView("funcid").Detach()
opr := lex.Token{Type: lex.OprToken, View: v}
tknView := parse.NewTokenView([]lex.Token{opr})

expectedErr := parse.UnexpectedTokenError{
Expected: []lex.TokenType{lex.GlbToken},
Actual: opr,
}

_, err := parse.SignatureParser{}.Parse(&tknView)
assert.NotNil(t, err)

details, ok := err.(parse.UnexpectedTokenError)
assert.True(t, ok)
assert.Equal(t, expectedErr, details)
}

0 comments on commit 40fb314

Please sign in to comment.