diff --git a/example/assert.c b/example/assert.c index 02fef4d..bb17954 100644 --- a/example/assert.c +++ b/example/assert.c @@ -22,4 +22,5 @@ extern char *to_string(int64_t i) { static char buffer[32]; sprintf(buffer, "%lld", (long long)i); - return buffer; \ No newline at end of file + return buffer; +} \ No newline at end of file diff --git a/example/main.flint b/example/main.flint index c44b9ec..8dbbde9 100644 --- a/example/main.flint +++ b/example/main.flint @@ -5,7 +5,6 @@ pub fn assert(cond: Bool) Nil pub fn print(string: String) Nil fn test(x: Int) Int { x } - pub fn main() Nil { match test(1) { | 1 -> print("One") diff --git a/example/match.flint b/example/match.flint index 5bdd295..d872d9e 100644 --- a/example/match.flint +++ b/example/match.flint @@ -1,5 +1,24 @@ -pub fn main() Int { - val x: List(Int) = [1, 2, 3] - val y: Int = x[1] - y +@external(c, "flint_stdlib", "assert") +pub fn assert(cond: Bool) Nil + +@external(c, "flint_stdlib", "print") +pub fn print(string: String) Nil + +pub fn println(v: String) Nil { + print(v) + print("\n") +} + +pub fn main() Nil { + val a: List(String) = ["1", "2", "3"] + println(a[0]) + + // val d: (Int, Float, String) = (1, 4.1, "Hiiiii") + // val b: List((Int, Float, String)) = [(1, 4.1, "Hiiiii"), (1, 4.1, "oooooo")] + // println(b[0][2]) + + mut c: String = "Hi Universe!" + println(c) + c = "Hello World!" + println(c) } \ No newline at end of file diff --git a/internal/codegen/builtins.go b/internal/codegen/builtins.go new file mode 100644 index 0000000..7dafd9d --- /dev/null +++ b/internal/codegen/builtins.go @@ -0,0 +1,109 @@ +package codegen + +import ( + "github.com/llir/llvm/ir" + "github.com/llir/llvm/ir/constant" + "github.com/llir/llvm/ir/enum" + "github.com/llir/llvm/ir/types" +) + +func (cg *CodeGen) defineExit() { + statusParam := ir.NewParam("statusCode", cg.platformIntType()) + flint_exit := cg.mod.NewFunc("flint_exit", types.Void, statusParam) + flint_exit.FuncAttrs = append(flint_exit.FuncAttrs, enum.FuncAttrNoReturn) + flint_exit_dispatch := cg.mod.NewFunc("flint_exit_dispatch", types.I32, statusParam) + + dispatch_entry := flint_exit_dispatch.NewBlock("entry") + dispatch_entry.NewRet(dispatch_entry.NewTrunc(statusParam, types.I32)) + + exit_entry := flint_exit.NewBlock("entry") + exit_entry.NewCall(flint_exit_dispatch, statusParam).Tail = enum.TailMustTail + exit_entry.NewUnreachable() + + cg.funcs["exit"] = flint_exit +} + +// func (cg *CodeGen) defineAssert() { +// valueParam := ir.NewParam("v", types.I1) +// flint_assert := cg.mod.NewFunc("flint_assert", types.Void, valueParam) + +// assert_entry := flint_assert.NewBlock("entry") +// // assert_true := flint_assert.NewBlock("assert.true") +// assert_false := flint_assert.NewBlock("assert.false") + +// cmp := assert_entry.NewICmp(enum.IPredNE, valueParam, constant.NewInt(types.I1, 1)) +// assert_entry.NewCondBr(cmp, cg.mod._, nil) +// assert_entry.NewRet(nil) + +// assert_entry.NewEx +// assert_false.NewRet(nil) + +// cg.funcs["assert"] = flint_assert +// } + +func (cg *CodeGen) defineBuiltins() { + cg.defineMkStr() + cg.defineStrlen() +} + +func (cg *CodeGen) defineStrlen() { + intType := cg.platformIntType() + + strParam := ir.NewParam("str", types.I8Ptr) + flint_strlen := cg.mod.NewFunc("flint_strlen", intType, strParam) + + entry := flint_strlen.NewBlock("entry") + loop := flint_strlen.NewBlock("loop") + inc := flint_strlen.NewBlock("loop.inc") + exit := flint_strlen.NewBlock("loop.exit") + + zeroInt := constant.NewInt(intType, 0) + oneInt := constant.NewInt(intType, 1) + + zero8 := constant.NewInt(types.I8, 0) + + // entry_start + strIdx := entry.NewAlloca(intType) + intPtr := entry.NewAlloca(intType) + + entry.NewStore(zeroInt, strIdx) + entry.NewStore(entry.NewPtrToInt(strParam, intType), intPtr) + + entry.NewBr(loop) + // entry_end + + // loop_start + intPtrAdd := loop.NewAdd( + loop.NewLoad(intType, intPtr), + loop.NewLoad(intType, strIdx), + ) + strPtr := loop.NewIntToPtr(intPtrAdd, types.I8Ptr) + + chr := loop.NewLoad(types.I8, strPtr) + cmp := loop.NewICmp(enum.IPredEQ, chr, zero8) + loop.NewCondBr(cmp, exit, inc) + // loop_end + + // exit_start + idxLoad := exit.NewLoad(intType, strIdx) + exit.NewRet(idxLoad) + // exit_end + + // inc_start + strPtrAdd := inc.NewAdd(inc.NewLoad(intType, strIdx), oneInt) + inc.NewStore(strPtrAdd, strIdx) + inc.NewBr(loop) + // inc_end + + cg.funcs["strlen"] = flint_strlen +} + +func (cg *CodeGen) defineMkStr() { + // strParam := ir.NewParam("size", types.I64) + // flint_strlen := cg.mod.NewFunc("flint_mkstr", types.I8Ptr, strParam) + + // entry := flint_strlen.NewBlock("entry") + // entry.NewUnreachable() + + // cg.funcs["mkstr"] = flint_strlen +} diff --git a/internal/codegen/expr.go b/internal/codegen/expr.go index 0e24e28..213006e 100644 --- a/internal/codegen/expr.go +++ b/internal/codegen/expr.go @@ -44,6 +44,12 @@ func (cg *CodeGen) emitExpr(b *ir.Block, e parser.Expr, isTail bool) value.Value return cg.emitAssign(b, v) case *parser.PrefixExpr: return cg.emitPrefix(b, v) + case *parser.ListExpr: + return cg.emitList(b, v) + case *parser.TupleExpr: + return cg.emitTuple(b, v) + case *parser.IndexExpr: + return cg.emitIndex(b, v) default: panic("unsupported expression type") } diff --git a/internal/codegen/lists.go b/internal/codegen/lists.go new file mode 100644 index 0000000..c32414b --- /dev/null +++ b/internal/codegen/lists.go @@ -0,0 +1,60 @@ +package codegen + +import ( + "flint/internal/parser" + "fmt" + + "github.com/llir/llvm/ir" + "github.com/llir/llvm/ir/constant" + "github.com/llir/llvm/ir/types" + "github.com/llir/llvm/ir/value" +) + +func (cg *CodeGen) emitList(b *ir.Block, e *parser.ListExpr) value.Value { + exprs := make([]value.Value, 0) + + for _, elem := range e.Elements { + expr := cg.emitExpr(b, elem, false) + exprs = append(exprs, expr) + } + listType := exprs[0].Type() + alloc := b.NewAlloca(types.NewArray(uint64(len(exprs)), listType)) + for idx, expr := range exprs { + index := constant.NewInt(types.I32, int64(idx)) + elemPtr := b.NewGetElementPtr(listType, alloc, index) + b.NewStore(expr, elemPtr) + } + return alloc +} + +func (cg *CodeGen) emitIndex(b *ir.Block, e *parser.IndexExpr) value.Value { + target := cg.emitExpr(b, e.Target, false) + index := cg.emitExpr(b, e.Index, false) + + elemType := (target.Type().(*types.PointerType)).ElemType + fmt.Println(target, index, elemType) + + elemPtr := b.NewGetElementPtr(elemType, target, index) + + return b.NewLoad(elemType, elemPtr) +} + +func (cg *CodeGen) emitTuple(b *ir.Block, e *parser.TupleExpr) value.Value { + exprs := make([]value.Value, 0) + tTypes := make([]types.Type, 0) + + for _, elem := range e.Elements { + expr := cg.emitExpr(b, elem, false) + exprs = append(exprs, expr) + tTypes = append(tTypes, expr.Type()) + } + tupleType := types.NewStruct(tTypes...) + alloc := b.NewAlloca(tupleType) + + for idx, expr := range exprs { + index := constant.NewInt(types.I32, int64(idx)) + elemPtr := b.NewGetElementPtr(tupleType, alloc, constant.NewInt(types.I32, 0), index) + b.NewStore(expr, elemPtr) + } + return alloc +}