package compiler import ( "jinx/pkg/lang/ast" "jinx/pkg/lang/vm/code" ) type Compiler struct { ast ast.Program builder code.Builder } func New(ast ast.Program) *Compiler { return &Compiler{ ast: ast, builder: code.NewBuilder(), } } func (comp *Compiler) Compile() (code.Code, error) { for _, stmt := range comp.ast.Stmts { if stmt.Kind == ast.StmtKindEmpty { continue } if stmt.Kind != ast.StmtKindExpr { panic("statements other than expressions and empties not implemented") } expr := stmt.Value.(ast.StmtExpr).Value if err := comp.compileExpr(expr); err != nil { return code.Code{}, err } } return comp.builder.Build(), nil } func (comp *Compiler) compileExpr(expr ast.Expr) error { switch expr.Kind { case ast.ExprKindBinary: return comp.compileBinaryExpr(expr.Value.(ast.ExprBinary)) case ast.ExprKindUnary: return comp.compileUnaryExpr(expr.Value.(ast.ExprUnary)) case ast.ExprKindCall: return comp.compileCallExpr(expr.Value.(ast.ExprCall)) case ast.ExprKindSubscription: return comp.compileSubscriptionExpr(expr.Value.(ast.ExprSubscription)) case ast.ExprKindGroup: return comp.compileGroupExpr(expr.Value.(ast.ExprGroup)) case ast.ExprKindFnLit: panic("not implemented") case ast.ExprKindArrayLit: panic("not implemented") case ast.ExprKindIdent: panic("not implemented") case ast.ExprKindIntLit: return comp.compileIntLitExpr(expr.Value.(ast.ExprIntLit)) case ast.ExprKindFloatLit: return comp.compileFloatLitExpr(expr.Value.(ast.ExprFloatLit)) case ast.ExprKindStringLit: return comp.compileStringLitExpr(expr.Value.(ast.ExprStringLit)) case ast.ExprKindBoolLit: return comp.compileBoolLitExpr(expr.Value.(ast.ExprBoolLit)) case ast.ExprKindNullLit: return comp.compileNullLitExpr(expr.Value.(ast.ExprNullLit)) case ast.ExprKindThis: panic("not implemented") default: panic("unknown expression kind") } } func (comp *Compiler) compileBinaryExpr(expr ast.ExprBinary) error { if err := comp.compileExpr(expr.Right); err != nil { return err } if err := comp.compileExpr(expr.Left); err != nil { return err } switch expr.Op { case ast.BinOpPlus: comp.builder.AppendOp(code.OpAdd) case ast.BinOpMinus: comp.builder.AppendOp(code.OpSub) case ast.BinOpStar: // comp.builder.AppendOp(code.OpMul) panic("not implemented") case ast.BinOpSlash: // comp.builder.AppendOp(code.OpDiv) panic("not implemented") case ast.BinOpPercent: // comp.builder.AppendOp(code.OpMod) panic("not implemented") case ast.BinOpAssign: panic("not implemented") case ast.BinOpEq: // comp.builder.AppendOp(code.OpEq) panic("not implemented") case ast.BinOpNeq: // comp.builder.AppendOp(code.OpNeq) panic("not implemented") case ast.BinOpLt: // comp.builder.AppendOp(code.OpLt) panic("not implemented") case ast.BinOpLte: comp.builder.AppendOp(code.OpLte) case ast.BinOpGt: // comp.builder.AppendOp(code.OpGt) panic("not implemented") case ast.BinOpGte: // comp.builder.AppendOp(code.OpGte) panic("not implemented") default: panic("unknown binary operator") } return nil } func (comp *Compiler) compileUnaryExpr(expr ast.ExprUnary) error { if err := comp.compileExpr(expr.Value); err != nil { return err } switch expr.Op { case ast.UnOpBang: panic("not implemented") case ast.UnOpMinus: panic("not implemented") default: panic("unknown unary operator") } return nil } func (comp *Compiler) compileCallExpr(expr ast.ExprCall) error { for i := len(expr.Args) - 1; i >= 0; i-- { if err := comp.compileExpr(expr.Args[i]); err != nil { return err } } if err := comp.compileExpr(expr.Callee); err != nil { return err } comp.builder.AppendOp(code.OpCall) comp.builder.AppendInt(int64(len(expr.Args))) return nil } func (comp *Compiler) compileSubscriptionExpr(expr ast.ExprSubscription) error { if err := comp.compileExpr(expr.Key); err != nil { return err } if err := comp.compileExpr(expr.Obj); err != nil { return err } comp.builder.AppendOp(code.OpIndex) return nil } func (comp *Compiler) compileGroupExpr(expr ast.ExprGroup) error { return comp.compileExpr(expr.Value) } func (comp *Compiler) compileIntLitExpr(expr ast.ExprIntLit) error { comp.builder.AppendOp(code.OpPushInt) comp.builder.AppendInt(int64(expr.Value)) return nil } func (comp *Compiler) compileFloatLitExpr(expr ast.ExprFloatLit) error { comp.builder.AppendOp(code.OpPushFloat) comp.builder.AppendFloat(expr.Value) return nil } func (comp *Compiler) compileStringLitExpr(expr ast.ExprStringLit) error { comp.builder.AppendOp(code.OpPushString) comp.builder.AppendString(expr.Value) return nil } func (comp *Compiler) compileBoolLitExpr(expr ast.ExprBoolLit) error { if expr.Value { comp.builder.AppendOp(code.OpPushTrue) } else { comp.builder.AppendOp(code.OpPushFalse) } return nil } func (comp *Compiler) compileNullLitExpr(expr ast.ExprNullLit) error { comp.builder.AppendOp(code.OpPushNull) return nil }