Skip to content

Commit

Permalink
Merge #160
Browse files Browse the repository at this point in the history
160: Constants r=zegl a=zegl

Updates #159

Co-authored-by: Gustav Westling <[email protected]>
  • Loading branch information
bors[bot] and zegl authored Feb 9, 2020
2 parents a6973f7 + 8bb7e77 commit 0a8f1a9
Show file tree
Hide file tree
Showing 13 changed files with 178 additions and 17 deletions.
18 changes: 18 additions & 0 deletions compiler/compiler/alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ func (c *Compiler) compileAllocNode(v *parser.AllocNode) {
c.contextAlloc = c.contextAlloc[0 : len(c.contextAlloc)-1]
}()

if v.IsConst {
c.compileAllocConstNode(v)
return
}

// Allocate from type
if len(v.Val) == 0 && v.Type != nil {
treType := c.parserTypeToType(v.Type)
Expand Down Expand Up @@ -125,6 +130,16 @@ func (c *Compiler) compileAllocNode(v *parser.AllocNode) {
return
}

func (c *Compiler) compileAllocConstNode(v *parser.AllocNode) {
for i, varName := range v.Name {
cnst := v.Val[i].(*parser.ConstantNode)
c.setVar(varName, value.Value{
Type: &types.UntypedConstantNumber{},
Value: constant.NewInt(i64.LLVM().(*irTypes.IntType), cnst.Value),
})
}
}

func (c *Compiler) compileAssignNode(v *parser.AssignNode) {
// Allocate from type
if typeNode, ok := v.Val[0].(parser.TypeNode); ok {
Expand All @@ -143,6 +158,9 @@ func (c *Compiler) compileAssignNode(v *parser.AssignNode) {
// Skip temporary variables if we're assigning to one single var
if len(v.Target) == 1 {
dst := c.compileValue(v.Target[0])
if !dst.IsVariable {
compilePanic("Can only assign to variable")
}
s := c.compileSingleAssign(dst.Type, dst, v.Val[0])
c.contextBlock.NewStore(s, dst.Value)
return
Expand Down
16 changes: 13 additions & 3 deletions compiler/compiler/condition.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,19 @@ func getConditionLLVMpred(operator parser.Operator) enum.IPred {

func (c *Compiler) compileOperatorNode(v *parser.OperatorNode) value.Value {
left := c.compileValue(v.Left)
leftLLVM := left.Value

right := c.compileValue(v.Right)

_, rightIsUntyped := right.Type.(*types.UntypedConstantNumber)
_, leftIsUntyped := left.Type.(*types.UntypedConstantNumber)

if rightIsUntyped && !leftIsUntyped {
right = value.UntypedConstAs(right, left)
}
if leftIsUntyped && !rightIsUntyped {
left = value.UntypedConstAs(left, right)
}

leftLLVM := left.Value
rightLLVM := right.Value

if left.IsVariable {
Expand All @@ -48,7 +58,7 @@ func (c *Compiler) compileOperatorNode(v *parser.OperatorNode) value.Value {
rightLLVM = c.contextBlock.NewLoad(pointer.ElemType(rightLLVM), rightLLVM)
}

if !leftLLVM.Type().Equal(rightLLVM.Type()) {
if !leftLLVM.Type().Equal(rightLLVM.Type()) && !rightIsUntyped && !leftIsUntyped {
panic(fmt.Sprintf("Different types in operation: %T and %T (%+v and %+v)", left.Type, right.Type, leftLLVM.Type(), rightLLVM.Type()))
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/compiler/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (c *Compiler) compileConstantNode(v *parser.ConstantNode) value.Value {

return value.Value{
Value: constant.NewInt(intType.Type, v.Value),
Type: i64,
Type: intType,
IsVariable: false,
}

Expand Down
5 changes: 3 additions & 2 deletions compiler/compiler/func.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,16 @@ func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) value.Value {
}

// Save all parameters in the block mapping
// Return value arguments are ignored
for i, param := range llvmParams {
var paramName string
var dataType types.Type
var isVariable bool

// Named return values
if i < argumentReturnValuesCount {
paramName = v.ReturnValues[i].Name
dataType = treReturnTypes[i]
isVariable = true
} else {
paramName = v.Arguments[i-argumentReturnValuesCount].Name
dataType = treParams[i-argumentReturnValuesCount]
Expand All @@ -218,7 +219,7 @@ func (c *Compiler) compileDefineFuncNode(v *parser.DefineFuncNode) value.Value {
c.setVar(paramName, value.Value{
Value: param,
Type: dataType,
IsVariable: false,
IsVariable: isVariable,
})
}

Expand Down
15 changes: 14 additions & 1 deletion compiler/compiler/types/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ package types

import (
"fmt"
"math/big"

"github.com/llir/llvm/ir"
"github.com/llir/llvm/ir/constant"
"github.com/llir/llvm/ir/types"
llvmValue "github.com/llir/llvm/ir/value"
"math/big"

"github.com/zegl/tre/compiler/compiler/internal/pointer"
"github.com/zegl/tre/compiler/compiler/name"
Expand Down Expand Up @@ -342,3 +343,15 @@ func (m MultiValue) Name() string {
func (m MultiValue) LLVM() types.Type {
panic("MutliValue has no LLVM type")
}

type UntypedConstantNumber struct {
backingType
}

func (m UntypedConstantNumber) Name() string {
return "UntypedConstantNumber"
}

func (m UntypedConstantNumber) LLVM() types.Type {
panic("UntypedConstantNumber has no LLVM type")
}
19 changes: 19 additions & 0 deletions compiler/compiler/value/value.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package value

import (
"github.com/llir/llvm/ir/constant"
llvmValue "github.com/llir/llvm/ir/value"

"github.com/zegl/tre/compiler/compiler/types"
Expand All @@ -21,3 +22,21 @@ type Value struct {
// type information
MultiValues []Value
}

func UntypedConstAs(val Value, context Value) Value {
switch val.Type.(type) {
case *types.UntypedConstantNumber:
if contextInt, ok := context.Type.(*types.Int); ok {
return Value{
Type: contextInt,
Value: &constant.Int{
Typ: contextInt.Type,
X: val.Value.(*constant.Int).X,
},
}
}
panic("unexpected type in UntypedConstAs")
default:
panic("unexpected type in UntypedConstAs")
}
}
1 change: 1 addition & 0 deletions compiler/lexer/keywords.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ var keywords = map[string]struct{}{
"type": {},
"struct": {},
"var": {},
"const": {},
"package": {},
"for": {},
"break": {},
Expand Down
2 changes: 2 additions & 0 deletions compiler/parser/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ type AllocNode struct {
Val []Node

Type TypeNode // Is set when allocating on the format "var ident int" and "var ident, ident int = expr, expr"

IsConst bool // Is true when in a const expression.
}

func (an AllocNode) String() string {
Expand Down
22 changes: 12 additions & 10 deletions compiler/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -527,9 +527,11 @@ func (p *parser) parseOneWithOptions(withAheadParse, withArithAhead, withIdentif
}

// New instance of type
if current.Val == "var" {
if current.Val == "var" || current.Val == "const" {
p.i++

isConst := current.Val == "const"

isGroup := p.lookAhead(0)
if isGroup.Val == "(" {
p.i++
Expand All @@ -544,12 +546,12 @@ func (p *parser) parseOneWithOptions(withAheadParse, withArithAhead, withIdentif
p.i++
continue
}
allocs = append(allocs, p.parseVarDecl())
allocs = append(allocs, p.parseVarDecl(isConst))
}
return &AllocGroup{Allocs: allocs}
}

return p.parseVarDecl()
return p.parseVarDecl(isConst)
}

if current.Val == "package" {
Expand Down Expand Up @@ -612,15 +614,15 @@ func (p *parser) parseOneWithOptions(withAheadParse, withArithAhead, withIdentif
panic("")
}

func (p *parser) parseVarDecl() *AllocNode {
allocNode := &AllocNode{Name: p.identifierList()}
func (p *parser) parseVarDecl(isConst bool) *AllocNode {
allocNode := &AllocNode{Name: p.identifierList(), IsConst: isConst}

isEq := p.lookAhead(0)
if isEq.Type == lexer.OPERATOR && isEq.Val == "=" {
p.i++
allocNode.Val = p.expressionList()
return allocNode
} else {
if isEq.Type != lexer.OPERATOR || isEq.Val != "=" {
if isConst {
panic("unexpected type in const declaration")
}

tp, err := p.parseOneType()
if err != nil {
panic(err)
Expand Down
49 changes: 49 additions & 0 deletions compiler/parser/var_alloc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,52 @@ func TestAllocGroup(t *testing.T) {

assert.Equal(t, expected, Parse(lexed, false))
}

func TestConstAlloc(t *testing.T) {
lexed := lexer.Lex(`const a = 30`)
expected := FileNode{
Instructions: []Node{
&AllocNode{
IsConst: true,
Name: []string{"a"},
Val: []Node{&ConstantNode{Type: NUMBER, Value: 30}},
},
},
}

assert.Equal(t, expected, Parse(lexed, false))
}

func TestAllocConstGroup(t *testing.T) {
lexed := lexer.Lex(`const (
a = 10
b, c = "bbb", "ccc"
d = 20
)`)

expected := FileNode{
Instructions: []Node{
&AllocGroup{
Allocs: []*AllocNode{
{
IsConst: true,
Name: []string{"a"},
Val: []Node{&ConstantNode{Type: NUMBER, Value: 10}},
},
{
Name: []string{"b", "c"},
Val: []Node{&ConstantNode{Type: STRING, ValueStr: "bbb"}, &ConstantNode{Type: STRING, ValueStr: "ccc"}},
IsConst: true,
},
{
Name: []string{"d"},
Val: []Node{&ConstantNode{Type: NUMBER, Value: 20}},
IsConst: true,
},
},
},
},
}

assert.Equal(t, expected, Parse(lexed, false))
}
26 changes: 26 additions & 0 deletions compiler/testdata/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import "external"

const (
a = 10
c = 12

big = 100000000
)

func main() {
external.Printf("%d\n", a) // 10

var b uint8
b = 5
external.Printf("%d\n", b+a) // 15
external.Printf("%d\n", a+b) // 15

external.Printf("%d\n", a+c) // 22

var b32 int32
b32 = 222288822
external.Printf("%d\n", b32+a) // 222288832
external.Printf("%d\n", a+b32) // 222288832
}
10 changes: 10 additions & 0 deletions compiler/testdata/const_no_modify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package main

const (
c = 12
)

func main() {
// compile panic: Can only assign to variable
c = 40
}
10 changes: 10 additions & 0 deletions compiler/testdata/tour-named-return.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ func namedReturnNotUsed(inp int) (res int) {
return 500
}

func multiNamedReturnRef(inp int) (x int, y int) {
x = inp * 2
y = x + 2
return
}

func main() {
// 34 8
a, b := multiNamedReturn(17)
Expand All @@ -28,4 +34,8 @@ func main() {

// 500
external.Printf("%d\n", namedReturnNotUsed(18))

// 36 38
c, d := multiNamedReturnRef(18)
external.Printf("%d %d\n", c, d)
}

0 comments on commit 0a8f1a9

Please sign in to comment.