From 621f624f50a7bef16eeed02113b470e79e790cd9 Mon Sep 17 00:00:00 2001 From: Mel Date: Mon, 20 Jun 2022 00:37:01 +0200 Subject: Compile rudimetary variables --- pkg/lang/compiler/compiler.go | 85 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 12 deletions(-) (limited to 'pkg/lang/compiler/compiler.go') diff --git a/pkg/lang/compiler/compiler.go b/pkg/lang/compiler/compiler.go index e299fdc..d2b332d 100644 --- a/pkg/lang/compiler/compiler.go +++ b/pkg/lang/compiler/compiler.go @@ -1,6 +1,7 @@ package compiler import ( + "fmt" "jinx/pkg/lang/ast" "jinx/pkg/lang/vm/code" ) @@ -8,33 +9,57 @@ import ( type Compiler struct { ast ast.Program builder code.Builder + + scopes ScopeChain } func New(ast ast.Program) *Compiler { return &Compiler{ ast: ast, builder: code.NewBuilder(), + + scopes: NewScopeChain(), } } func (comp *Compiler) Compile() (code.Code, error) { for _, stmt := range comp.ast.Stmts { - if stmt.Kind == ast.StmtKindEmpty { - continue + if err := comp.compileStmt(stmt); err != nil { + return code.Code{}, err } + } - if stmt.Kind != ast.StmtKindExpr { - panic("statements other than expressions and empties not implemented") - } + return comp.builder.Build(), nil +} +func (comp *Compiler) compileStmt(stmt ast.Stmt) error { + var err error + switch stmt.Kind { + case ast.StmtKindEmpty: + // Do nothing. + case ast.StmtKindVarDecl: + decl := stmt.Value.(ast.StmtVarDecl) + err = comp.compileVarDeclStmt(decl) + case ast.StmtKindExpr: expr := stmt.Value.(ast.StmtExpr).Value + err = comp.compileExpr(expr) + default: + panic("statements other than expressions, variable declarations, var and empties not implemented") + } - if err := comp.compileExpr(expr); err != nil { - return code.Code{}, err - } + return err +} + +func (comp *Compiler) compileVarDeclStmt(decl ast.StmtVarDecl) error { + if !comp.scopes.Declare(decl.Name.Value) { + return fmt.Errorf("variable %s already declared", decl.Name.Value) } - return comp.builder.Build(), nil + if err := comp.compileExpr(decl.Value); err != nil { + return err + } + + return nil } func (comp *Compiler) compileExpr(expr ast.Expr) error { @@ -55,7 +80,7 @@ func (comp *Compiler) compileExpr(expr ast.Expr) error { case ast.ExprKindArrayLit: panic("not implemented") case ast.ExprKindIdent: - panic("not implemented") + return comp.compileIdentExpr(expr.Value.(ast.ExprIdent)) case ast.ExprKindIntLit: return comp.compileIntLitExpr(expr.Value.(ast.ExprIntLit)) case ast.ExprKindFloatLit: @@ -74,6 +99,10 @@ func (comp *Compiler) compileExpr(expr ast.Expr) error { } func (comp *Compiler) compileBinaryExpr(expr ast.ExprBinary) error { + if expr.Op == ast.BinOpAssign { + return comp.compileAssignExpr(expr) + } + if err := comp.compileExpr(expr.Right); err != nil { return err } @@ -97,8 +126,6 @@ func (comp *Compiler) compileBinaryExpr(expr ast.ExprBinary) error { // 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") @@ -123,6 +150,27 @@ func (comp *Compiler) compileBinaryExpr(expr ast.ExprBinary) error { return nil } +func (comp *Compiler) compileAssignExpr(expr ast.ExprBinary) error { + if expr.Left.Kind != ast.ExprKindIdent { + return fmt.Errorf("lvalues other than identifiers not implemented") + } + + name := expr.Left.Value.(ast.ExprIdent).Value.Value + symbol, ok := comp.scopes.Lookup(name) + if !ok { + return fmt.Errorf("variable %s not declared", name) + } + + if err := comp.compileExpr(expr.Right); err != nil { + return err + } + + comp.builder.AppendOp(code.OpSetLocal) + comp.builder.AppendInt(int64(symbol.localIndex)) + + return nil +} + func (comp *Compiler) compileUnaryExpr(expr ast.ExprUnary) error { if err := comp.compileExpr(expr.Value); err != nil { return err @@ -174,6 +222,19 @@ func (comp *Compiler) compileGroupExpr(expr ast.ExprGroup) error { return comp.compileExpr(expr.Value) } +func (comp *Compiler) compileIdentExpr(expr ast.ExprIdent) error { + symbol, ok := comp.scopes.Lookup(expr.Value.Value) + if !ok { + return fmt.Errorf("undefined symbol %s", expr.Value.Value) + } + + // TODO: Add boundries to check how the symbol should be fetched. (local, env, global, etc.) + comp.builder.AppendOp(code.OpGetLocal) + comp.builder.AppendInt(int64(symbol.localIndex)) + + return nil +} + func (comp *Compiler) compileIntLitExpr(expr ast.ExprIntLit) error { comp.builder.AppendOp(code.OpPushInt) comp.builder.AppendInt(int64(expr.Value)) -- cgit 1.4.1