Skip to content

Commit

Permalink
func: add support for functions as values
Browse files Browse the repository at this point in the history
This updates #36
  • Loading branch information
zegl committed Dec 1, 2018
1 parent b147f00 commit ffd1c95
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 12 deletions.
7 changes: 7 additions & 0 deletions compiler/compiler/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@ package compiler
import "fmt"

var blockIndex uint64
var anonFuncIndex uint64

func getBlockName() string {
name := fmt.Sprintf("block-%d", blockIndex)
blockIndex++
return name
}

func getAnonFuncName() string {
name := fmt.Sprintf("fn-%d", anonFuncIndex)
anonFuncIndex++
return name
}

func getVarName(prefix string) string {
name := fmt.Sprintf("%s-%d", prefix, blockIndex)
blockIndex++
Expand Down
13 changes: 8 additions & 5 deletions compiler/compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ func (c *Compiler) Compile(root parser.PackageNode) (err error) {
}

func (c *Compiler) GetIR() string {
return fmt.Sprintln(c.module)
return c.module.String()
}

func (c *Compiler) addGlobal() {
Expand Down Expand Up @@ -214,17 +214,17 @@ func (c *Compiler) compile(instructions []parser.Node) {
}
}

func (c *Compiler) funcByName(name string) *types.Function {
func (c *Compiler) funcByName(name string) (*types.Function, bool) {
if f, ok := c.globalFuncs[name]; ok {
return f
return f, true
}

// Function in the current package
if f, ok := c.currentPackage.Funcs[name]; ok {
return f
return f, true
}

panic("funcByName: no such func: " + name)
return nil, false
}

func (c *Compiler) varByName(name string) value.Value {
Expand Down Expand Up @@ -294,6 +294,9 @@ func (c *Compiler) compileValue(node parser.Node) value.Value {
return c.compileInitStructWithValues(v)
case *parser.TypeCastInterfaceNode:
return c.compileTypeCastInterfaceNode(v)

case *parser.DefineFuncNode:
return c.compileDefineFuncNode(v)
}

panic("compileValue fail: " + fmt.Sprintf("%T: %+v", node, node))
Expand Down
35 changes: 29 additions & 6 deletions compiler/compiler/func.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package compiler

import (
"fmt"
"github.com/llir/llvm/ir"
"github.com/llir/llvm/ir/constant"
llvmTypes "github.com/llir/llvm/ir/types"
Expand All @@ -11,7 +12,7 @@ import (
"github.com/zegl/tre/compiler/parser"
)

func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) {
func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) value.Value {
var compiledName string

if v.IsMethod {
Expand All @@ -31,8 +32,10 @@ func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) {

// Change the name of our function
compiledName = c.currentPackageName + "_method_" + v.MethodOnType.TypeName + "_" + v.Name
} else {
} else if v.IsNamed {
compiledName = c.currentPackageName + "_" + v.Name
} else {
compiledName = c.currentPackageName + "_" + getAnonFuncName()
}

llvmParams := make([]*ir.Param, len(v.Arguments))
Expand Down Expand Up @@ -127,12 +130,15 @@ func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) {

// Make this method available in interfaces via a jump function
typesFunc.JumpFunction = c.compileInterfaceMethodJump(fn)
} else {
} else if v.IsNamed {
c.currentPackage.Funcs[v.Name] = typesFunc
}

entry := fn.NewBlock(getBlockName())

prevContextFunc := c.contextFunc
prevContextBlock := c.contextBlock

c.contextFunc = typesFunc
c.contextBlock = entry
c.pushVariablesStack()
Expand Down Expand Up @@ -196,7 +202,15 @@ func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) {
c.contextBlock.NewRet(constant.NewInt(llvmTypes.I32, 0))
}

c.contextFunc = prevContextFunc
c.contextBlock = prevContextBlock

c.popVariablesStack()

return value.Value{
Type: typesFunc,
Value: typesFunc.LlvmFunction,
}
}

func (c *Compiler) compileInterfaceMethodJump(targetFunc *ir.Function) *ir.Function {
Expand Down Expand Up @@ -248,7 +262,7 @@ func (c *Compiler) compileReturnNode(v *parser.ReturnNode) {
// Set value and jump to return block
val := c.compileValue(v.Vals[0])

// Type cast if neccesary
// Type cast if necessary
val = c.valueToInterfaceValue(val, c.contextFunc.LlvmReturnType)

if val.IsVariable {
Expand All @@ -264,7 +278,7 @@ func (c *Compiler) compileReturnNode(v *parser.ReturnNode) {
for i, val := range v.Vals {
compVal := c.compileValue(val)

// Type cast if neccesary
// TODO: Type cast if necessary
// compVal = c.valueToInterfaceValue(compVal, c.contextFunc.ReturnType)

// Assign to ptr
Expand Down Expand Up @@ -300,7 +314,16 @@ func (c *Compiler) compileCallNode(v *parser.CallNode) value.Value {
var fn *types.Function

if isNameNode {
fn = c.funcByName(name.Name)
if namedFn, ok := c.funcByName(name.Name); ok {
fn = namedFn
} else {
funcByVal := c.compileValue(v.Function)
if checkIfFunc, ok := funcByVal.Type.(*types.Function); ok {
fn = checkIfFunc
} else {
panic(fmt.Sprintf("no such function: %v", v))
}
}
} else {
funcByVal := c.compileValue(v.Function)
if checkIfFunc, ok := funcByVal.Type.(*types.Function); ok {
Expand Down
5 changes: 4 additions & 1 deletion compiler/compiler/func_len.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ func (c *Compiler) lenFuncCall(v *parser.CallNode) value.Value {
arg := c.compileValue(v.Arguments[0])

if arg.Type.Name() == "string" {
f := c.funcByName("len_string")
f, ok := c.funcByName("len_string")
if !ok {
panic("could not find len_string func")
}

val := arg.Value
if arg.IsVariable {
Expand Down
18 changes: 18 additions & 0 deletions compiler/testdata/func-as-value.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import "external"

func main() {
f1 := func() int {
return 100
}

external.Printf("%d\n", f1()) // 100


f2 := func(a int) int {
return 100 * a
}

external.Printf("%d\n", f2(2)) // 200
}
4 changes: 4 additions & 0 deletions compiler/testdata/int64-method.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ func main() {
var abc myint
abc = 100
abc.Yolo()

f1 := func() int {
return 100
}
}

0 comments on commit ffd1c95

Please sign in to comment.