Closed mratsim closed 6 years ago
There are two possible solutions:
set[uint16]
of the enum coverage and then use it to generate the jump tablesWhat's the best one for y'all?
Raise an error if the enum has holes
IMHO that's the way to go. If you want speed, design your enums properly.
I think it should raise an error as well, this is not supported on the C side.
Regarding enum design, the opcode <-> hex/enum value table is most likely not in the hand of people writing the implementation, and most designs I've seen have holes.
Fortunately it is not hard to come up with a macro to fill holes, this is the one I am using.
import macros, strformat, strutils
macro fill_enum_holes*(body: untyped): untyped =
## Fill the holes of an enum
## For example
## type Foo {.pure.} = enum
## A = 0x00,
## B = 0x10
# Sanity checks
#
# StmtList
# TypeSection
# TypeDef
# PragmaExpr
# Postfix
# Ident "*"
# Ident "Op"
# Pragma
# Ident "pure"
# Empty
# EnumTy
# Empty
# EnumFieldDef
# Ident "A"
# IntLit 0
# EnumFieldDef
# Ident "B"
# IntLit 16
body[0].expectKind(nnkTypeSection)
body[0][0][2].expectKind(nnkEnumTy)
let opcodes = body[0][0][2]
# We will iterate over all the opcodes
# check if the i-th value is declared, if not add a no-op
# and accumulate that in a "dense opcodes" declaration
var
opcode = 0
holes_idx = 1
dense_opcs = nnkEnumTy.newTree()
dense_opcs.add newEmptyNode()
# Iterate on the enum with holes
while holes_idx < opcodes.len:
let curr_ident = opcodes[holes_idx]
if curr_ident.kind in {nnkIdent, nnkEmpty} or
(curr_ident.kind == nnkEnumFieldDef and
curr_ident[1].intVal == opcode):
dense_opcs.add curr_ident
inc holes_idx
else:
dense_opcs.add newIdentNode(&"Nop0x{opcode.toHex(2)}")
inc opcode
result = body
result[0][0][2] = dense_opcs
It can be added to sugar.nim.
Regarding enum design, the opcode <-> hex/enum value table is most likely not in the hand of people writing the implementation, and most designs I've seen have holes.
Come on, when you read the bytecode from disk or whatever, you convert it to the different enum representation. This lookup table can also be generated by a macro if the mapping is obvious enough.
Taking the test here: https://github.com/nim-lang/Nim/blob/ddc131cf07972decc206e033b2dd85a42eb1c98d/tests/casestmt/tcomputedgoto.nim and changing the enum to enum with holes breaks codegen: