package expr import "llvm.org/llvm/bindings/go/llvm" type BuildCtx struct { C *Ctx B llvm.Builder M llvm.Module } func (bctx BuildCtx) Build(stmts ...Statement) llvm.Value { var lastVal llvm.Value for _, stmt := range stmts { if e := bctx.BuildStmt(stmt); e != nil { lastVal = bctx.buildVal(e) } } if (lastVal == llvm.Value{}) { lastVal = bctx.B.CreateRetVoid() } return lastVal } func (bctx BuildCtx) BuildStmt(s Statement) Expr { m := s.Op.(Macro) return bctx.C.Macro(m)(bctx, s.Arg) } // may return nil if e is a Statement which has no return func (bctx BuildCtx) buildExpr(e Expr) Expr { return bctx.buildExprTill(e, func(Expr) bool { return false }) } // like buildExpr, but will stop short and stop recursing when the function // returns true func (bctx BuildCtx) buildExprTill(e Expr, fn func(e Expr) bool) Expr { if fn(e) { return e } switch ea := e.(type) { case llvmVal: return e case Int: return llvmVal(llvm.ConstInt(llvm.Int64Type(), uint64(ea), false)) case Identifier: return bctx.C.Identifier(ea) case Statement: return bctx.BuildStmt(ea) case Tuple: for i := range ea { ea[i] = bctx.buildExprTill(ea[i], fn) } return ea case List: for i := range ea { ea[i] = bctx.buildExprTill(ea[i], fn) } return ea default: panicf("type %T can't express a value", ea) } panic("go is dumb") } func (bctx BuildCtx) buildVal(e Expr) llvm.Value { return llvm.Value(bctx.buildExpr(e).(llvmVal)) } // globalCtx describes what's available to *all* contexts, and is what all // contexts should have as the root parent in the tree var globalCtx = &Ctx{ macros: map[Macro]MacroFn{ "add": func(bctx BuildCtx, e Expr) Expr { tup := bctx.buildExpr(e).(Tuple) a := bctx.buildVal(tup[0]) b := bctx.buildVal(tup[1]) return llvmVal(bctx.B.CreateAdd(a, b, "")) }, "bind": func(bctx BuildCtx, e Expr) Expr { tup := bctx.buildExprTill(e, isIdentifier).(Tuple) id := bctx.buildExprTill(tup[0], isIdentifier).(Identifier) *bctx.C = bctx.C.Bind(id, bctx.buildExpr(tup[1])) return nil }, }, }