1
0
mirror of https://github.com/MontFerret/ferret.git synced 2025-08-13 19:52:52 +02:00

Refactor compiler structure; move internal packages to core and update references

This commit is contained in:
Tim Voronov
2025-06-11 10:00:57 -04:00
parent cf87b63720
commit 09f47e66fc
21 changed files with 141 additions and 127 deletions

View File

@@ -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() {

View File

@@ -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)

View File

@@ -1,4 +1,4 @@
package internal
package core
import (
"github.com/MontFerret/ferret/pkg/vm"

View File

@@ -1,4 +1,4 @@
package internal
package core
import (
"github.com/MontFerret/ferret/pkg/runtime"

View File

@@ -0,0 +1,8 @@
package core
const (
JumpPlaceholder = -1
UndefinedVariable = -1
IgnorePseudoVariable = "_"
PseudoVariable = "CURRENT"
)

View File

@@ -1,4 +1,4 @@
package internal
package core
import (
"github.com/MontFerret/ferret/pkg/vm"

View File

@@ -1,4 +1,4 @@
package internal
package core
import (
"github.com/MontFerret/ferret/pkg/vm"

View File

@@ -1,4 +1,4 @@
package internal
package core
import "github.com/pkg/errors"

View File

@@ -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
}

View File

@@ -1,4 +1,4 @@
package internal
package core
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package internal
package core
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package internal
package core
import (
"fmt"

View File

@@ -1,4 +1,4 @@
package internal_test
package core_test
import "testing"

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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))

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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
}

View File

@@ -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()))
}

View File

@@ -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),
}))
}