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:
@@ -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() {
|
||||
|
@@ -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)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/vm"
|
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/runtime"
|
8
pkg/compiler/internal/core/constants.go
Normal file
8
pkg/compiler/internal/core/constants.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package core
|
||||
|
||||
const (
|
||||
JumpPlaceholder = -1
|
||||
UndefinedVariable = -1
|
||||
IgnorePseudoVariable = "_"
|
||||
PseudoVariable = "CURRENT"
|
||||
)
|
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/vm"
|
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package core
|
||||
|
||||
import (
|
||||
"github.com/MontFerret/ferret/pkg/vm"
|
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package core
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
@@ -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
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
@@ -1,4 +1,4 @@
|
||||
package internal
|
||||
package core
|
||||
|
||||
import (
|
||||
"fmt"
|
@@ -1,4 +1,4 @@
|
||||
package internal_test
|
||||
package core_test
|
||||
|
||||
import "testing"
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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))
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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()))
|
||||
}
|
||||
|
@@ -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),
|
||||
}))
|
||||
}
|
||||
|
Reference in New Issue
Block a user