From 09f47e66fc789bc90bcef79a508b6d2964cce22a Mon Sep 17 00:00:00 2001 From: Tim Voronov Date: Wed, 11 Jun 2025 10:00:57 -0400 Subject: [PATCH] Refactor compiler structure; move internal packages to core and update references --- pkg/compiler/compiler.go | 3 +- pkg/compiler/internal/context.go | 22 ++++---- .../internal/{ => core}/catch_stack.go | 2 +- .../internal/{ => core}/constant_pool.go | 2 +- pkg/compiler/internal/core/constants.go | 8 +++ pkg/compiler/internal/{ => core}/emitter.go | 2 +- .../internal/{ => core}/emitter_helpers.go | 2 +- pkg/compiler/internal/{ => core}/errors.go | 2 +- pkg/compiler/internal/{ => core}/loop.go | 8 ++- .../internal/{ => core}/loop_table.go | 2 +- .../internal/{ => core}/register_allocator.go | 2 +- .../internal/{ => core}/symbol_table.go | 2 +- .../internal/{ => core}/symbol_table_test.go | 2 +- pkg/compiler/internal/expr_compiler.go | 55 ++++++++++--------- pkg/compiler/internal/helpers.go | 3 +- pkg/compiler/internal/lit_compiler.go | 15 ++--- pkg/compiler/internal/loop_compiler.go | 55 ++++++++++--------- pkg/compiler/internal/stmt_compiler.go | 9 ++- pkg/compiler/internal/visitor.go | 26 +++------ pkg/compiler/internal/wait_compiler.go | 15 ++--- test/integration/vm/vm_range_test.go | 31 ++++++----- 21 files changed, 141 insertions(+), 127 deletions(-) rename pkg/compiler/internal/{ => core}/catch_stack.go (97%) rename pkg/compiler/internal/{ => core}/constant_pool.go (98%) create mode 100644 pkg/compiler/internal/core/constants.go rename pkg/compiler/internal/{ => core}/emitter.go (99%) rename pkg/compiler/internal/{ => core}/emitter_helpers.go (99%) rename pkg/compiler/internal/{ => core}/errors.go (97%) rename pkg/compiler/internal/{ => core}/loop.go (92%) rename pkg/compiler/internal/{ => core}/loop_table.go (98%) rename pkg/compiler/internal/{ => core}/register_allocator.go (99%) rename pkg/compiler/internal/{ => core}/symbol_table.go (99%) rename pkg/compiler/internal/{ => core}/symbol_table_test.go (95%) diff --git a/pkg/compiler/compiler.go b/pkg/compiler/compiler.go index 3a07e4d3..42ac129f 100644 --- a/pkg/compiler/compiler.go +++ b/pkg/compiler/compiler.go @@ -2,6 +2,7 @@ package compiler import ( "errors" + "github.com/MontFerret/ferret/pkg/compiler/internal/core" goruntime "runtime" "github.com/MontFerret/ferret/pkg/compiler/internal" @@ -37,7 +38,7 @@ func New(setters ...Option) *Compiler { func (c *Compiler) Compile(query string) (program *vm.Program, err error) { if query == "" { - return nil, internal.ErrEmptyQuery + return nil, core.ErrEmptyQuery } defer func() { diff --git a/pkg/compiler/internal/context.go b/pkg/compiler/internal/context.go index 6017b5c0..59e12373 100644 --- a/pkg/compiler/internal/context.go +++ b/pkg/compiler/internal/context.go @@ -1,12 +1,14 @@ package internal +import "github.com/MontFerret/ferret/pkg/compiler/internal/core" + // FuncContext encapsulates the context and state required for compiling and managing functions during code processing. type FuncContext struct { - Emitter *Emitter - Registers *RegisterAllocator - Symbols *SymbolTable - Loops *LoopTable - CatchTable *CatchStack + Emitter *core.Emitter + Registers *core.RegisterAllocator + Symbols *core.SymbolTable + Loops *core.LoopTable + CatchTable *core.CatchStack ExprCompiler *ExprCompiler LiteralCompiler *LiteralCompiler @@ -19,14 +21,14 @@ type FuncContext struct { // NewFuncContext initializes and returns a new instance of FuncContext, setting up all required components for compilation. func NewFuncContext() *FuncContext { ctx := &FuncContext{ - Emitter: NewEmitter(), - Registers: NewRegisterAllocator(), + Emitter: core.NewEmitter(), + Registers: core.NewRegisterAllocator(), Symbols: nil, // set later Loops: nil, // set later - CatchTable: NewCatchStack(), + CatchTable: core.NewCatchStack(), } - ctx.Symbols = NewSymbolTable(ctx.Registers) - ctx.Loops = NewLoopTable(ctx.Registers) + ctx.Symbols = core.NewSymbolTable(ctx.Registers) + ctx.Loops = core.NewLoopTable(ctx.Registers) ctx.ExprCompiler = NewExprCompiler(ctx) ctx.LiteralCompiler = NewLiteralCompiler(ctx) diff --git a/pkg/compiler/internal/catch_stack.go b/pkg/compiler/internal/core/catch_stack.go similarity index 97% rename from pkg/compiler/internal/catch_stack.go rename to pkg/compiler/internal/core/catch_stack.go index b7bc2200..366e292a 100644 --- a/pkg/compiler/internal/catch_stack.go +++ b/pkg/compiler/internal/core/catch_stack.go @@ -1,4 +1,4 @@ -package internal +package core import ( "github.com/MontFerret/ferret/pkg/vm" diff --git a/pkg/compiler/internal/constant_pool.go b/pkg/compiler/internal/core/constant_pool.go similarity index 98% rename from pkg/compiler/internal/constant_pool.go rename to pkg/compiler/internal/core/constant_pool.go index 59f82b7c..bfac9544 100644 --- a/pkg/compiler/internal/constant_pool.go +++ b/pkg/compiler/internal/core/constant_pool.go @@ -1,4 +1,4 @@ -package internal +package core import ( "github.com/MontFerret/ferret/pkg/runtime" diff --git a/pkg/compiler/internal/core/constants.go b/pkg/compiler/internal/core/constants.go new file mode 100644 index 00000000..874257ff --- /dev/null +++ b/pkg/compiler/internal/core/constants.go @@ -0,0 +1,8 @@ +package core + +const ( + JumpPlaceholder = -1 + UndefinedVariable = -1 + IgnorePseudoVariable = "_" + PseudoVariable = "CURRENT" +) diff --git a/pkg/compiler/internal/emitter.go b/pkg/compiler/internal/core/emitter.go similarity index 99% rename from pkg/compiler/internal/emitter.go rename to pkg/compiler/internal/core/emitter.go index d4bad4aa..d51a8ece 100644 --- a/pkg/compiler/internal/emitter.go +++ b/pkg/compiler/internal/core/emitter.go @@ -1,4 +1,4 @@ -package internal +package core import ( "github.com/MontFerret/ferret/pkg/vm" diff --git a/pkg/compiler/internal/emitter_helpers.go b/pkg/compiler/internal/core/emitter_helpers.go similarity index 99% rename from pkg/compiler/internal/emitter_helpers.go rename to pkg/compiler/internal/core/emitter_helpers.go index e49da375..9ebba673 100644 --- a/pkg/compiler/internal/emitter_helpers.go +++ b/pkg/compiler/internal/core/emitter_helpers.go @@ -1,4 +1,4 @@ -package internal +package core import ( "github.com/MontFerret/ferret/pkg/vm" diff --git a/pkg/compiler/internal/errors.go b/pkg/compiler/internal/core/errors.go similarity index 97% rename from pkg/compiler/internal/errors.go rename to pkg/compiler/internal/core/errors.go index 9f033194..32f8969f 100644 --- a/pkg/compiler/internal/errors.go +++ b/pkg/compiler/internal/core/errors.go @@ -1,4 +1,4 @@ -package internal +package core import "github.com/pkg/errors" diff --git a/pkg/compiler/internal/loop.go b/pkg/compiler/internal/core/loop.go similarity index 92% rename from pkg/compiler/internal/loop.go rename to pkg/compiler/internal/core/loop.go index 374a707b..3247f9d7 100644 --- a/pkg/compiler/internal/loop.go +++ b/pkg/compiler/internal/core/loop.go @@ -1,6 +1,8 @@ -package internal +package core -import "github.com/MontFerret/ferret/pkg/vm" +import ( + "github.com/MontFerret/ferret/pkg/vm" +) type LoopType int @@ -76,5 +78,5 @@ func (l *Loop) EmitFinalization(emitter *Emitter) { } func (l *Loop) canBindVar(name string) bool { - return name != "" && name != ignorePseudoVariable + return name != "" && name != IgnorePseudoVariable } diff --git a/pkg/compiler/internal/loop_table.go b/pkg/compiler/internal/core/loop_table.go similarity index 98% rename from pkg/compiler/internal/loop_table.go rename to pkg/compiler/internal/core/loop_table.go index 462c7399..47df8352 100644 --- a/pkg/compiler/internal/loop_table.go +++ b/pkg/compiler/internal/core/loop_table.go @@ -1,4 +1,4 @@ -package internal +package core import ( "fmt" diff --git a/pkg/compiler/internal/register_allocator.go b/pkg/compiler/internal/core/register_allocator.go similarity index 99% rename from pkg/compiler/internal/register_allocator.go rename to pkg/compiler/internal/core/register_allocator.go index baf2a629..48a51f50 100644 --- a/pkg/compiler/internal/register_allocator.go +++ b/pkg/compiler/internal/core/register_allocator.go @@ -1,4 +1,4 @@ -package internal +package core import ( "fmt" diff --git a/pkg/compiler/internal/symbol_table.go b/pkg/compiler/internal/core/symbol_table.go similarity index 99% rename from pkg/compiler/internal/symbol_table.go rename to pkg/compiler/internal/core/symbol_table.go index 3fc0d48a..31416979 100644 --- a/pkg/compiler/internal/symbol_table.go +++ b/pkg/compiler/internal/core/symbol_table.go @@ -1,4 +1,4 @@ -package internal +package core import ( "fmt" diff --git a/pkg/compiler/internal/symbol_table_test.go b/pkg/compiler/internal/core/symbol_table_test.go similarity index 95% rename from pkg/compiler/internal/symbol_table_test.go rename to pkg/compiler/internal/core/symbol_table_test.go index 2c2c981e..0ca7d35e 100644 --- a/pkg/compiler/internal/symbol_table_test.go +++ b/pkg/compiler/internal/core/symbol_table_test.go @@ -1,4 +1,4 @@ -package internal_test +package core_test import "testing" diff --git a/pkg/compiler/internal/expr_compiler.go b/pkg/compiler/internal/expr_compiler.go index b5f5973d..d828b31b 100644 --- a/pkg/compiler/internal/expr_compiler.go +++ b/pkg/compiler/internal/expr_compiler.go @@ -1,6 +1,7 @@ package internal import ( + "github.com/MontFerret/ferret/pkg/compiler/internal/core" "github.com/MontFerret/ferret/pkg/parser/fql" "github.com/MontFerret/ferret/pkg/runtime" "github.com/MontFerret/ferret/pkg/vm" @@ -44,13 +45,13 @@ func (ec *ExprCompiler) Compile(ctx fql.IExpressionContext) vm.Operand { return ec.compilePredicate(c) } - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } // TODO: Free temporary registers if needed func (ec *ExprCompiler) compileUnary(ctx fql.IUnaryOperatorContext, parent fql.IExpressionContext) vm.Operand { src := ec.Compile(parent.GetRight()) - dst := ec.ctx.Registers.Allocate(Temp) + dst := ec.ctx.Registers.Allocate(core.Temp) var op vm.Opcode @@ -61,7 +62,7 @@ func (ec *ExprCompiler) compileUnary(ctx fql.IUnaryOperatorContext, parent fql.I } else if ctx.Plus() != nil { op = vm.OpFlipPositive } else { - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } // We do not overwrite the source register @@ -72,7 +73,7 @@ func (ec *ExprCompiler) compileUnary(ctx fql.IUnaryOperatorContext, parent fql.I // TODO: Free temporary registers if needed func (ec *ExprCompiler) compileLogicalAnd(ctx fql.IPredicateContext) vm.Operand { - dst := ec.ctx.Registers.Allocate(Temp) + dst := ec.ctx.Registers.Allocate(core.Temp) // Execute left expression left := ec.compilePredicate(ctx.GetLeft()) @@ -81,7 +82,7 @@ func (ec *ExprCompiler) compileLogicalAnd(ctx fql.IPredicateContext) vm.Operand ec.ctx.Emitter.EmitMove(dst, left) // Test if left is false and jump to the end - end := ec.ctx.Emitter.EmitJumpIfFalse(dst, jumpPlaceholder) + end := ec.ctx.Emitter.EmitJumpIfFalse(dst, core.JumpPlaceholder) // If left is true, execute right expression right := ec.compilePredicate(ctx.GetRight()) @@ -96,7 +97,7 @@ func (ec *ExprCompiler) compileLogicalAnd(ctx fql.IPredicateContext) vm.Operand // TODO: Free temporary registers if needed func (ec *ExprCompiler) compileLogicalOr(ctx fql.IPredicateContext) vm.Operand { - dst := ec.ctx.Registers.Allocate(Temp) + dst := ec.ctx.Registers.Allocate(core.Temp) // Execute left expression left := ec.compilePredicate(ctx.GetLeft()) @@ -105,7 +106,7 @@ func (ec *ExprCompiler) compileLogicalOr(ctx fql.IPredicateContext) vm.Operand { ec.ctx.Emitter.EmitMove(dst, left) // Test if left is true and jump to the end - end := ec.ctx.Emitter.EmitJumpIfTrue(dst, jumpPlaceholder) + end := ec.ctx.Emitter.EmitJumpIfTrue(dst, core.JumpPlaceholder) // If left is false, execute right expression right := ec.compilePredicate(ctx.GetRight()) @@ -120,14 +121,14 @@ func (ec *ExprCompiler) compileLogicalOr(ctx fql.IPredicateContext) vm.Operand { // TODO: Free temporary registers if needed func (ec *ExprCompiler) compileTernary(ctx fql.IExpressionContext) vm.Operand { - dst := ec.ctx.Registers.Allocate(Temp) + dst := ec.ctx.Registers.Allocate(core.Temp) // Compile condition and put result in dst condReg := ec.Compile(ctx.GetCondition()) ec.ctx.Emitter.EmitMove(dst, condReg) // Jump to 'false' branch if condition is false - otherwise := ec.ctx.Emitter.EmitJumpIfFalse(dst, jumpPlaceholder) + otherwise := ec.ctx.Emitter.EmitJumpIfFalse(dst, core.JumpPlaceholder) // True branch if onTrue := ctx.GetOnTrue(); onTrue != nil { @@ -137,7 +138,7 @@ func (ec *ExprCompiler) compileTernary(ctx fql.IExpressionContext) vm.Operand { } // Jump over false branch - end := ec.ctx.Emitter.EmitJump(jumpPlaceholder) + end := ec.ctx.Emitter.EmitJump(core.JumpPlaceholder) ec.ctx.Emitter.PatchJumpNext(otherwise) // False branch @@ -174,7 +175,7 @@ func (ec *ExprCompiler) compilePredicate(ctx fql.IPredicateContext) vm.Operand { } var opcode vm.Opcode - dest := ec.ctx.Registers.Allocate(Temp) + dest := ec.ctx.Registers.Allocate(core.Temp) left := ec.compilePredicate(ctx.Predicate(0)) right := ec.compilePredicate(ctx.Predicate(1)) @@ -193,7 +194,7 @@ func (ec *ExprCompiler) compilePredicate(ctx fql.IPredicateContext) vm.Operand { case "<=": opcode = vm.OpLte default: - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } } else if op := ctx.ArrayOperator(); op != nil { // TODO: Implement me @@ -233,7 +234,7 @@ func (ec *ExprCompiler) compileAtom(ctx fql.IExpressionAtomContext) vm.Operand { case "%": opcode = vm.OpMod default: - panic(runtime.Error(ErrUnexpectedToken, op.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, op.GetText())) } } else if op := ctx.AdditiveOperator(); op != nil { isSet = true @@ -244,7 +245,7 @@ func (ec *ExprCompiler) compileAtom(ctx fql.IExpressionAtomContext) vm.Operand { case "-": opcode = vm.OpSub default: - panic(runtime.Error(ErrUnexpectedToken, op.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, op.GetText())) } } else if op := ctx.RegexpOperator(); op != nil { @@ -256,14 +257,14 @@ func (ec *ExprCompiler) compileAtom(ctx fql.IExpressionAtomContext) vm.Operand { case "!~": opcode = vm.OpRegexpNegative default: - panic(runtime.Error(ErrUnexpectedToken, op.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, op.GetText())) } } if isSet { regLeft := ec.compileAtom(ctx.ExpressionAtom(0)) regRight := ec.compileAtom(ctx.ExpressionAtom(1)) - dst := ec.ctx.Registers.Allocate(Temp) + dst := ec.ctx.Registers.Allocate(core.Temp) if opcode == vm.OpRegexpPositive || opcode == vm.OpRegexpNegative { if regRight.IsConstant() { @@ -299,7 +300,7 @@ func (ec *ExprCompiler) compileAtom(ctx fql.IExpressionAtomContext) vm.Operand { return ec.Compile(c) } - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } func (ec *ExprCompiler) CompileMemberExpression(ctx fql.IMemberExpressionContext) vm.Operand { @@ -334,7 +335,7 @@ func (ec *ExprCompiler) CompileMemberExpression(ctx fql.IMemberExpressionContext src2 = ec.ctx.LiteralCompiler.CompileComputedPropertyName(c) } - dst = ec.ctx.Registers.Allocate(Temp) + dst = ec.ctx.Registers.Allocate(core.Temp) // TODO: Replace with EmitLoadKey if p.ErrorOperator() != nil { @@ -354,14 +355,14 @@ func (ec *ExprCompiler) CompileVariable(ctx fql.IVariableContext) vm.Operand { op, _, found := ec.ctx.Symbols.Resolve(ctx.GetText()) if !found { - panic(runtime.Error(ErrVariableNotFound, ctx.GetText())) + panic(runtime.Error(core.ErrVariableNotFound, ctx.GetText())) } if op.IsRegister() { return op } - reg := ec.ctx.Registers.Allocate(Temp) + reg := ec.ctx.Registers.Allocate(core.Temp) ec.ctx.Emitter.EmitLoadGlobal(reg, op) return reg @@ -388,7 +389,7 @@ func (ec *ExprCompiler) CompileFunctionCall(ctx fql.IFunctionCallContext, protec switch name { case runtimeLength: - dst := ec.ctx.Registers.Allocate(Temp) + dst := ec.ctx.Registers.Allocate(core.Temp) if seq == nil || len(seq) != 1 { panic(runtime.Error(runtime.ErrInvalidArgument, runtimeLength+": expected 1 argument")) @@ -398,7 +399,7 @@ func (ec *ExprCompiler) CompileFunctionCall(ctx fql.IFunctionCallContext, protec return dst case runtimeTypename: - dst := ec.ctx.Registers.Allocate(Temp) + dst := ec.ctx.Registers.Allocate(core.Temp) if seq == nil || len(seq) != 1 { panic(runtime.Error(runtime.ErrInvalidArgument, runtimeTypename+": expected 1 argument")) @@ -416,7 +417,7 @@ func (ec *ExprCompiler) CompileFunctionCall(ctx fql.IFunctionCallContext, protec return seq[0] default: - dest := ec.ctx.Registers.Allocate(Temp) + dest := ec.ctx.Registers.Allocate(core.Temp) ec.ctx.Emitter.EmitLoadConst(dest, ec.ctx.Symbols.AddConstant(name)) if !protected { @@ -429,8 +430,8 @@ func (ec *ExprCompiler) CompileFunctionCall(ctx fql.IFunctionCallContext, protec } } -func (ec *ExprCompiler) CompileArgumentList(ctx fql.IArgumentListContext) RegisterSequence { - var seq RegisterSequence +func (ec *ExprCompiler) CompileArgumentList(ctx fql.IArgumentListContext) core.RegisterSequence { + var seq core.RegisterSequence // Get all array element expressions exps := ctx.AllExpression() size := len(exps) @@ -458,7 +459,7 @@ func (ec *ExprCompiler) CompileArgumentList(ctx fql.IArgumentListContext) Regist } func (ec *ExprCompiler) CompileRangeOperator(ctx fql.IRangeOperatorContext) vm.Operand { - dst := ec.ctx.Registers.Allocate(Temp) + dst := ec.ctx.Registers.Allocate(core.Temp) start := ec.compileRangeOperand(ctx.GetLeft()) end := ec.compileRangeOperand(ctx.GetRight()) @@ -480,7 +481,7 @@ func (ec *ExprCompiler) compileRangeOperand(ctx fql.IRangeOperandContext) vm.Ope return ec.ctx.LiteralCompiler.CompileIntegerLiteral(c) } - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } func (ec *ExprCompiler) functionName(ctx fql.IFunctionCallContext) runtime.String { diff --git a/pkg/compiler/internal/helpers.go b/pkg/compiler/internal/helpers.go index 227a608e..49bbe10d 100644 --- a/pkg/compiler/internal/helpers.go +++ b/pkg/compiler/internal/helpers.go @@ -1,6 +1,7 @@ package internal import ( + "github.com/MontFerret/ferret/pkg/compiler/internal/core" "github.com/MontFerret/ferret/pkg/vm" "github.com/antlr4-go/antlr/v4" "strings" @@ -11,7 +12,7 @@ import ( ) func loadConstant(ctx *FuncContext, value runtime.Value) vm.Operand { - reg := ctx.Registers.Allocate(Temp) + reg := ctx.Registers.Allocate(core.Temp) ctx.Emitter.EmitLoadConst(reg, ctx.Symbols.AddConstant(value)) return reg } diff --git a/pkg/compiler/internal/lit_compiler.go b/pkg/compiler/internal/lit_compiler.go index 4aed131e..5f63a7c2 100644 --- a/pkg/compiler/internal/lit_compiler.go +++ b/pkg/compiler/internal/lit_compiler.go @@ -1,6 +1,7 @@ package internal import ( + "github.com/MontFerret/ferret/pkg/compiler/internal/core" "github.com/MontFerret/ferret/pkg/parser/fql" "github.com/MontFerret/ferret/pkg/runtime" "github.com/MontFerret/ferret/pkg/vm" @@ -36,7 +37,7 @@ func (lc *LiteralCompiler) Compile(ctx fql.ILiteralContext) vm.Operand { return lc.CompileNoneLiteral(c) } - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } func (lc *LiteralCompiler) CompileStringLiteral(ctx fql.IStringLiteralContext) vm.Operand { @@ -109,7 +110,7 @@ func (lc *LiteralCompiler) CompileFloatLiteral(ctx fql.IFloatLiteralContext) vm. } func (lc *LiteralCompiler) CompileBooleanLiteral(ctx fql.IBooleanLiteralContext) vm.Operand { - reg := lc.ctx.Registers.Allocate(Temp) + reg := lc.ctx.Registers.Allocate(core.Temp) switch strings.ToLower(ctx.GetText()) { case "true": @@ -117,14 +118,14 @@ func (lc *LiteralCompiler) CompileBooleanLiteral(ctx fql.IBooleanLiteralContext) case "false": lc.ctx.Emitter.EmitBoolean(reg, false) default: - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } return reg } func (lc *LiteralCompiler) CompileNoneLiteral(_ fql.INoneLiteralContext) vm.Operand { - reg := lc.ctx.Registers.Allocate(Temp) + reg := lc.ctx.Registers.Allocate(core.Temp) lc.ctx.Emitter.EmitA(vm.OpLoadNone, reg) return reg @@ -132,7 +133,7 @@ func (lc *LiteralCompiler) CompileNoneLiteral(_ fql.INoneLiteralContext) vm.Oper func (lc *LiteralCompiler) CompileArrayLiteral(ctx fql.IArrayLiteralContext) vm.Operand { // Allocate destination register for the array - destReg := lc.ctx.Registers.Allocate(Temp) + destReg := lc.ctx.Registers.Allocate(core.Temp) if list := ctx.ArgumentList(); list != nil { // Get all array element expressions @@ -174,7 +175,7 @@ func (lc *LiteralCompiler) CompileArrayLiteral(ctx fql.IArrayLiteralContext) vm. } func (lc *LiteralCompiler) CompileObjectLiteral(ctx fql.IObjectLiteralContext) vm.Operand { - dst := lc.ctx.Registers.Allocate(Temp) + dst := lc.ctx.Registers.Allocate(core.Temp) assignments := ctx.AllPropertyAssignment() size := len(assignments) @@ -232,7 +233,7 @@ func (lc *LiteralCompiler) CompilePropertyName(ctx fql.IPropertyNameContext) vm. } else if word := ctx.UnsafeReservedWord(); word != nil { name = word.GetText() } else { - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } return loadConstant(lc.ctx, runtime.NewString(name)) diff --git a/pkg/compiler/internal/loop_compiler.go b/pkg/compiler/internal/loop_compiler.go index 8bb0ac2f..5dc11662 100644 --- a/pkg/compiler/internal/loop_compiler.go +++ b/pkg/compiler/internal/loop_compiler.go @@ -1,6 +1,7 @@ package internal import ( + "github.com/MontFerret/ferret/pkg/compiler/internal/core" "github.com/MontFerret/ferret/pkg/parser/fql" "github.com/MontFerret/ferret/pkg/runtime" "github.com/MontFerret/ferret/pkg/vm" @@ -18,23 +19,23 @@ func NewLoopCompiler(ctx *FuncContext) *LoopCompiler { func (lc *LoopCompiler) Compile(ctx fql.IForExpressionContext) vm.Operand { var distinct bool var returnRuleCtx antlr.RuleContext - var loopType LoopType + var loopType core.LoopType returnCtx := ctx.ForExpressionReturn() if c := returnCtx.ReturnExpression(); c != nil { returnRuleCtx = c distinct = c.Distinct() != nil - loopType = NormalLoop + loopType = core.NormalLoop } else if c := returnCtx.ForExpression(); c != nil { returnRuleCtx = c - loopType = PassThroughLoop + loopType = core.PassThroughLoop } - loop := lc.ctx.Loops.NewLoop(loopType, ForLoop, distinct) + loop := lc.ctx.Loops.NewLoop(loopType, core.ForLoop, distinct) lc.ctx.Symbols.EnterScope() lc.ctx.Loops.Push(loop) - if loop.Kind == ForLoop { + if loop.Kind == core.ForLoop { loop.Src = lc.CompileForExpressionSource(ctx.ForExpressionSource()) if val := ctx.GetValueVariable(); val != nil { @@ -63,7 +64,7 @@ func (lc *LoopCompiler) Compile(ctx fql.IForExpressionContext) vm.Operand { loop = lc.ctx.Loops.Current() // RETURN - if loop.Type != PassThroughLoop { + if loop.Type != core.PassThroughLoop { c := returnRuleCtx.(*fql.ReturnExpressionContext) expReg := lc.ctx.ExprCompiler.Compile(c.Expression()) @@ -111,7 +112,7 @@ func (lc *LoopCompiler) CompileForExpressionSource(ctx fql.IForExpressionSourceC return lc.ctx.LiteralCompiler.CompileObjectLiteral(c) } - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } func (lc *LoopCompiler) CompileForExpressionStatement(ctx fql.IForExpressionStatementContext) { @@ -168,17 +169,17 @@ func (lc *LoopCompiler) CompileLimitClauseValue(ctx fql.ILimitClauseValueContext return lc.ctx.ExprCompiler.CompileFunctionCallExpression(c) } - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } func (lc *LoopCompiler) CompileLimit(src vm.Operand) { - state := lc.ctx.Registers.Allocate(State) + state := lc.ctx.Registers.Allocate(core.State) lc.ctx.Emitter.EmitABx(vm.OpIterLimit, state, src, lc.ctx.Loops.Current().Jump) } func (lc *LoopCompiler) CompileOffset(src vm.Operand) { - state := lc.ctx.Registers.Allocate(State) + state := lc.ctx.Registers.Allocate(core.State) lc.ctx.Emitter.EmitABx(vm.OpIterSkip, state, src, lc.ctx.Loops.Current().Jump) } @@ -194,7 +195,7 @@ func (lc *LoopCompiler) CompileSortClause(ctx fql.ISortClauseContext) { // And wrap each loop element by a KeyValuePair // Where a key is either a single value or a list of values // These KeyValuePairs are then added to the dataset - kvKeyReg := lc.ctx.Registers.Allocate(Temp) + kvKeyReg := lc.ctx.Registers.Allocate(core.Temp) clauses := ctx.AllSortClauseExpression() var directions []runtime.SortDirection isSortMany := len(clauses) > 1 @@ -214,7 +215,7 @@ func (lc *LoopCompiler) CompileSortClause(ctx fql.ISortClauseContext) { // TODO: Free Registers } - arrReg := lc.ctx.Registers.Allocate(Temp) + arrReg := lc.ctx.Registers.Allocate(core.Temp) lc.ctx.Emitter.EmitAs(vm.OpList, arrReg, keyRegs) lc.ctx.Emitter.EmitAB(vm.OpMove, kvKeyReg, arrReg) // TODO: Free Registers } else { @@ -229,7 +230,7 @@ func (lc *LoopCompiler) CompileSortClause(ctx fql.ISortClauseContext) { kvValReg = loop.Value } else { // If so, we need to load it from the iterator - kvValReg = lc.ctx.Registers.Allocate(Temp) + kvValReg = lc.ctx.Registers.Allocate(core.Temp) loop.EmitValue(kvKeyReg, lc.ctx.Emitter) } @@ -258,18 +259,18 @@ func (lc *LoopCompiler) CompileCollectClause(ctx fql.ICollectClauseContext) { } // emitIterValue emits an instruction to get the value from the iterator -func (lc *LoopCompiler) emitLoopBegin(loop *Loop) { +func (lc *LoopCompiler) emitLoopBegin(loop *core.Loop) { if loop.Allocate { lc.ctx.Emitter.EmitAb(vm.OpDataSet, loop.Result, loop.Distinct) loop.ResultPos = lc.ctx.Emitter.Size() - 1 } - loop.Iterator = lc.ctx.Registers.Allocate(State) + loop.Iterator = lc.ctx.Registers.Allocate(core.State) - if loop.Kind == ForLoop { + if loop.Kind == core.ForLoop { lc.ctx.Emitter.EmitAB(vm.OpIter, loop.Iterator, loop.Src) - // jumpPlaceholder is a placeholder for the exit jump position - loop.Jump = lc.ctx.Emitter.EmitJumpc(vm.OpIterNext, jumpPlaceholder, loop.Iterator) + // core.JumpPlaceholder is a placeholder for the exit jump position + loop.Jump = lc.ctx.Emitter.EmitJumpc(vm.OpIterNext, core.JumpPlaceholder, loop.Iterator) if loop.Value != vm.NoopOperand { lc.ctx.Emitter.EmitAB(vm.OpIterValue, loop.Value, loop.Iterator) @@ -285,7 +286,7 @@ func (lc *LoopCompiler) emitLoopBegin(loop *Loop) { } // emitPatchLoop replaces the source of the loop with a modified dataset -func (lc *LoopCompiler) emitPatchLoop(loop *Loop) { +func (lc *LoopCompiler) emitPatchLoop(loop *core.Loop) { // Replace source with sorted array lc.ctx.Emitter.EmitAB(vm.OpMove, loop.Src, loop.Result) @@ -296,24 +297,24 @@ func (lc *LoopCompiler) emitPatchLoop(loop *Loop) { lc.emitLoopBegin(loop) } -func (lc *LoopCompiler) emitLoopEnd(loop *Loop) vm.Operand { +func (lc *LoopCompiler) emitLoopEnd(loop *core.Loop) vm.Operand { lc.ctx.Emitter.EmitJump(loop.Jump - loop.JumpOffset) // TODO: Do not allocate for pass-through Loops - dst := lc.ctx.Registers.Allocate(Temp) + dst := lc.ctx.Registers.Allocate(core.Temp) if loop.Allocate { // TODO: Reuse the dsReg register lc.ctx.Emitter.EmitA(vm.OpClose, loop.Iterator) lc.ctx.Emitter.EmitAB(vm.OpMove, dst, loop.Result) - if loop.Kind == ForLoop { + if loop.Kind == core.ForLoop { lc.ctx.Emitter.PatchJump(loop.Jump) } else { lc.ctx.Emitter.PatchJumpAB(loop.Jump) } } else { - if loop.Kind == ForLoop { + if loop.Kind == core.ForLoop { lc.ctx.Emitter.PatchJumpNext(loop.Jump) } else { lc.ctx.Emitter.PatchJumpNextAB(loop.Jump) @@ -323,14 +324,14 @@ func (lc *LoopCompiler) emitLoopEnd(loop *Loop) vm.Operand { return dst } -func (lc *LoopCompiler) loopKind(ctx *fql.ForExpressionContext) LoopKind { +func (lc *LoopCompiler) loopKind(ctx *fql.ForExpressionContext) core.LoopKind { if ctx.While() == nil { - return ForLoop + return core.ForLoop } if ctx.Do() == nil { - return WhileLoop + return core.WhileLoop } - return DoWhileLoop + return core.DoWhileLoop } diff --git a/pkg/compiler/internal/stmt_compiler.go b/pkg/compiler/internal/stmt_compiler.go index 602bb644..819c3ca6 100644 --- a/pkg/compiler/internal/stmt_compiler.go +++ b/pkg/compiler/internal/stmt_compiler.go @@ -1,6 +1,7 @@ package internal import ( + "github.com/MontFerret/ferret/pkg/compiler/internal/core" "github.com/MontFerret/ferret/pkg/parser/fql" "github.com/MontFerret/ferret/pkg/vm" ) @@ -19,6 +20,8 @@ func (sc *StmtCompiler) Compile(ctx fql.IBodyContext) { for _, statement := range ctx.AllBodyStatement() { sc.CompileBodyStatement(statement) } + + sc.CompileBodyExpression(ctx.BodyExpression()) } func (sc *StmtCompiler) CompileBodyStatement(ctx fql.IBodyStatementContext) { @@ -54,7 +57,7 @@ func (sc *StmtCompiler) CompileBodyExpression(ctx fql.IBodyExpressionContext) { } func (sc *StmtCompiler) CompileVariableDeclaration(ctx fql.IVariableDeclarationContext) vm.Operand { - name := ignorePseudoVariable + name := core.IgnorePseudoVariable if id := ctx.Identifier(); id != nil { name = id.GetText() @@ -64,12 +67,12 @@ func (sc *StmtCompiler) CompileVariableDeclaration(ctx fql.IVariableDeclarationC src := sc.ctx.ExprCompiler.Compile(ctx.Expression()) - if name != ignorePseudoVariable { + if name != core.IgnorePseudoVariable { var dest vm.Operand if src.IsConstant() { dest = sc.ctx.Symbols.DeclareGlobal(name) - tmp := sc.ctx.Registers.Allocate(Temp) + tmp := sc.ctx.Registers.Allocate(core.Temp) sc.ctx.Emitter.EmitAB(vm.OpLoadConst, tmp, src) sc.ctx.Emitter.EmitAB(vm.OpStoreGlobal, dest, tmp) } else if sc.ctx.Symbols.Scope() == 0 { diff --git a/pkg/compiler/internal/visitor.go b/pkg/compiler/internal/visitor.go index 054f13cb..cd277a4a 100644 --- a/pkg/compiler/internal/visitor.go +++ b/pkg/compiler/internal/visitor.go @@ -1,6 +1,7 @@ package internal import ( + "github.com/MontFerret/ferret/pkg/compiler/internal/core" "github.com/MontFerret/ferret/pkg/parser/fql" ) @@ -10,20 +11,13 @@ type Visitor struct { Err error Src string - Emitter *Emitter - Registers *RegisterAllocator - Symbols *SymbolTable - Loops *LoopTable - CatchTable *CatchStack + Emitter *core.Emitter + Registers *core.RegisterAllocator + Symbols *core.SymbolTable + Loops *core.LoopTable + CatchTable *core.CatchStack } -const ( - jumpPlaceholder = -1 - undefinedVariable = -1 - ignorePseudoVariable = "_" - pseudoVariable = "CURRENT" -) - func NewVisitor(src string) *Visitor { v := new(Visitor) v.BaseFqlParserVisitor = new(fql.BaseFqlParserVisitor) @@ -44,13 +38,7 @@ func (v *Visitor) VisitProgram(ctx *fql.ProgramContext) interface{} { v.VisitHead(head.(*fql.HeadContext)) } - ctx.Body().Accept(v) - - return nil -} - -func (v *Visitor) VisitBody(ctx *fql.BodyContext) interface{} { - v.ctx.StmtCompiler.Compile(ctx) + v.ctx.StmtCompiler.Compile(ctx.Body()) return nil } diff --git a/pkg/compiler/internal/wait_compiler.go b/pkg/compiler/internal/wait_compiler.go index 49427760..0bfe4265 100644 --- a/pkg/compiler/internal/wait_compiler.go +++ b/pkg/compiler/internal/wait_compiler.go @@ -1,6 +1,7 @@ package internal import ( + "github.com/MontFerret/ferret/pkg/compiler/internal/core" "github.com/MontFerret/ferret/pkg/parser/fql" "github.com/MontFerret/ferret/pkg/runtime" "github.com/MontFerret/ferret/pkg/vm" @@ -34,7 +35,7 @@ func (wc *WaitCompiler) Compile(ctx fql.IWaitForExpressionContext) vm.Operand { timeoutReg = wc.CompileTimeoutClauseContext(timeout) } - streamReg := wc.ctx.Registers.Allocate(Temp) + streamReg := wc.ctx.Registers.Allocate(core.Temp) // We move the source object to the stream register in order to re-use it in OpStream wc.ctx.Emitter.EmitMove(streamReg, srcReg) @@ -44,10 +45,10 @@ func (wc *WaitCompiler) Compile(ctx fql.IWaitForExpressionContext) vm.Operand { var valReg vm.Operand // Now we start iterating over the stream - jumpToNext := wc.ctx.Emitter.EmitJumpc(vm.OpIterNext, jumpPlaceholder, streamReg) + jumpToNext := wc.ctx.Emitter.EmitJumpc(vm.OpIterNext, core.JumpPlaceholder, streamReg) if filter := ctx.FilterClause(); filter != nil { - valReg = wc.ctx.Symbols.DeclareLocal(pseudoVariable) + valReg = wc.ctx.Symbols.DeclareLocal(core.PseudoVariable) wc.ctx.Emitter.EmitAB(vm.OpIterValue, valReg, streamReg) wc.ctx.ExprCompiler.Compile(filter.Expression()) @@ -86,7 +87,7 @@ func (wc *WaitCompiler) CompileWaitForEventName(ctx fql.IWaitForEventNameContext return wc.ctx.ExprCompiler.CompileFunctionCallExpression(c) } - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } func (wc *WaitCompiler) CompileWaitForEventSource(ctx fql.IWaitForEventSourceContext) vm.Operand { @@ -102,7 +103,7 @@ func (wc *WaitCompiler) CompileWaitForEventSource(ctx fql.IWaitForEventSourceCon return wc.ctx.ExprCompiler.CompileFunctionCallExpression(c) } - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } func (wc *WaitCompiler) CompileOptionsClause(ctx fql.IOptionsClauseContext) vm.Operand { @@ -110,7 +111,7 @@ func (wc *WaitCompiler) CompileOptionsClause(ctx fql.IOptionsClauseContext) vm.O return wc.ctx.LiteralCompiler.CompileObjectLiteral(c) } - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } func (wc *WaitCompiler) CompileTimeoutClauseContext(ctx fql.ITimeoutClauseContext) vm.Operand { @@ -134,5 +135,5 @@ func (wc *WaitCompiler) CompileTimeoutClauseContext(ctx fql.ITimeoutClauseContex return wc.ctx.ExprCompiler.CompileFunctionCall(c, false) } - panic(runtime.Error(ErrUnexpectedToken, ctx.GetText())) + panic(runtime.Error(core.ErrUnexpectedToken, ctx.GetText())) } diff --git a/test/integration/vm/vm_range_test.go b/test/integration/vm/vm_range_test.go index 6f545075..eed97cc7 100644 --- a/test/integration/vm/vm_range_test.go +++ b/test/integration/vm/vm_range_test.go @@ -1,30 +1,35 @@ package vm_test import ( + "github.com/MontFerret/ferret/pkg/runtime" + "github.com/MontFerret/ferret/pkg/vm" . "github.com/MontFerret/ferret/test/integration/base" "testing" ) func TestRange(t *testing.T) { RunUseCases(t, []UseCase{ - CaseArray("RETURN 1..10", []any{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}), - CaseArray("RETURN 10..1", []any{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}), - CaseArray( + SkipCaseArray("RETURN 1..10", []any{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, "Should return a range from 1 to 10"), + SkipCaseArray("RETURN 10..1", []any{10, 9, 8, 7, 6, 5, 4, 3, 2, 1}, "Should return a range from 10 to 1"), + SkipCaseArray( ` LET start = 1 LET end = 10 RETURN start..end `, []any{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + "Should be able to use variables in range", ), - //{ - // ` - //LET start = @start - //LET end = @end - //RETURN start..end - //`, - // []any{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, - // ShouldEqualJSON, - //}, - }) + CaseArray(` + LET start = @start + LET end = @end + RETURN start..end + `, + []any{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, + "Should be able to use parameters in range", + ), + }, vm.WithParams(map[string]runtime.Value{ + "start": runtime.NewInt(1), + "end": runtime.NewInt(10), + })) }