diff --git a/compiler/compiler/alloc.go b/compiler/compiler/alloc.go index 747cbcf..2906c58 100644 --- a/compiler/compiler/alloc.go +++ b/compiler/compiler/alloc.go @@ -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) @@ -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 { @@ -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 diff --git a/compiler/compiler/condition.go b/compiler/compiler/condition.go index 6f7d14b..3736620 100644 --- a/compiler/compiler/condition.go +++ b/compiler/compiler/condition.go @@ -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 { @@ -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())) } diff --git a/compiler/compiler/constants.go b/compiler/compiler/constants.go index c01d131..bba9d74 100644 --- a/compiler/compiler/constants.go +++ b/compiler/compiler/constants.go @@ -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, } diff --git a/compiler/compiler/types/type.go b/compiler/compiler/types/type.go index 134e167..54e611f 100644 --- a/compiler/compiler/types/type.go +++ b/compiler/compiler/types/type.go @@ -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" @@ -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") +} diff --git a/compiler/compiler/value/value.go b/compiler/compiler/value/value.go index a067177..71b575e 100644 --- a/compiler/compiler/value/value.go +++ b/compiler/compiler/value/value.go @@ -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" @@ -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") + } +} diff --git a/compiler/testdata/const.go b/compiler/testdata/const.go new file mode 100644 index 0000000..462b51e --- /dev/null +++ b/compiler/testdata/const.go @@ -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 +} diff --git a/compiler/testdata/const_no_modify.go b/compiler/testdata/const_no_modify.go new file mode 100644 index 0000000..37880e6 --- /dev/null +++ b/compiler/testdata/const_no_modify.go @@ -0,0 +1,10 @@ +package main + +const ( + c = 12 +) + +func main() { + // compile panic: Can only assign to variable + c = 40 +}