Skip to content

Commit

Permalink
fix rept 0 count support
Browse files Browse the repository at this point in the history
  • Loading branch information
cornelk committed Nov 11, 2024
1 parent 516d45a commit d3c0012
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 23 deletions.
98 changes: 98 additions & 0 deletions assembler/assembler_asm6_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,48 @@ IF i==0
ENDIF
`

var asm6ElseOutsideOfContext = `
.segment "HEADER"
ELSE
`

var asm6MultipleElse = `
.segment "HEADER"
i = 1
IF i > 0
ELSE
ELSE
`

var asm6EndifOutsideOfContext = `
.segment "HEADER"
ENDIF
`

var asm6MissingEndif = `
.segment "HEADER"
i = 1
IF i > 0
`

var asm6ElseifOutsideOfContext = `
.segment "HEADER"
ELSEIF 1 > 0
`

var asm6ElseifReferenceProgramCounter = `
.segment "HEADER"
IF 1 > 0
ELSEIF $ > 0
ENDIF
`

var asm6IfReferenceProgramCounter = `
.segment "HEADER"
IF $ > 0
ENDIF
`

func TestAssemblerAsm6IfElseElseIfEndif(t *testing.T) {
b, err := runAsm6Test(t, unitTestConfig, asm6IfEndifTestCode)
assert.NoError(t, err)
Expand All @@ -274,6 +316,27 @@ func TestAssemblerAsm6IfElseElseIfEndif(t *testing.T) {
0x3, // 1 item
}
assert.Equal(t, expected, b)

_, err = runAsm6Test(t, unitTestConfig, asm6ElseOutsideOfContext)
assert.ErrorIs(t, err, errConditionOutsideIfContext)

_, err = runAsm6Test(t, unitTestConfig, asm6MultipleElse)
assert.ErrorIs(t, err, errMultipleElseFound)

_, err = runAsm6Test(t, unitTestConfig, asm6EndifOutsideOfContext)
assert.ErrorIs(t, err, errConditionOutsideIfContext)

_, err = runAsm6Test(t, unitTestConfig, asm6MissingEndif)
assert.ErrorIs(t, err, errMissingEndif)

_, err = runAsm6Test(t, unitTestConfig, asm6ElseifOutsideOfContext)
assert.ErrorIs(t, err, errConditionOutsideIfContext)

_, err = runAsm6Test(t, unitTestConfig, asm6ElseifReferenceProgramCounter)
assert.ErrorIs(t, err, errExpressionCantReferenceProgramCounter)

_, err = runAsm6Test(t, unitTestConfig, asm6IfReferenceProgramCounter)
assert.ErrorIs(t, err, errExpressionCantReferenceProgramCounter)
}

var asm6IfIfdefTestCode = `
Expand All @@ -292,6 +355,9 @@ ELSE
DB 4
ENDIF
IFDEF k
DB 6
ENDIF
`

func TestAssemblerAsm6IfdefIfndef(t *testing.T) {
Expand Down Expand Up @@ -377,6 +443,27 @@ ENDR
DB 0xff
`

var asm6ReptReferenceProgramCounter = `
.segment "HEADER"
REPT $
ENDR
`

var asm6Rept0 = `
.segment "HEADER"
REPT 0
DB 1
ENDR
`

var asm6Rept0Eval = `
.segment "HEADER"
i = 0
REPT i
DB 1
ENDR
`

func TestAssemblerAsm6Rept(t *testing.T) {
b, err := runAsm6Test(t, unitTestConfig, asm6ReptCode)
assert.NoError(t, err)
Expand All @@ -387,6 +474,17 @@ func TestAssemblerAsm6Rept(t *testing.T) {
0xff, // 1 item
}
assert.Equal(t, expected, b)

b, err = runAsm6Test(t, unitTestConfig, asm6Rept0)
assert.NoError(t, err)
assert.True(t, len(b) == 0, "expected no output")

b, err = runAsm6Test(t, unitTestConfig, asm6Rept0Eval)
assert.NoError(t, err)
assert.True(t, len(b) == 0, "expected no output")

_, err = runAsm6Test(t, unitTestConfig, asm6ReptReferenceProgramCounter)
assert.ErrorIs(t, err, errExpressionCantReferenceProgramCounter)
}

