Skip to content

Commit

Permalink
Fixed use of local variables
Browse files Browse the repository at this point in the history
  • Loading branch information
ziflex committed Feb 4, 2024
1 parent 5a9fb8d commit 2b3fd4f
Show file tree
Hide file tree
Showing 10 changed files with 202 additions and 90 deletions.
9 changes: 9 additions & 0 deletions pkg/compiler/compiler_for_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,14 @@ func TestFor(t *testing.T) {
[]any{1, 2, 3, 4, 5},
ShouldEqualJSON,
},
{
`FOR i IN 1..5
LET x = i
PRINT(x)
RETURN i
`,
[]any{1, 2, 3, 4, 5},
ShouldEqualJSON,
},
})
}
23 changes: 14 additions & 9 deletions pkg/compiler/compiler_range_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,28 @@ func TestRange(t *testing.T) {
[]any{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
ShouldEqualJSON,
},
{
"RETURN 10..1",
[]any{10, 9, 8, 7, 6, 5, 4, 3, 2, 1},
ShouldEqualJSON,
},
{
`
LET start = 1
LET end = 10
RETURN start..end
`,
LET start = 1
LET end = 10
RETURN start..end
`,
[]any{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
ShouldEqualJSON,
},
// {
// `
//{
// `
//LET start = @start
//LET end = @end
//RETURN start..end
//`,
// []any{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
// ShouldEqualJSON,
// },
// []any{1, 2, 3, 4, 5, 6, 7, 8, 9, 10},
// ShouldEqualJSON,
//},
})
}
53 changes: 36 additions & 17 deletions pkg/compiler/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ type (

const (
jumpPlaceholder = -1
undefinedVariable = -1
ignorePseudoVariable = "_"
pseudoVariable = "CURRENT"
waitScope = "waitfor"
Expand Down Expand Up @@ -108,22 +109,23 @@ func (v *visitor) VisitHead(_ *fql.HeadContext) interface{} {
func (v *visitor) VisitForExpression(ctx *fql.ForExpressionContext) interface{} {
v.beginScope()
v.emit(runtime.OpArray)
resArrayIndex := len(v.bytecode) - 1

var loopStart, exitJump int
var loopJump, exitJump int
// identify whether it's WHILE or FOR loop
isForInLoop := ctx.While() == nil

if isForInLoop {
loopStart = len(v.bytecode)

// Loop data source to iterate over
if c := ctx.ForExpressionSource(); c != nil {
c.Accept(v)
}

v.emit(runtime.OpLoopInit)
loopJump = len(v.bytecode)
v.emit(runtime.OpLoopHasNext)
exitJump = v.emitJump(runtime.OpJumpIfFalse)
// pop the boolean value from the stack
v.emitPop()

valVar := ctx.GetValueVariable().GetText()
Expand All @@ -138,7 +140,22 @@ func (v *visitor) VisitForExpression(ctx *fql.ForExpressionContext) interface{}
hasCounterVar = true
}

var valVarIndex int

// declare value variable
if hasValVar {
valVarIndex = v.declareVariable(valVar)
}

var counterVarIndex int

if hasCounterVar {
// declare counter variable
counterVarIndex = v.declareVariable(counterVar)
}

if hasValVar && hasCounterVar {
// we will calculate the index of the counter variable
v.emit(runtime.OpLoopNext)
} else if hasValVar {
v.emit(runtime.OpLoopNextValue)
Expand All @@ -148,32 +165,29 @@ func (v *visitor) VisitForExpression(ctx *fql.ForExpressionContext) interface{}
panic(core.Error(ErrUnexpectedToken, ctx.GetText()))
}

// declare value variable
valVarIndex := v.declareVariable(valVar)

var counterVarIndex int

if hasCounterVar {
// declare counter variable
counterVarIndex = v.declareVariable(counterVar)
if hasValVar {
v.defineVariable(valVarIndex)
// remove the value from the stack
v.emitPop()
}

v.defineVariable(valVarIndex)

if hasCounterVar {
v.defineVariable(counterVarIndex)
// remove the counter from the stack
v.emitPop()
}
} else {
// Create initial value for the loop counter
v.emitConstant(runtime.OpPush, values.NewInt(0))

loopStart = len(v.bytecode)
loopJump = len(v.bytecode)

// Condition expression
ctx.Expression().Accept(v)

// Condition check
exitJump = v.emitJump(runtime.OpJumpIfFalse)
// pop the boolean value from the stack
v.emitPop()

counterVar := ctx.GetCounterVariable().GetText()
Expand Down Expand Up @@ -212,13 +226,18 @@ func (v *visitor) VisitForExpression(ctx *fql.ForExpressionContext) interface{}

// return
if c := ctx.ForExpressionReturn(); c != nil {
returnIdx := len(v.bytecode)
c.Accept(v)

// patch return in order to access the resulting array
v.arguments[returnIdx-1] = resArrayIndex
}

v.emitLoop(loopStart)
v.emitLoop(loopJump)
v.patchJump(exitJump)
// pop loop counter
v.emitPop()
v.emitPop()
v.endScope()

return nil
Expand Down Expand Up @@ -811,7 +830,7 @@ func (v *visitor) declareVariable(name string) int {
}
}

v.locals = append(v.locals, variable{name, v.scope})
v.locals = append(v.locals, variable{name, undefinedVariable})

return len(v.locals) - 1
}
Expand All @@ -835,7 +854,7 @@ func (v *visitor) emitConstant(op runtime.Opcode, constant core.Value) {
// emitLoop emits a loop instruction.
func (v *visitor) emitLoop(loopStart int) {
pos := v.emitJump(runtime.OpLoop)
jump := pos - loopStart + 2
jump := pos - loopStart
v.arguments[pos-1] = jump
}

Expand Down
1 change: 0 additions & 1 deletion pkg/runtime/globals.go

This file was deleted.

1 change: 0 additions & 1 deletion pkg/runtime/heap.go

This file was deleted.

6 changes: 1 addition & 5 deletions pkg/runtime/operators/range.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,5 @@ func Range(left, right core.Value) (core.Value, error) {
start := values.ToInt(left)
end := values.ToInt(right)

if start > end {
return values.None, nil
}

return values.NewRange(uint64(start), uint64(end)), nil
return values.NewRange(int64(start), int64(end)), nil
}
42 changes: 32 additions & 10 deletions pkg/runtime/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,57 @@ package runtime
import "github.com/MontFerret/ferret/pkg/runtime/core"

type Stack struct {
values []core.Value
operands []core.Value
variables []core.Value
}

func NewStack(cap int) *Stack {
return &Stack{make([]core.Value, 0, cap)}
func NewStack(operands, variables int) *Stack {
return &Stack{
make([]core.Value, 0, operands),
make([]core.Value, 0, variables),
}
}

func (s *Stack) Len() int {
return len(s.values)
return len(s.operands)
}

func (s *Stack) Peek() core.Value {
return s.values[len(s.values)-1]
return s.operands[len(s.operands)-1]
}

func (s *Stack) Push(value core.Value) {
s.values = append(s.values, value)
s.operands = append(s.operands, value)
}

func (s *Stack) Pop() core.Value {
value := s.values[len(s.values)-1]
s.values = s.values[:len(s.values)-1]
value := s.operands[len(s.operands)-1]
s.operands = s.operands[:len(s.operands)-1]
return value
}

func (s *Stack) Get(index int) core.Value {
return s.values[index]
return s.operands[index]
}

func (s *Stack) Set(index int, value core.Value) {
s.values[index] = value
s.operands[index] = value
}

func (s *Stack) GetVariable(index int) core.Value {
return s.variables[index]
}

func (s *Stack) SetVariable(index int, value core.Value) {
// TODO: Calculate in advance the number of variables
if index >= len(s.variables) {
s.variables = append(s.variables, value)
return
}

s.variables[index] = value
}

func (s *Stack) PushVariable(value core.Value) {
s.variables = append(s.variables, value)
}
Loading

0 comments on commit 2b3fd4f

Please sign in to comment.