Skip to content

Commit

Permalink
AST VariableDeclaration Tuple and Return Statement Fix + Resolver Imp…
Browse files Browse the repository at this point in the history
…rovements (#108)

* More reference resolution, return statement fix
* Type description void if return does not have expression
* Wth...
* VariableDeclaration tuple were missing...
* Fixing builder_test
  • Loading branch information
0x19 committed Sep 23, 2023
1 parent 393162e commit 6f76db2
Show file tree
Hide file tree
Showing 65 changed files with 262,244 additions and 46,903 deletions.
20 changes: 16 additions & 4 deletions ast/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"
"path/filepath"
"reflect"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -27,6 +28,7 @@ func TestAstBuilderFromSourceAsString(t *testing.T) {

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {

parser, err := solgo.NewParserFromSources(context.TODO(), testCase.sources)
assert.NoError(t, err)
assert.NotNil(t, parser)
Expand Down Expand Up @@ -55,6 +57,7 @@ func TestAstBuilderFromSourceAsString(t *testing.T) {
assert.Equal(t, errsExpected, errs)
assert.Equal(t, int(testCase.unresolvedReferences), astBuilder.GetResolver().GetUnprocessedCount())
assert.Equal(t, len(astBuilder.GetResolver().GetUnprocessedNodes()), astBuilder.GetResolver().GetUnprocessedCount())

for _, sourceUnit := range astBuilder.GetRoot().GetSourceUnits() {
prettyJson, err := utils.ToJSONPretty(sourceUnit)
assert.NoError(t, err)
Expand Down Expand Up @@ -126,11 +129,18 @@ func TestAstBuilderFromSourceAsString(t *testing.T) {
}

func recursiveTest(t *testing.T, node Node[NodeType]) {
if node == nil {
return
}

assert.NotNil(t, node.GetNodes(), fmt.Sprintf("Node %T has nil nodes", node))
assert.GreaterOrEqual(t, node.GetId(), int64(0), fmt.Sprintf("Node %T has empty id", node))
assert.NotNil(t, node.GetType(), fmt.Sprintf("Node %T has empty type", node))
assert.NotNil(t, node.GetSrc(), fmt.Sprintf("Node %T has empty GetSrc()", node))
assert.NotNil(t, node.GetTypeDescription(), fmt.Sprintf("Node %T has not defined GetTypeDescription()", node))

if reflect.TypeOf(node).String() != "*ast.ReturnStatement" {
assert.NotNil(t, node.GetTypeDescription(), fmt.Sprintf("Node %T has not defined GetTypeDescription()", node))
}

if contract, ok := node.(*Contract); ok {
assert.GreaterOrEqual(t, len(contract.GetBaseContracts()), 0)
Expand Down Expand Up @@ -351,8 +361,10 @@ func recursiveReferenceDescriptorSetTest(t *testing.T, node Node[NodeType]) {
node.SetReferenceDescriptor(0, &TypeDescription{})

for _, childNode := range node.GetNodes() {
childNode.SetReferenceDescriptor(0, nil)
childNode.SetReferenceDescriptor(0, &TypeDescription{})
recursiveReferenceDescriptorSetTest(t, childNode)
if childNode != nil {
childNode.SetReferenceDescriptor(0, nil)
childNode.SetReferenceDescriptor(0, &TypeDescription{})
recursiveReferenceDescriptorSetTest(t, childNode)
}
}
}
12 changes: 11 additions & 1 deletion ast/index_access.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,9 @@ func (i *IndexAccess) ToProto() NodeType {
}

for _, td := range i.GetTypeDescriptions() {
proto.TypeDescriptions = append(proto.TypeDescriptions, td.ToProto())
if td != nil {
proto.TypeDescriptions = append(proto.TypeDescriptions, td.ToProto())
}
}

return NewTypedStruct(&proto, "IndexAccess")
Expand Down Expand Up @@ -193,6 +195,14 @@ func (i *IndexAccess) buildTypeDescription() *TypeDescription {
typeIdentifiers := make([]string, 0)

for _, paramType := range i.GetTypeDescriptions() {
// REMOVE-LATER: It's a fix because sometimes forward-path is not quite working at this stage...
// For example, defining state variables at end of the contract instead of the top :explosion:
if paramType == nil {
typeStrings = append(typeStrings, "unknown")
typeIdentifiers = append(typeIdentifiers, "$_t_unknown")
continue
}

if strings.Contains(paramType.TypeString, "literal_string") {
typeStrings = append(typeStrings, "string memory")
typeIdentifiers = append(typeIdentifiers, "_"+paramType.TypeIdentifier)
Expand Down
7 changes: 7 additions & 0 deletions ast/primary_expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,13 @@ func (p *PrimaryExpression) Parse(
}
}

if p.TypeDescription == nil {
if refId, refTypeDescription := p.GetResolver().ResolveByNode(p, p.Name); refTypeDescription != nil {
p.ReferencedDeclaration = refId
p.TypeDescription = refTypeDescription
}
}

return p
}

Expand Down
16 changes: 16 additions & 0 deletions ast/reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,14 @@ func (r *Resolver) Resolve() []error {
),
)
}
} else {
errors = append(
errors,
fmt.Errorf(
"unable to find node by id %d - name: %s - type: %v",
nodeId, node.Name, reflect.TypeOf(node.Node),
),
)
}
}

Expand Down Expand Up @@ -483,6 +491,14 @@ func (r *Resolver) byRecursiveSearch(node Node[NodeType], name string) (Node[Nod
if nodeCtx.GetName() == name {
return nodeCtx, nodeCtx.GetTypeDescription()
}
case *Assignment:
if nodeCtx.GetRightExpression() != nil {
if expr, ok := nodeCtx.GetRightExpression().(*PrimaryExpression); ok {
if expr.GetName() == name {
return expr, expr.GetTypeDescription()
}
}
}
}

for _, n := range node.GetNodes() {
Expand Down
27 changes: 20 additions & 7 deletions ast/return.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,14 @@ func (r *ReturnStatement) GetFunctionReturnParameters() int64 {

// GetTypeDescription returns the type description of the ReturnStatement's expression.
func (r *ReturnStatement) GetTypeDescription() *TypeDescription {
if r.Expression != nil {
return r.Expression.GetTypeDescription()
if r.Expression == nil {
return &TypeDescription{
TypeString: "void",
TypeIdentifier: "$_t_return_void",
}
}
return nil

return r.Expression.GetTypeDescription()
}

// GetNodes returns a list of child nodes contained in the ReturnStatement.
Expand All @@ -76,8 +80,14 @@ func (r *ReturnStatement) ToProto() NodeType {
NodeType: r.GetType(),
Src: r.Src.ToProto(),
FunctionReturnParameters: r.GetFunctionReturnParameters(),
Expression: r.GetExpression().ToProto().(*v3.TypedStruct),
TypeDescription: r.GetTypeDescription().ToProto(),
}

if r.GetExpression() != nil {
proto.Expression = r.GetExpression().ToProto().(*v3.TypedStruct)
}

if r.GetTypeDescription() != nil {
proto.TypeDescription = r.GetTypeDescription().ToProto()
}

return NewTypedStruct(&proto, "Return")
Expand Down Expand Up @@ -106,7 +116,10 @@ func (r *ReturnStatement) Parse(
r.FunctionReturnParameters = fnCtx.GetId()
}

expression := NewExpression(r.ASTBuilder)
r.Expression = expression.Parse(unit, contractNode, fnNode, bodyNode, nil, nil, ctx.Expression())
if ctx.Expression() != nil {
expression := NewExpression(r.ASTBuilder)
r.Expression = expression.Parse(unit, contractNode, fnNode, bodyNode, nil, nil, ctx.Expression())
}

return r
}
18 changes: 18 additions & 0 deletions ast/sources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,24 @@ func getSourceTestCases(t *testing.T) []struct {
expectedProto: tests.ReadJsonBytesForTest(t, "ast/Empty.solgo.ast.proto").Content,
unresolvedReferences: 0,
},
{
name: "PAPA Contract",
outputPath: "contracts/papa/",
sources: &solgo.Sources{
SourceUnits: []*solgo.SourceUnit{
{
Name: "ERC20",
Path: tests.ReadContractFileForTest(t, "contracts/papa/Token").Path,
Content: tests.ReadContractFileForTest(t, "contracts/papa/Token").Content,
},
},
EntrySourceUnitName: "Token",
LocalSourcesPath: buildFullPath("../sources/"),
},
expectedAst: tests.ReadJsonBytesForTest(t, "contracts/papa/Token.solgo.ast").Content,
expectedProto: tests.ReadJsonBytesForTest(t, "contracts/papa/Token.solgo.ast.proto").Content,
unresolvedReferences: 0,
},
{
name: "Simple Storage Contract Test",
outputPath: "ast/",
Expand Down
9 changes: 9 additions & 0 deletions ast/variable.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,15 @@ func (v *VariableDeclaration) Parse(
v.Assignments = append(v.Assignments, declaration.GetId())
}

if ctx.VariableDeclarationTuple() != nil {
for _, declarationCtx := range ctx.VariableDeclarationTuple().AllVariableDeclaration() {
declaration := NewDeclaration(v.ASTBuilder)
declaration.ParseVariableDeclaration(unit, contractNode, fnNode, bodyNode, v, declarationCtx)
v.Declarations = append(v.Declarations, declaration)
v.Assignments = append(v.Assignments, declaration.GetId())
}
}

if ctx.Expression() != nil {
expression := NewExpression(v.ASTBuilder)
v.InitialValue = expression.Parse(unit, contractNode, fnNode, bodyNode, v, nil, ctx.Expression())
Expand Down
2 changes: 1 addition & 1 deletion data/solc/releases/releases.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion data/tests/abi/TransparentUpgradeableProxy.abi.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"entry_contract_id": 2309,
"entry_contract_id": 2337,
"entry_contract_name": "TransparentUpgradeableProxy",
"contracts_count": 13,
"contracts": {
Expand Down
2 changes: 1 addition & 1 deletion data/tests/abi/TransparentUpgradeableProxy.abi.proto.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"entryContractId": 2309,
"entryContractId": 2337,
"entryContractName": "TransparentUpgradeableProxy",
"contractsCount": 13,
"contracts": {
Expand Down
Loading

0 comments on commit 6f76db2

Please sign in to comment.