Skip to content

Commit

Permalink
Abstract Syntax Tree Bugfixes and Improvements (#77)
Browse files Browse the repository at this point in the history
* tensorflow and openssf

* Just some shit code that will be trashed

* Dropping useless code

* Auditing, prediction deletion and fixes of the report path building

* This was overly ambitious and just bad idea...

* fixing simplify import paths for WriteToDir

* Bunch of updates, however need to deal with references as they suck

* Ast nonsense code cleanups to start from base

* Bunch of corrections for reference resolver and tree updater

* More fixes

* More fixes, especially to type descriptions

* Remaining protos for ast, some documentation, bump of protos to 0.1.5. Should build now

* Bunch of corrections

* Sources test cases are now readable. Finally basic AST documentation completed

* More cleanups, fixes and unit test basic coverage

* Most of the AST is now at least basically unit tested

* Updates final I guess...
  • Loading branch information
0x19 authored Aug 17, 2023
1 parent 2bb90bc commit b327bdd
Show file tree
Hide file tree
Showing 191 changed files with 262,200 additions and 135,821 deletions.
20 changes: 13 additions & 7 deletions abi/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/txpull/solgo/ast"
"github.com/txpull/solgo/ir"
"github.com/txpull/solgo/tests"
"github.com/txpull/solgo/utils"
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
)
Expand All @@ -31,6 +32,7 @@ func TestBuilderFromSources(t *testing.T) {
expectedAbi string
expectedProto string
unresolvedReferences int64
isEmpty bool
}{
{
name: "Empty Contract Test",
Expand All @@ -50,6 +52,7 @@ func TestBuilderFromSources(t *testing.T) {
expectedAbi: tests.ReadJsonBytesForTest(t, "abi/Empty.abi").Content,
expectedProto: tests.ReadJsonBytesForTest(t, "abi/Empty.abi.proto").Content,
unresolvedReferences: 0,
isEmpty: true,
},
{
name: "Simple Storage Contract Test",
Expand Down Expand Up @@ -260,11 +263,14 @@ func TestBuilderFromSources(t *testing.T) {
root := builder.GetRoot()
assert.NotNil(t, root)

/* assert.GreaterOrEqual(
t,
int32(len(builder.GetSources().SourceUnits)),
root.GetContractsCount(),
) */
assert.NotNil(t, builder.GetSources())
assert.NotNil(t, builder.GetTypeResolver())

if !testCase.isEmpty {
assert.NotNil(t, root.GetIR())
assert.NotNil(t, root.GetContractsAsSlice())
assert.NotNil(t, root.GetEntryContract())
}

pretty, err := builder.ToJSONPretty()
assert.NoError(t, err)
Expand Down Expand Up @@ -293,7 +299,7 @@ func TestBuilderFromSources(t *testing.T) {

// Leaving it here for now to make unit tests pass...
// This will be removed before final push to the main branch
err = builder.GetAstBuilder().WriteToFile(
err = utils.WriteToFile(
"../data/tests/abi/"+testCase.sources.EntrySourceUnitName+".abi.json",
pretty,
)
Expand All @@ -306,7 +312,7 @@ func TestBuilderFromSources(t *testing.T) {

// Leaving it here for now to make unit tests pass...
// This will be removed before final push to the main branch
err = builder.GetAstBuilder().WriteToFile(
err = utils.WriteToFile(
"../data/tests/abi/"+testCase.sources.EntrySourceUnitName+".abi.proto.json",
protoPretty,
)
Expand Down
18 changes: 0 additions & 18 deletions abi/helpers.go
Original file line number Diff line number Diff line change
@@ -1,30 +1,12 @@
package abi

import (
"encoding/json"
"fmt"
"os"
"regexp"
"strings"

ast_pb "github.com/txpull/protos/dist/go/ast"
)

// dumpNode prints a formatted JSON representation of the provided interface and exits the program.
// This function is primarily used for debugging purposes.
func dumpNode(whatever interface{}) {
j, _ := json.MarshalIndent(whatever, "", "\t")
fmt.Println(string(j))
os.Exit(1)
}

// dumpNodeNoExit prints a formatted JSON representation of the provided interface without exiting the program.
// This function is primarily used for debugging purposes.
func dumpNodeNoExit(whatever interface{}) {
j, _ := json.MarshalIndent(whatever, "", "\t")
fmt.Println(string(j))
}

// normalizeStateMutability converts the provided Mutability value to its corresponding string representation.
func (b *Builder) normalizeStateMutability(m ast_pb.Mutability) string {
switch m {
Expand Down
11 changes: 10 additions & 1 deletion abi/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,20 @@ func (r *Root) GetEntryName() string {
return r.EntryContractName
}

// GetContracts returns the map of contracts in the ABI.
// GetContracts returns the map of contracts.
func (r *Root) GetContracts() map[string]*Contract {
return r.Contracts
}

// GetContractsAsSlice returns the slice contracts.
func (r *Root) GetContractsAsSlice() []*Contract {
toReturn := make([]*Contract, 0)
for _, c := range r.Contracts {
toReturn = append(toReturn, c)
}
return toReturn
}

// GetContractByName retrieves a contract by its name from the ABI.
// Returns nil if the contract is not found.
func (r *Root) GetContractByName(name string) *Contract {
Expand Down
140 changes: 140 additions & 0 deletions ast/and_operation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package ast

import (
v3 "github.com/cncf/xds/go/xds/type/v3"
ast_pb "github.com/txpull/protos/dist/go/ast"
"github.com/txpull/solgo/parser"
)

// AndOperation represents an 'and' operation in an abstract syntax tree.
type AndOperation struct {
*ASTBuilder

Id int64 `json:"id"`
NodeType ast_pb.NodeType `json:"node_type"`
Src SrcNode `json:"src"`
Expressions []Node[NodeType] `json:"expressions"`
TypeDescriptions []*TypeDescription `json:"type_descriptions"`
}

// NewAndOperationExpression creates a new AndOperation instance.
func NewAndOperationExpression(b *ASTBuilder) *AndOperation {
return &AndOperation{
ASTBuilder: b,
Id: b.GetNextID(),
NodeType: ast_pb.NodeType_AND_OPERATION,
TypeDescriptions: make([]*TypeDescription, 0),
}
}

// SetReferenceDescriptor sets the reference descriptions of the AndOperation node.
// This function always returns false for now.
func (b *AndOperation) SetReferenceDescriptor(refId int64, refDesc *TypeDescription) bool {
return false
}

// GetId returns the ID of the AndOperation.
func (f *AndOperation) GetId() int64 {
return f.Id
}

// GetType returns the NodeType of the AndOperation.
func (f *AndOperation) GetType() ast_pb.NodeType {
return f.NodeType
}

// GetSrc returns the source information of the AndOperation.
func (f *AndOperation) GetSrc() SrcNode {
return f.Src
}

// GetTypeDescription returns the type description associated with the AndOperation.
func (f *AndOperation) GetTypeDescription() *TypeDescription {
return f.TypeDescriptions[0]
}

// GetNodes returns the child nodes of the AndOperation.
func (f *AndOperation) GetNodes() []Node[NodeType] {
toReturn := []Node[NodeType]{}
toReturn = append(toReturn, f.Expressions...)
return toReturn
}

// GetExpressions returns the expressions within the AndOperation.
func (f *AndOperation) GetExpressions() []Node[NodeType] {
return f.Expressions
}

// ToProto converts the AndOperation to its corresponding protocol buffer representation.
func (f *AndOperation) ToProto() NodeType {
proto := ast_pb.AndOperation{
Id: f.GetId(),
NodeType: f.GetType(),
Src: f.GetSrc().ToProto(),
Expressions: make([]*v3.TypedStruct, 0),
TypeDescriptions: make([]*ast_pb.TypeDescription, 0),
}

for _, exp := range f.GetExpressions() {
proto.Expressions = append(proto.Expressions, exp.ToProto().(*v3.TypedStruct))
}

for _, typeDesc := range f.TypeDescriptions {
proto.TypeDescriptions = append(proto.TypeDescriptions, typeDesc.ToProto())
}

return NewTypedStruct(nil, "AndOperation")
}

// Parse parses the AndOperation node from the parsing context and associates it with other nodes.
func (f *AndOperation) Parse(
unit *SourceUnit[Node[ast_pb.SourceUnit]],
contractNode Node[NodeType],
fnNode Node[NodeType],
bodyNode *BodyNode,
vDeclar *VariableDeclaration,
expNode Node[NodeType],
ctx *parser.AndOperationContext,
) Node[NodeType] {
f.Id = f.GetNextID()
f.Src = SrcNode{
Id: f.GetNextID(),
Line: int64(ctx.GetStart().GetLine()),
Column: int64(ctx.GetStart().GetColumn()),
Start: int64(ctx.GetStart().GetStart()),
End: int64(ctx.GetStop().GetStop()),
Length: int64(ctx.GetStop().GetStop() - ctx.GetStart().GetStart() + 1),
ParentIndex: func() int64 {
if vDeclar != nil {
return vDeclar.GetId()
}

if expNode != nil {
return expNode.GetId()
}

if bodyNode != nil {
return bodyNode.GetId()
}

if fnNode != nil {
return fnNode.GetId()
}

return contractNode.GetId()
}(),
}

expression := NewExpression(f.ASTBuilder)

for _, expr := range ctx.AllExpression() {
parsedExp := expression.Parse(unit, contractNode, fnNode, bodyNode, vDeclar, f, expr)
f.Expressions = append(
f.Expressions,
parsedExp,
)
f.TypeDescriptions = append(f.TypeDescriptions, parsedExp.GetTypeDescription())
}

return f
}
2 changes: 1 addition & 1 deletion ast/assembly.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (a *AssemblyStatement) GetNodes() []Node[NodeType] {
// GetTypeDescription returns the type description of the assembly statement.
// For an AssemblyStatement, this is always nil.
func (a *AssemblyStatement) GetTypeDescription() *TypeDescription {
return nil
return &TypeDescription{}
}

// ToProto returns the protobuf representation of the assembly statement.
Expand Down
37 changes: 24 additions & 13 deletions ast/assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ import (
type Assignment struct {
*ASTBuilder

Id int64 `json:"id"`
NodeType ast_pb.NodeType `json:"node_type"`
Src SrcNode `json:"src"`
Expression Node[NodeType] `json:"expression,omitempty"`
Operator ast_pb.Operator `json:"operator,omitempty"`
LeftExpression Node[NodeType] `json:"left_expression,omitempty"`
RightExpression Node[NodeType] `json:"right_expression,omitempty"`
ReferencedDeclaration int64 `json:"referenced_declaration,omitempty"`
TypeDescription *TypeDescription `json:"type_description,omitempty"`
Id int64 `json:"id"` // Unique identifier for the Assignment node.
NodeType ast_pb.NodeType `json:"node_type"` // Type of the AST node.
Src SrcNode `json:"src"` // Source location information.
Expression Node[NodeType] `json:"expression,omitempty"` // Expression for the assignment (if used).
Operator ast_pb.Operator `json:"operator,omitempty"` // Operator used in the assignment.
LeftExpression Node[NodeType] `json:"left_expression,omitempty"` // Left-hand side expression.
RightExpression Node[NodeType] `json:"right_expression,omitempty"` // Right-hand side expression.
ReferencedDeclaration int64 `json:"referenced_declaration,omitempty"` // Referenced declaration identifier (if used).
TypeDescription *TypeDescription `json:"type_description,omitempty"` // Type description associated with the Assignment node.
}

// NewAssignment creates a new Assignment node with a given ASTBuilder.
Expand Down Expand Up @@ -129,7 +129,7 @@ func (a *Assignment) ToProto() NodeType {
func (a *Assignment) SetReferenceDescriptor(refId int64, refDesc *TypeDescription) bool {
a.ReferencedDeclaration = refId
a.TypeDescription = refDesc
return false
return true
}

// ParseStatement parses an expression statement context into the Assignment node.
Expand All @@ -142,6 +142,7 @@ func (a *Assignment) ParseStatement(
eCtx *parser.ExpressionStatementContext,
ctx *parser.AssignmentContext,
) {
// Setting the source location information.
a.Src = SrcNode{
Id: a.GetNextID(),
Line: int64(eCtx.GetStart().GetLine()),
Expand All @@ -166,8 +167,10 @@ func (a *Assignment) ParseStatement(
}(),
}

// Parsing the expression and setting the type description.
expression := NewExpression(a.ASTBuilder)
a.Expression = expression.Parse(unit, contractNode, fnNode, bodyNode, nil, nil, ctx)
a.TypeDescription = a.Expression.GetTypeDescription()
}

// Parse parses an assignment context into the Assignment node.
Expand All @@ -180,6 +183,7 @@ func (a *Assignment) Parse(
expNode Node[NodeType],
ctx *parser.AssignmentContext,
) Node[NodeType] {
// Setting the type and source location information.
a.NodeType = ast_pb.NodeType_ASSIGNMENT
a.Src = SrcNode{
Id: a.GetNextID(),
Expand All @@ -201,16 +205,23 @@ func (a *Assignment) Parse(
}(),
}

// Parsing the operator.
a.Operator = parseOperator(ctx.AssignOp())

// Parsing left and right expressions.
expression := NewExpression(a.ASTBuilder)
a.LeftExpression = expression.Parse(unit, contractNode, fnNode, bodyNode, vDeclar, a, ctx.Expression(0))
a.RightExpression = expression.Parse(unit, contractNode, fnNode, bodyNode, vDeclar, a, ctx.Expression(1))

// What we are going to do here is take left expression type description and assign it to the
// asignment type description. This is because the left expression is the one that holds the
// type description of the assignment.
// Setting the type description based on the left expression.
a.TypeDescription = a.LeftExpression.GetTypeDescription()

// If the left expression is nil, set the reference descriptor for the right expression.
if a.TypeDescription == nil {
a.LeftExpression.SetReferenceDescriptor(a.RightExpression.GetId(), a.RightExpression.GetTypeDescription())
a.TypeDescription = a.RightExpression.GetTypeDescription()
}

return a
}

Expand Down
10 changes: 5 additions & 5 deletions ast/base_contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ func (b *BaseContractName) GetReferencedDeclaration() int64 {
// ToProto returns the protobuf representation of the base contract name.
func (b *BaseContractName) ToProto() *ast_pb.BaseContractName {
return &ast_pb.BaseContractName{
Id: b.Id,
NodeType: b.NodeType,
Src: b.Src.ToProto(),
Name: b.Name,
ReferencedDeclaration: b.ReferencedDeclaration,
Id: b.GetId(),
NodeType: b.GetType(),
Src: b.GetSrc().ToProto(),
Name: b.GetName(),
ReferencedDeclaration: b.GetReferencedDeclaration(),
}
}
1 change: 1 addition & 0 deletions ast/binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ func (a *BinaryOperation) ParseEqualityComparison(
return a
}

// ParseOr is a method that parses or comparison operations.
func (a *BinaryOperation) ParseOr(
unit *SourceUnit[Node[ast_pb.SourceUnit]],
contractNode Node[NodeType],
Expand Down
5 changes: 4 additions & 1 deletion ast/body.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ func (b *BodyNode) IsImplemented() bool {
// GetTypeDescription returns the type description of the body node.
// As BodyNode does not have a type description, it returns nil.
func (b *BodyNode) GetTypeDescription() *TypeDescription {
return nil
return &TypeDescription{
TypeString: "block",
TypeIdentifier: "$_t_block",
}
}

// GetNodes returns the nodes associated with the body node.
Expand Down
Loading

0 comments on commit b327bdd

Please sign in to comment.