232 lines
4.8 KiB
Go
232 lines
4.8 KiB
Go
package compiler
|
|
|
|
import "testing"
|
|
|
|
func TestLabelStack_PushCreatesUniqueLabels(t *testing.T) {
|
|
stack := NewLabelStack("test")
|
|
|
|
lbl1 := stack.Push()
|
|
lbl2 := stack.Push()
|
|
lbl3 := stack.Push()
|
|
|
|
if lbl1 != "test1" {
|
|
t.Errorf("expected test1, got %s", lbl1)
|
|
}
|
|
if lbl2 != "test2" {
|
|
t.Errorf("expected test2, got %s", lbl2)
|
|
}
|
|
if lbl3 != "test3" {
|
|
t.Errorf("expected test3, got %s", lbl3)
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_PeekDoesNotRemove(t *testing.T) {
|
|
stack := NewLabelStack("peek")
|
|
|
|
stack.Push()
|
|
lbl := stack.Push()
|
|
|
|
peeked, err := stack.Peek()
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if peeked != lbl {
|
|
t.Errorf("expected %s, got %s", lbl, peeked)
|
|
}
|
|
|
|
if stack.Size() != 2 {
|
|
t.Errorf("expected size 2 after peek, got %d", stack.Size())
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_PopRemoves(t *testing.T) {
|
|
stack := NewLabelStack("pop")
|
|
|
|
stack.Push()
|
|
lbl := stack.Push()
|
|
|
|
popped, err := stack.Pop()
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if popped != lbl {
|
|
t.Errorf("expected %s, got %s", lbl, popped)
|
|
}
|
|
|
|
if stack.Size() != 1 {
|
|
t.Errorf("expected size 1 after pop, got %d", stack.Size())
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_PeekEmptyReturnsError(t *testing.T) {
|
|
stack := NewLabelStack("empty")
|
|
|
|
_, err := stack.Peek()
|
|
if err == nil {
|
|
t.Error("expected error on peek of empty stack")
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_PopEmptyReturnsError(t *testing.T) {
|
|
stack := NewLabelStack("empty")
|
|
|
|
_, err := stack.Pop()
|
|
if err == nil {
|
|
t.Error("expected error on pop of empty stack")
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_IsEmpty(t *testing.T) {
|
|
stack := NewLabelStack("check")
|
|
|
|
if !stack.IsEmpty() {
|
|
t.Error("new stack should be empty")
|
|
}
|
|
|
|
stack.Push()
|
|
if stack.IsEmpty() {
|
|
t.Error("stack with item should not be empty")
|
|
}
|
|
|
|
stack.Pop()
|
|
if !stack.IsEmpty() {
|
|
t.Error("stack after pop should be empty")
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_CounterNeverResets(t *testing.T) {
|
|
stack := NewLabelStack("counter")
|
|
|
|
lbl1 := stack.Push()
|
|
lbl2 := stack.Push()
|
|
stack.Pop()
|
|
stack.Pop()
|
|
lbl3 := stack.Push()
|
|
|
|
if lbl1 != "counter1" || lbl2 != "counter2" || lbl3 != "counter3" {
|
|
t.Errorf("counter reset detected: %s, %s, %s", lbl1, lbl2, lbl3)
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_WhileWendPattern(t *testing.T) {
|
|
whileStack := NewLabelStack("whilelbl")
|
|
wendStack := NewLabelStack("wendlbl")
|
|
|
|
// WHILE
|
|
whileLbl := whileStack.Push()
|
|
wendLbl := wendStack.Push()
|
|
|
|
if whileLbl != "whilelbl1" {
|
|
t.Errorf("expected whilelbl1, got %s", whileLbl)
|
|
}
|
|
if wendLbl != "wendlbl1" {
|
|
t.Errorf("expected wendlbl1, got %s", wendLbl)
|
|
}
|
|
|
|
// WEND
|
|
w, err := whileStack.Pop()
|
|
if err != nil || w != whileLbl {
|
|
t.Errorf("failed to pop while label")
|
|
}
|
|
|
|
wd, err := wendStack.Pop()
|
|
if err != nil || wd != wendLbl {
|
|
t.Errorf("failed to pop wend label")
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_IfElseEndifPattern(t *testing.T) {
|
|
ifStack := NewLabelStack("iflbl")
|
|
|
|
// IF
|
|
ifLbl1 := ifStack.Push()
|
|
|
|
// ELSE - peek the if label, then push new one
|
|
peeked, err := ifStack.Peek()
|
|
if err != nil || peeked != ifLbl1 {
|
|
t.Errorf("failed to peek if label")
|
|
}
|
|
|
|
// Commit (pop) the first label
|
|
popped, err := ifStack.Pop()
|
|
if err != nil || popped != ifLbl1 {
|
|
t.Errorf("failed to pop first if label")
|
|
}
|
|
|
|
// Push new label for ENDIF
|
|
ifLbl2 := ifStack.Push()
|
|
|
|
// ENDIF
|
|
endifLbl, err := ifStack.Pop()
|
|
if err != nil || endifLbl != ifLbl2 {
|
|
t.Errorf("failed to pop endif label")
|
|
}
|
|
|
|
if ifLbl1 != "iflbl1" || ifLbl2 != "iflbl2" {
|
|
t.Errorf("unexpected label names: %s, %s", ifLbl1, ifLbl2)
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_NestedIfPattern(t *testing.T) {
|
|
ifStack := NewLabelStack("iflbl")
|
|
|
|
// Outer IF
|
|
outerIf := ifStack.Push()
|
|
|
|
// Inner IF
|
|
innerIf := ifStack.Push()
|
|
|
|
// Inner ENDIF
|
|
innerEnd, _ := ifStack.Pop()
|
|
if innerEnd != innerIf {
|
|
t.Errorf("inner endif mismatch")
|
|
}
|
|
|
|
// Outer ENDIF
|
|
outerEnd, _ := ifStack.Pop()
|
|
if outerEnd != outerIf {
|
|
t.Errorf("outer endif mismatch")
|
|
}
|
|
|
|
if outerIf != "iflbl1" || innerIf != "iflbl2" {
|
|
t.Errorf("nested labels incorrect: %s, %s", outerIf, innerIf)
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_BreakPattern(t *testing.T) {
|
|
wendStack := NewLabelStack("wendlbl")
|
|
|
|
// WHILE
|
|
wendLbl := wendStack.Push()
|
|
|
|
// BREAK - needs to peek wend label without popping
|
|
breakTarget, err := wendStack.Peek()
|
|
if err != nil || breakTarget != wendLbl {
|
|
t.Errorf("failed to peek for break")
|
|
}
|
|
|
|
// Stack should still have the label
|
|
if wendStack.Size() != 1 {
|
|
t.Error("peek should not modify stack")
|
|
}
|
|
|
|
// WEND - now pop it
|
|
wend, _ := wendStack.Pop()
|
|
if wend != wendLbl {
|
|
t.Errorf("wend label mismatch")
|
|
}
|
|
}
|
|
|
|
func TestLabelStack_MultipleSeparateStacks(t *testing.T) {
|
|
whileStack := NewLabelStack("whilelbl")
|
|
ifStack := NewLabelStack("iflbl")
|
|
generalStack := NewLabelStack("general")
|
|
|
|
w := whileStack.Push()
|
|
i := ifStack.Push()
|
|
g := generalStack.Push()
|
|
|
|
if w != "whilelbl1" || i != "iflbl1" || g != "general1" {
|
|
t.Errorf("separate stacks interfering: %s, %s, %s", w, i, g)
|
|
}
|
|
}
|