func runAsm6Test(t *testing.T, testConfig, testCode string) ([]byte, error) {
Expand Down
4 changes: 1 addition & 3 deletions assembler/context.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package assembler

import "errors"

type context struct {
processNodes bool
hasElse bool // to detect invalid multiple else usages
Expand All @@ -15,7 +13,7 @@ func processElseCondition(expEval *expressionEvaluation) error {
return errConditionOutsideIfContext
}
if expEval.currentContext.hasElse {
return errors.New("multiple else found")
return errMultipleElseFound
}

expEval.currentContext.hasElse = true
Expand Down
51 changes: 34 additions & 17 deletions assembler/expression_evaluation_step.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import (

var (
errExpressionCantReferenceProgramCounter = errors.New("expression can not reference program counter")
errConditionOutsideIfContext = errors.New("directive used outside if context")
errConditionOutsideIfContext = errors.New("directive used outside of if context")
errMissingEndif = errors.New("missing endif")
errMultipleElseFound = errors.New("multiple else found")
errReptCountNegative = errors.New("rept count can not be negative")
)

type expressionEvaluation struct {
Expand Down Expand Up @@ -55,7 +58,7 @@ func evaluateExpressionsStep(asm *Assembler) error {
}

if expEval.currentContext.parent != nil {
return errors.New("missing endif")
return errMissingEndif
}
return nil
}
Expand Down Expand Up @@ -304,8 +307,8 @@ func parseRept(expEval *expressionEvaluation, rept ast.Rept, seg *segment, curre
if err != nil {
return fmt.Errorf("getting rept count: %w", err)
}
if count <= 0 {
return errors.New("rept count must be positive")
if count < 0 {
return errReptCountNegative
}

var nodes []ast.Node
Expand All @@ -325,22 +328,36 @@ func parseRept(expEval *expressionEvaluation, rept ast.Rept, seg *segment, curre
return errors.New("rept without endr found")
}

// insert the nodes count-1 times, as the first insertion are the existing nodes
count--
unrollReptNodes(nodes, seg, currentNodeIndex, count)

return nil
}

func unrollReptNodes(nodes []ast.Node, seg *segment, currentNodeIndex int, count int64) {
nodesToInsert := make([]ast.Node, 0, len(nodes)*int(count))
for range count {
for _, node := range nodes {
nodesToInsert = append(nodesToInsert, node.Copy())

if count > 0 {
// insert the nodes count-1 times, as the first insertion are the existing nodes
count--
for range count {
for _, node := range nodes {
nodesToInsert = append(nodesToInsert, node.Copy())
}
}
}

// copy nodes up to endr
nodes = seg.nodes[:currentNodeIndex+len(nodesToInsert)-1]
// append now node copies
nodes = append(nodes, nodesToInsert...)
// append nodes after endr
nodes = append(nodes, seg.nodes[currentNodeIndex+len(nodesToInsert):]...)
// copy nodes up to endr
nodes = seg.nodes[:currentNodeIndex+len(nodesToInsert)-1]
// append now node copies
nodes = append(nodes, nodesToInsert...)
// append nodes after endr
nodes = append(nodes, seg.nodes[currentNodeIndex+len(nodesToInsert):]...)
} else {
reptNodeCount := len(nodes)
// copy nodes up to rept
nodes = seg.nodes[:currentNodeIndex+1]
// append nodes after endr
nodes = append(nodes, seg.nodes[currentNodeIndex+reptNodeCount+2:]...)
}

seg.nodes = nodes
return nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ module github.com/retroenv/retroasm

go 1.22

require github.com/retroenv/retrogolib v0.0.0-20240320144300-4dc6a43b5983
require github.com/retroenv/retrogolib v0.0.0-20241111003331-fc91264b5684
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
github.com/retroenv/retrogolib v0.0.0-20240320144300-4dc6a43b5983 h1:jqCLtAkseEa0cgNOvlyNjYxA0rnJzR3KG/zHeBd7Fwo=
github.com/retroenv/retrogolib v0.0.0-20240320144300-4dc6a43b5983/go.mod h1:HZ3Y8NA+pJQrTLDJ6VSg/X6Oo4jWxz2S9ZMSvv8Zm1o=
github.com/retroenv/retrogolib v0.0.0-20241111003331-fc91264b5684 h1:4dQQv1dgk2t1pGFpcczmKRsHuAvMxZN/fUPMwESwmjg=
github.com/retroenv/retrogolib v0.0.0-20241111003331-fc91264b5684/go.mod h1:8pe9mEjbKL9Z5L4FFzYGSk1Ovhrq1LR6ucwRFj5CIXs=

0 comments on commit d3c0012

Please sign in to comment.