Skip to content

Commit

Permalink
Implement void functions
Browse files Browse the repository at this point in the history
* void functions cannot return values
* void functions cannot be used as expressions
  • Loading branch information
algorandskiy authored and pzbitskiy committed Apr 10, 2022
1 parent 429b9f6 commit 118514d
Show file tree
Hide file tree
Showing 10 changed files with 421 additions and 110 deletions.
8 changes: 7 additions & 1 deletion GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,18 @@ function logic() {

## Functions

Functions must return some value and can not be recursive or re-entrant.
There are three kinds of functions:
* Inline
* Regular
* Void

Non-void functions must return some value. All functions can not be recursive or re-entrant.

```
inline function inc(x) { return x+1; } // inlined at the calling point
function dec(y) { return y-1; } // uses callsub and retsub
function logic() { return inc(0); }
function noop() void { return; }
```

## Logic function
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ function sample2(a) {
return a + 1
}
function noop() void {
return
}
function logic() {
return sample1(2) + sample2(3)
}
Expand Down
1 change: 1 addition & 0 deletions TealangLexer.l4
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ CLEARSTATE : 'clearstate' ;
FOR : 'for' ;
BREAK : 'break' ;
INLINE : 'inline' ;
VOID : 'void' ;

GLOBAL : 'global' ;
INNERTXN : 'itxn' ;
Expand Down
40 changes: 25 additions & 15 deletions TealangParser.g4
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ options {
}

program
: declaration* (main) EOF
: globalStatement* (main) EOF
;

module
Expand All @@ -22,8 +22,8 @@ statement
| termination
| assignment
| builtinVarStatement
| logStatement
| innertxn
| functionCallStatement
| NEWLINE|SEMICOLON
;

Expand All @@ -35,17 +35,22 @@ main
: FUNC MAINFUNC LEFTPARA RIGHTPARA block NEWLINE*
;

globalStatement
: declaration
| functionCallStatement
;

declaration
: decl (NEWLINE|SEMICOLON)
| IMPORT MODULENAME MODULENAMEEND
| INLINE? FUNC IDENT LEFTPARA (IDENT (COMMA IDENT)* )? RIGHTPARA block NEWLINE
| INLINE? FUNC IDENT LEFTPARA (IDENT (COMMA IDENT)* )? RIGHTPARA VOID? block NEWLINE
| NEWLINE|SEMICOLON
;

// named rules for tree-walking only
condition
: IF condIfExpr condTrueBlock (NEWLINE? ELSE condFalseBlock)? # IfStatement
| FOR condForExpr condTrueBlock # ForStatement
| FOR condForExpr condTrueBlock # ForStatement
;

condTrueBlock
Expand All @@ -66,7 +71,7 @@ innertxn

termination
: ERR (NEWLINE|SEMICOLON) # TermError
| RET expr (NEWLINE|SEMICOLON) # TermReturn
| RET expr? (NEWLINE|SEMICOLON) # TermReturn
| ASSERT LEFTPARA expr RIGHTPARA # TermAssert
| BREAK (NEWLINE|SEMICOLON) # Break
;
Expand All @@ -89,13 +94,13 @@ expr
: IDENT # Identifier
| NUMBER # NumberLiteral
| STRING # StringLiteral
| LEFTPARA expr RIGHTPARA # Group
| functionCall # FunctionCallExpr
| LEFTPARA expr RIGHTPARA # Group
| functionCallExpresion # FunctionCallExpr
| builtinVarExpr # BuiltinObject
| op=LNOT expr # Not
| op=BNOT expr # BitNot
| expr op=(MUL|DIV|MOD) expr # MulDivMod
| expr op=(PLUS|MINUS) expr # AddSub
| expr op=(MUL|DIV|MOD) expr # MulDivMod
| expr op=(PLUS|MINUS) expr # AddSub
| expr op=(LESS|LE|GREATER|GE|EE|NE) expr # Relation
| expr op=(BOR|BXOR|BAND) expr # BitOp
| expr op=(LAND|LOR) expr # AndOr
Expand Down Expand Up @@ -126,17 +131,22 @@ builtinVarStatement
| APPS LEFTSQUARE expr RIGHTSQUARE DOT (APPPUT|APPDEL) LEFTPARA expr (COMMA expr)? RIGHTPARA
;

logStatement
: LOG LEFTPARA expr RIGHTPARA # DoLog
;

functionCall
functionCallExpresion
: BUILTINFUNC LEFTPARA ( expr (COMMA expr)* )? RIGHTPARA # BuiltinFunCall
| IDENT LEFTPARA ( expr (COMMA expr)* )? RIGHTPARA # FunCall
| functionCall # FunCall
| ECDSAVERIFY LEFTPARA ( ECDSACURVE COMMA expr COMMA expr COMMA expr COMMA expr COMMA expr ) RIGHTPARA # EcDsaFunCall
| EXTRACT LEFTPARA ( (EXTRACTOPT COMMA)? expr COMMA expr (COMMA expr)? ) RIGHTPARA # ExtractFunCall
;

functionCallStatement
: functionCall # VoidFunCall
| LOG LEFTPARA expr RIGHTPARA # DoLog
;

functionCall
: IDENT LEFTPARA ( expr (COMMA expr)* )? RIGHTPARA
;

builtinVarExpr
: GLOBAL DOT GLOBALFIELD # GlobalFieldExpr
| txn # TxnFieldExpr
Expand Down
89 changes: 65 additions & 24 deletions compiler/ast.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ type funDefNode struct {
name string
args []funArg
inline bool
void bool
}

type blockNode struct {
Expand Down Expand Up @@ -405,8 +406,7 @@ type ifExprNode struct {

type forStatementNode struct {
*TreeNode
condExpr ExprNodeIf
condTrueExpr ExprNodeIf
condExpr ExprNodeIf
}

type ifStatementNode struct {
Expand Down Expand Up @@ -727,22 +727,6 @@ func newRuntimeArgNode(ctx *context, parent TreeNodeIf, op string, number string
//
//--------------------------------------------------------------------------------------------------

func (n *varDeclNode) setExpr(value ExprNodeIf) {
n.value = value
}

func (n *varDeclTupleNode) setExpr(value ExprNodeIf) {
n.value = value
}

func (n *varDeclQuadrupleNode) setExpr(value ExprNodeIf) {
n.value = value
}

func (n *exprGroupNode) setExpr(value ExprNodeIf) {
n.value = value
}

func (n *exprLiteralNode) getType() (exprType, error) {
return n.exprType, nil
}
Expand Down Expand Up @@ -869,7 +853,7 @@ func determineBlockReturnType(node TreeNodeIf, retTypeSeen []exprType) (exprType
retTypeSeen = append(retTypeSeen, tp)
case *errorNode:
retTypeSeen = append(retTypeSeen, intType) // error is ok
case *ifStatementNode, *blockNode:
case *ifStatementNode, *blockNode, *forStatementNode:
blockType, err := determineBlockReturnType(stmt, retTypeSeen)
if err != nil {
return invalidType, err
Expand Down Expand Up @@ -929,7 +913,7 @@ func (n *funCallNode) getType() (exprType, error) {
if err != nil {
_, builtin = builtinFun[n.name]
if !builtin {
return invalidType, fmt.Errorf("function %s lookup failed: %s", n.name, err.Error())
return invalidType, fmt.Errorf("function '%s' lookup failed: %s", n.name, err.Error())
}
}

Expand All @@ -940,7 +924,7 @@ func (n *funCallNode) getType() (exprType, error) {
if idx, ok := builtinFunDependantTypes[n.name]; ok {
tp, err = n.childrenNodes[idx].(ExprNodeIf).getType()
if err != nil {
return invalidType, fmt.Errorf("function %s type deduction failed: %s", n.name, err.Error())
return invalidType, fmt.Errorf("function '%s' type deduction failed: %s", n.name, err.Error())
}
}
}
Expand All @@ -956,7 +940,7 @@ func (n *funCallNode) getTypeTuple() (exprType, exprType, error) {
builtin := false
_, builtin = builtinFun[n.name]
if !builtin {
return invalidType, invalidType, fmt.Errorf("function %s lookup failed: %s", n.name, err.Error())
return invalidType, invalidType, fmt.Errorf("function '%s' lookup failed: %s", n.name, err.Error())
}

var tpl exprType = invalidType
Expand Down Expand Up @@ -984,7 +968,7 @@ func (n *funCallNode) getTypeQuadruple() (exprType, exprType, exprType, exprType
builtin := false
_, builtin = builtinFun[n.name]
if !builtin {
return invalidType, invalidType, invalidType, invalidType, fmt.Errorf("function %s lookup failed: %s", n.name, err.Error())
return invalidType, invalidType, invalidType, invalidType, fmt.Errorf("function '%s' lookup failed: %s", n.name, err.Error())
}

var tpl exprType = invalidType
Expand Down Expand Up @@ -1102,7 +1086,64 @@ func (n *TreeNode) parent() TreeNodeIf {
return n.parentNode
}

// root returns programNode node
func (n *TreeNode) root() *programNode {
var node TreeNodeIf = n
for ; node != nil; node = node.parent() {
if p, ok := node.(*programNode); ok {
return p
}
}
return nil
}

//--------------------------------------------------------------------------------------------------
//
// helper methods
//
//--------------------------------------------------------------------------------------------------

func (p *programNode) registerFunction(defNode *funDefNode) {
found := false
for _, ch := range p.nonInlineFunc {
if ch.name == defNode.name {
found = true
break
}
}
if !found {
p.nonInlineFunc = append(p.nonInlineFunc, defNode)
}
}

func (ctx *context) registerFunCall(name string, node *funCallNode) {
if _, ok := ctx.functions[name]; !ok {
ctx.functions[name] = node
}
}

func (n *varDeclNode) setExpr(value ExprNodeIf) {
n.value = value
}

func (n *varDeclTupleNode) setExpr(value ExprNodeIf) {
n.value = value
}

func (n *varDeclQuadrupleNode) setExpr(value ExprNodeIf) {
n.value = value
}

func (n *exprGroupNode) setExpr(value ExprNodeIf) {
n.value = value
}

//--------------------------------------------------------------------------------------------------
//
// Print AST and context
//
//--------------------------------------------------------------------------------------------------

func (n *TreeNode) Print() {
printImpl(n, 0)

Expand Down Expand Up @@ -1164,7 +1205,7 @@ func (n *ifExprNode) String() string {
}

func (n *forStatementNode) String() string {
return fmt.Sprintf("for %s { %s}", n.condExpr, n.condTrueExpr)
return fmt.Sprintf("for %s {}", n.condExpr)
}

func (n *returnNode) String() string {
Expand Down
Loading

0 comments on commit 118514d

Please sign in to comment.